def CheckTCPConnection(self, mode, listensocket, netid, version, myaddr, remoteaddr, packet, reply, msg): establishing_ack = packets.ACK(version, remoteaddr, myaddr, reply)[1] # Attempt to confuse the kernel. self.InvalidateDstCache(version, remoteaddr, netid) self.ReceivePacketOn(netid, establishing_ack) # If we're using UID routing, the accept() call has to be run as a UID that # is routed to the specified netid, because the UID of the socket returned # by accept() is the effective UID of the process that calls it. It doesn't # need to be the same UID; any UID that selects the same interface will do. with net_test.RunAsUid(self.UidForNetid(netid)): s, _ = listensocket.accept() try: # Check that data sent on the connection goes out on the right interface. desc, data = packets.ACK(version, myaddr, remoteaddr, establishing_ack, payload=UDP_PAYLOAD) s.send(UDP_PAYLOAD) self.ExpectPacketOn(netid, msg + ": expecting %s" % desc, data) self.InvalidateDstCache(version, remoteaddr, netid) # Keep up our end of the conversation. ack = packets.ACK(version, remoteaddr, myaddr, data)[1] self.InvalidateDstCache(version, remoteaddr, netid) self.ReceivePacketOn(netid, ack) mark = self.GetSocketMark(s) finally: self.InvalidateDstCache(version, remoteaddr, netid) s.close() self.InvalidateDstCache(version, remoteaddr, netid) if mode == self.MODE_INCOMING_MARK: self.assertEquals(netid, mark, msg + ": Accepted socket: Expected mark %d, got %d" % ( netid, mark)) elif mode != self.MODE_EXPLICIT_MARK: self.assertEquals(0, self.GetSocketMark(listensocket)) # Check the FIN was sent on the right interface, and ack it. We don't expect # this to fail because by the time the connection is established things are # likely working, but a) extra tests are always good and b) extra packets # like the FIN (and retransmitted FINs) could cause later tests that expect # no packets to fail. desc, fin = packets.FIN(version, myaddr, remoteaddr, ack) self.ExpectPacketOn(netid, msg + ": expecting %s after close" % desc, fin) desc, finack = packets.FIN(version, remoteaddr, myaddr, fin) self.ReceivePacketOn(netid, finack) # Since we called close() earlier, the userspace socket object is gone, so # the socket has no UID. If we're doing UID routing, the ack might be routed # incorrectly. Not much we can do here. desc, finackack = packets.ACK(version, myaddr, remoteaddr, finack) self.ExpectPacketOn(netid, msg + ": expecting final ack", finackack)
def IncomingConnection(self, version, end_state, netid): self.s = self.OpenListenSocket(version, netid) self.end_state = end_state remoteaddr = self.remoteaddr = self.GetRemoteAddress(version) remotesockaddr = self.remotesockaddr = self.GetRemoteSocketAddress( version) myaddr = self.myaddr = self.MyAddress(version, netid) mysockaddr = self.mysockaddr = self.MySocketAddress(version, netid) if version == 5: version = 4 self.version = version if end_state == TCP_LISTEN: return desc, syn = packets.SYN(self.port, version, remoteaddr, myaddr) synack_desc, synack = packets.SYNACK(version, myaddr, remoteaddr, syn) msg = "Received %s, expected to see reply %s" % (desc, synack_desc) reply = self._ReceiveAndExpectResponse(netid, syn, synack, msg) if end_state == TCP_SYN_RECV: return establishing_ack = packets.ACK(version, remoteaddr, myaddr, reply)[1] self.ReceivePacketOn(netid, establishing_ack) if end_state == TCP_NOT_YET_ACCEPTED: return self.accepted, _ = self.s.accept() net_test.DisableFinWait(self.accepted) if end_state == TCP_ESTABLISHED: return desc, data = packets.ACK(version, myaddr, remoteaddr, establishing_ack, payload=net_test.UDP_PAYLOAD) self.accepted.send(net_test.UDP_PAYLOAD) self.ExpectPacketOn(netid, msg + ": expecting %s" % desc, data) desc, fin = packets.FIN(version, remoteaddr, myaddr, data) fin = packets._GetIpLayer(version)(str(fin)) ack_desc, ack = packets.ACK(version, myaddr, remoteaddr, fin) msg = "Received %s, expected to see reply %s" % (desc, ack_desc) # TODO: Why can't we use this? # self._ReceiveAndExpectResponse(netid, fin, ack, msg) self.ReceivePacketOn(netid, fin) time.sleep(0.1) self.ExpectPacketOn(netid, msg + ": expecting %s" % ack_desc, ack) if end_state == TCP_CLOSE_WAIT: return raise ValueError("Invalid TCP state %d specified" % end_state)
def ReceiveRstPacketOn(self, netid): # self.last_packet is the last packet we received. Invert direction twice. _, ack = packets.ACK(self.version, self.myaddr, self.remoteaddr, self.last_packet) desc, rst = packets.RST(self.version, self.remoteaddr, self.myaddr, ack) super(TcpBaseTest, self).ReceivePacketOn(netid, rst)
def CheckForwardingCrash(self, netid, iface1, iface2): listenport = packets.RandomPort() listensocket = net_test.IPv6TCPSocket() listensocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) listensocket.bind(("::", listenport)) listensocket.listen(100) self.SetSocketMark(listensocket, netid) version = 6 remoteaddr = self.GetRemoteAddress(version) myaddr = self.MyAddress(version, netid) desc, syn = packets.SYN(listenport, version, remoteaddr, myaddr) synack_desc, synack = packets.SYNACK(version, myaddr, remoteaddr, syn) msg = "Sent %s, expected %s" % (desc, synack_desc) reply = self._ReceiveAndExpectResponse(netid, syn, synack, msg) establishing_ack = packets.ACK(version, remoteaddr, myaddr, reply)[1] self.ReceivePacketOn(netid, establishing_ack) accepted, peer = listensocket.accept() remoteport = accepted.getpeername()[1] accepted.close() desc, fin = packets.FIN(version, myaddr, remoteaddr, establishing_ack) self.ExpectPacketOn(netid, msg + ": expecting %s after close" % desc, fin) desc, finack = packets.FIN(version, remoteaddr, myaddr, fin) self.ReceivePacketOn(netid, finack) # Check our socket is now in TIME_WAIT. sockets = self.ReadProcNetSocket("tcp6") mysrc = "%s:%04X" % (net_test.FormatSockStatAddress(myaddr), listenport) mydst = "%s:%04X" % (net_test.FormatSockStatAddress(remoteaddr), remoteport) state = None sockets = [s for s in sockets if s[0] == mysrc and s[1] == mydst] self.assertEquals(1, len(sockets)) self.assertEquals("%02X" % self.TCP_TIME_WAIT, sockets[0][2]) # Remove our IP address. try: self.iproute.DelAddress(myaddr, 64, self.ifindices[netid]) self.ReceivePacketOn(iface1, finack) self.ReceivePacketOn(iface1, establishing_ack) self.ReceivePacketOn(iface1, establishing_ack) # No crashes? Good. finally: # Put back our IP address. self.SendRA(netid) listensocket.close()
def testFinWait1Socket(self): for version in [4, 5, 6]: self.IncomingConnection(version, tcp_test.TCP_ESTABLISHED, self.netid) # Get the cookie so we can find this socket after we close it. diag_msg = self.sock_diag.FindSockDiagFromFd(self.accepted) diag_req = self.sock_diag.DiagReqFromDiagMsg(diag_msg, IPPROTO_TCP) # Close the socket and check that it goes into FIN_WAIT1 and sends a FIN. net_test.EnableFinWait(self.accepted) self.accepted.close() diag_req.states = 1 << tcp_test.TCP_FIN_WAIT1 diag_msg, attrs = self.sock_diag.GetSockInfo(diag_req) self.assertEquals(tcp_test.TCP_FIN_WAIT1, diag_msg.state) desc, fin = self.FinPacket() self.ExpectPacketOn(self.netid, "Closing FIN_WAIT1 socket", fin) # Destroy the socket and expect no RST. self.CheckRstOnClose(None, diag_req, False, "Closing FIN_WAIT1 socket") diag_msg, attrs = self.sock_diag.GetSockInfo(diag_req) # The socket is still there in FIN_WAIT1: SOCK_DESTROY did nothing # because userspace had already closed it. self.assertEquals(tcp_test.TCP_FIN_WAIT1, diag_msg.state) # ACK the FIN so we don't trip over retransmits in future tests. finversion = 4 if version == 5 else version desc, finack = packets.ACK(finversion, self.remoteaddr, self.myaddr, fin) diag_msg, attrs = self.sock_diag.GetSockInfo(diag_req) self.ReceivePacketOn(self.netid, finack) # See if we can find the resulting FIN_WAIT2 socket. This does not appear # to work on 3.10. if net_test.LINUX_VERSION >= (3, 18): diag_req.states = 1 << tcp_test.TCP_FIN_WAIT2 infos = self.sock_diag.Dump(diag_req, "") self.assertTrue( any(diag_msg.state == tcp_test.TCP_FIN_WAIT2 for diag_msg, attrs in infos), "Expected to find FIN_WAIT2 socket in %s" % infos)
def SendRSTOnClosedSocket(self, version, netid, expect_rst): self.IncomingConnection(version, tcp_test.TCP_ESTABLISHED, netid) self.accepted.setsockopt(net_test.SOL_TCP, net_test.TCP_LINGER2, -1) net_test.EnableFinWait(self.accepted) self.accepted.shutdown(SHUT_WR) desc, fin = self.FinPacket() self.ExpectPacketOn(netid, "Closing FIN_WAIT1 socket", fin) finversion = 4 if version == 5 else version desc, finack = packets.ACK(finversion, self.remoteaddr, self.myaddr, fin) self.ReceivePacketOn(netid, finack) try: self.ExpectPacketOn(netid, "Closing FIN_WAIT1 socket", fin) except AssertionError: pass self.accepted.close() desc, rst = packets.RST(version, self.myaddr, self.remoteaddr, self.last_packet) if expect_rst: msg = "closing socket with linger2, expecting %s: " % desc self.ExpectPacketOn(netid, msg, rst) else: msg = "closing socket with linger2, expecting no packets" self.ExpectNoPacketsOn(netid, msg)
def CheckConnectOption(self, version): ip_layer = {4: scapy.IP, 6: scapy.IPv6}[version] netid = self.RandomNetid() s = self.TFOClientSocket(version, netid) self.clearTcpMetrics(version, netid) # Connect the first time. remoteaddr = self.GetRemoteAddress(version) with self.assertRaisesErrno(EINPROGRESS): s.connect((remoteaddr, 53)) self.assertSocketNotConnected(s) # Expect a SYN handshake with an empty TFO option. myaddr = self.MyAddress(version, netid) port = s.getsockname()[1] self.assertNotEqual(0, port) desc, syn = packets.SYN(53, version, myaddr, remoteaddr, port, seq=None) syn.getlayer("TCP").options = [(TCPOPT_FASTOPEN, "")] msg = "Fastopen connect: expected %s" % desc syn = self.ExpectPacketOn(netid, msg, syn) syn = ip_layer(str(syn)) # Receive a SYN+ACK with a TFO cookie and expect the connection to proceed # as normal. desc, synack = packets.SYNACK(version, remoteaddr, myaddr, syn) synack.getlayer("TCP").options = [(TCPOPT_FASTOPEN, "helloT"), ("NOP", None), ("NOP", None)] self.ReceivePacketOn(netid, synack) synack = ip_layer(str(synack)) desc, ack = packets.ACK(version, myaddr, remoteaddr, synack) msg = "First connect: got SYN+ACK, expected %s" % desc self.ExpectPacketOn(netid, msg, ack) self.assertSocketConnected(s) s.close() desc, rst = packets.RST(version, myaddr, remoteaddr, synack) msg = "Closing client socket, expecting %s" % desc self.ExpectPacketOn(netid, msg, rst) # Connect to the same destination again. Expect the connect to succeed # without sending a SYN packet. s = self.TFOClientSocket(version, netid) s.connect((remoteaddr, 53)) self.assertSocketNotConnected(s) self.ExpectNoPacketsOn(netid, "Second TFO connect, expected no packets") # Issue a write and expect a SYN with data. port = s.getsockname()[1] s.send(net_test.UDP_PAYLOAD) desc, syn = packets.SYN(53, version, myaddr, remoteaddr, port, seq=None) t = syn.getlayer(scapy.TCP) t.options = [(TCPOPT_FASTOPEN, "helloT"), ("NOP", None), ("NOP", None)] t.payload = scapy.Raw(net_test.UDP_PAYLOAD) msg = "TFO write, expected %s" % desc self.ExpectPacketOn(netid, msg, syn)