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)
Exemple #2
0
    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)
Exemple #3
0
 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)
Exemple #7
0
    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)