def testProcNetIcmp6(self): numrows6 = len(self.ReadProcNetSocket("icmp6")) s = net_test.IPv6PingSocket() s.bind(("::1", 0xace)) s.connect(("::1", 0xbeef)) self.CheckSockStatFile("icmp6", "::1", 0xace, "::1", 0xbeef, 1) # Check the row goes away when the socket is closed. s.close() self.assertEquals(numrows6, len(self.ReadProcNetSocket("icmp6"))) # Try send, bind and connect to check the addresses and the state. s = net_test.IPv6PingSocket() self.assertEqual(0, len(self.ReadProcNetSocket("icmp6"))) s.sendto(net_test.IPV6_PING, (net_test.IPV6_ADDR, 12345)) self.assertEqual(1, len(self.ReadProcNetSocket("icmp6"))) # Can't bind after sendto, apparently. s = net_test.IPv6PingSocket() self.assertEqual(0, len(self.ReadProcNetSocket("icmp6"))) s.bind((self.lladdr, 0xd00d, 0, self.ifindex)) self.CheckSockStatFile("icmp6", self.lladdr, 0xd00d, "::", 0, 7) # Check receive bytes. s.setsockopt(net_test.SOL_IPV6, net_test.IPV6_MULTICAST_IF, self.ifindex) s.connect(("ff02::1", 0xdead)) self.CheckSockStatFile("icmp6", self.lladdr, 0xd00d, "ff02::1", 0xdead, 1) s.send(net_test.IPV6_PING) time.sleep(0.01) # Give the other thread time to reply. self.CheckSockStatFile("icmp6", self.lladdr, 0xd00d, "ff02::1", 0xdead, 1, txmem=0, rxmem=0x300) self.assertValidPingResponse(s, net_test.IPV6_PING) self.CheckSockStatFile("icmp6", self.lladdr, 0xd00d, "ff02::1", 0xdead, 1, txmem=0, rxmem=0)
def testBindAffectsIdentifier(self): s = net_test.IPv6PingSocket() s.bind((self.globaladdr, 0xf976)) s.sendto(net_test.IPV6_PING, (net_test.IPV6_ADDR, 55)) self.assertEquals("\xf9\x76", s.recv(32768)[4:6]) s = net_test.IPv6PingSocket() s.bind((self.globaladdr, 0xace)) s.sendto(net_test.IPV6_PING, (net_test.IPV6_ADDR, 55)) self.assertEquals("\x0a\xce", s.recv(32768)[4:6])
def testCrossProtocolCalls(self): """Tests that passing in the wrong family returns EAFNOSUPPORT.""" def CheckEAFNoSupport(function, *args): self.assertRaisesErrno(errno.EAFNOSUPPORT, function, *args) ipv6sockaddr = csocket.Sockaddr((net_test.IPV6_ADDR, 53)) # In order to check that IPv6 socket calls return EAFNOSUPPORT when passed # IPv4 socket address structures, we need to pass down a socket address # length argument that's at least sizeof(sockaddr_in6). Otherwise, the calls # will fail immediately with EINVAL because the passed-in socket length is # too short. So create a sockaddr_in that's as long as a sockaddr_in6. ipv4sockaddr = csocket.Sockaddr((net_test.IPV4_ADDR, 53)) ipv4sockaddr = csocket.SockaddrIn6( ipv4sockaddr.Pack() + "\x00" * (len(csocket.SockaddrIn6) - len(csocket.SockaddrIn))) s4 = net_test.IPv4PingSocket() s6 = net_test.IPv6PingSocket() # We can't just call s.connect(), s.bind() etc. with a tuple of the wrong # address family, because the Python implementation will just pass garbage # down to the kernel. So call the C functions directly. CheckEAFNoSupport(csocket.Bind, s4, ipv6sockaddr) CheckEAFNoSupport(csocket.Bind, s6, ipv4sockaddr) CheckEAFNoSupport(csocket.Connect, s4, ipv6sockaddr) CheckEAFNoSupport(csocket.Connect, s6, ipv4sockaddr) CheckEAFNoSupport(csocket.Sendmsg, s4, ipv6sockaddr, net_test.IPV4_PING, None, 0) CheckEAFNoSupport(csocket.Sendmsg, s6, ipv4sockaddr, net_test.IPV6_PING, None, 0)
def testFlowLabel(self): s = net_test.IPv6PingSocket() # Specifying a flowlabel without having set IPV6_FLOWINFO_SEND succeeds but # the flow label in the packet is not set. s.sendto(net_test.IPV6_PING, (net_test.IPV6_ADDR, 93, 0xdead, 0)) self.assertValidPingResponse(s, net_test.IPV6_PING) # Checks flow label==0. # If IPV6_FLOWINFO_SEND is set on the socket, attempting to set a flow label # that is not registered with the flow manager should return EINVAL... s.setsockopt(net_test.SOL_IPV6, net_test.IPV6_FLOWINFO_SEND, 1) # ... but this doesn't work yet. if False: self.assertRaisesErrno(errno.EINVAL, s.sendto, net_test.IPV6_PING, (net_test.IPV6_ADDR, 93, 0xdead, 0)) # After registering the flow label, it gets sent properly, appears in the # output packet, and is returned in the response. net_test.SetFlowLabel(s, net_test.IPV6_ADDR, 0xdead) self.assertEqual(1, s.getsockopt(net_test.SOL_IPV6, net_test.IPV6_FLOWINFO_SEND)) s.sendto(net_test.IPV6_PING, (net_test.IPV6_ADDR, 93, 0xdead, 0)) _, src = s.recvfrom(32768) _, _, flowlabel, _ = src self.assertEqual(0xdead, flowlabel & 0xfffff)
def testLinkLocalAddress(self): s = net_test.IPv6PingSocket() # Sending to a link-local address with no scope fails with EINVAL. self.assertRaisesErrno(errno.EINVAL, s.sendto, net_test.IPV6_PING, ("fe80::1", 55)) # Sending to link-local address with a scope succeeds. Note that Python # doesn't understand the "fe80::1%lo" format, even though it returns it. s.sendto(net_test.IPV6_PING, ("fe80::1", 55, 0, self.ifindex))
def testIPv6NoCrash(self): # Python 2.x does not provide either read() or recvmsg. s = net_test.IPv6PingSocket() written = s.sendto(net_test.IPV6_PING, ("::1", 55)) self.assertEquals(len(net_test.IPV6_PING), written) fd = s.fileno() reply = posix.read(fd, 4096) self.assertEquals(written, len(reply))
def testMappedAddressFails(self): s = net_test.IPv6PingSocket() s.sendto(net_test.IPV6_PING, (net_test.IPV6_ADDR, 55)) self.assertValidPingResponse(s, net_test.IPV6_PING) s.sendto(net_test.IPV6_PING, ("2001:4860:4860::8844", 55)) self.assertValidPingResponse(s, net_test.IPV6_PING) self.assertRaisesErrno(errno.EINVAL, s.sendto, net_test.IPV6_PING, ("::ffff:192.0.2.1", 55))
def testIPv6Error(self): s = net_test.IPv6PingSocket() s.setsockopt(net_test.SOL_IPV6, IPV6_UNICAST_HOPS, 2) s.setsockopt(net_test.SOL_IPV6, net_test.IPV6_RECVERR, 1) s.sendto(net_test.IPV6_PING, (net_test.IPV6_ADDR, 55)) # We can't check the actual error because Python 2.7 doesn't implement # recvmsg, but we can at least check that the socket returns an error. self.assertRaisesErrno(errno.EHOSTUNREACH, s.recv, 32768) # No response.
def testIPv6MulticastPing(self): s = net_test.IPv6PingSocket() # Send a multicast ping and check we get at least one duplicate. # The setsockopt should not be necessary, but ping_v6_sendmsg has a bug. s.setsockopt(net_test.SOL_IPV6, net_test.IPV6_MULTICAST_IF, self.ifindex) s.sendto(net_test.IPV6_PING, ("ff02::1", 55, 0, self.ifindex)) self.assertValidPingResponse(s, net_test.IPV6_PING) self.assertValidPingResponse(s, net_test.IPV6_PING)
def testIcmp6SocketsNotInIcmp(self): numrows = len(self.ReadProcNetSocket("icmp")) numrows6 = len(self.ReadProcNetSocket("icmp6")) s = net_test.IPv6PingSocket() s.bind(("::1", 0xace)) s.connect(("::1", 0xbeef)) self.assertEquals(numrows, len(self.ReadProcNetSocket("icmp"))) self.assertEquals(numrows6 + 1, len(self.ReadProcNetSocket("icmp6")))
def testLinkLocalOif(self): """Checks that ping to link-local addresses works correctly. Relevant kernel commits: upstream net: 5e45789 net: ipv6: Fix ping to link-local addresses. """ for mode in ["oif", "ucast_oif", None]: s = net_test.IPv6PingSocket() for netid in self.NETIDS: s2 = net_test.IPv6PingSocket() dst = self._RouterAddress(netid, 6) self.assertTrue(dst.startswith("fe80:")) if mode: self.SelectInterface(s, netid, mode) self.SelectInterface(s2, netid, mode) scopeid = 0 else: scopeid = self.ifindices[netid] if mode == "oif": # If SO_BINDTODEVICE has been set, any attempt to send on another # interface returns EINVAL. othernetid = self.NETIDS[(self.NETIDS.index(netid) + 1) % len(self.NETIDS)] otherscopeid = self.ifindices[othernetid] self.assertRaisesErrno(errno.EINVAL, s.sendto, net_test.IPV6_PING, (dst, 55, 0, otherscopeid)) self.assertRaisesErrno(errno.EINVAL, s.connect, (dst, 55, 0, otherscopeid)) # Try using both sendto and connect/send. # If we get a reply, we sent the packet out on the right interface. s.sendto(net_test.IPV6_PING, (dst, 123, 0, scopeid)) self.assertValidPingResponse(s, net_test.IPV6_PING) # IPV6_UNICAST_IF doesn't work on connected sockets. if mode != "ucast_oif": s2.connect((dst, 123, 0, scopeid)) s2.send(net_test.IPV6_PING) self.assertValidPingResponse(s2, net_test.IPV6_PING)
def testIPv6ScopedBind(self): # Can't bind to a link-local address without a scope ID. s = net_test.IPv6PingSocket() self.assertRaisesErrno(errno.EINVAL, s.bind, (self.lladdr, 1026, 0, 0)) # Binding to a link-local address with a scope ID works, and the scope ID is # returned by a subsequent getsockname. Interestingly, Python's getsockname # returns "fe80:1%foo", even though it does not understand it. expected = self.lladdr + "%" + self.ifname s.bind((self.lladdr, 4646, 0, self.ifindex)) self.assertEquals((expected, 4646, 0, self.ifindex), s.getsockname()) # Of course, for the above to work the address actually has to be configured # on the machine. self.assertRaisesErrno(errno.EADDRNOTAVAIL, s.bind, ("fe80::f00", 1026, 0, 1)) # Scope IDs on non-link-local addresses are silently ignored. s = net_test.IPv6PingSocket() s.bind(("::1", 1234, 0, 1)) self.assertEquals(("::1", 1234, 0, 0), s.getsockname())
def testIPv6Bind(self): # Bind to unspecified address. s = net_test.IPv6PingSocket() s.bind(("::", 769)) self.assertEquals(("::", 769, 0, 0), s.getsockname()) # Bind to loopback. s = net_test.IPv6PingSocket() s.bind(("::1", 99)) self.assertEquals(("::1", 99, 0, 0), s.getsockname()) # Binding twice is not allowed. self.assertRaisesErrno(errno.EINVAL, s.bind, ("::1", 22)) # But binding two different sockets to the same ID is allowed. s2 = net_test.IPv6PingSocket() s2.bind(("::1", 99)) self.assertEquals(("::1", 99, 0, 0), s2.getsockname()) s3 = net_test.IPv6PingSocket() s3.bind(("::1", 99)) self.assertEquals(("::1", 99, 0, 0), s3.getsockname()) # Binding both IPv4 and IPv6 to the same socket works. s4 = net_test.IPv4PingSocket() s6 = net_test.IPv6PingSocket() s4.bind(("0.0.0.0", 444)) s6.bind(("::", 666, 0, 0)) # Can't bind after sendto. s = net_test.IPv6PingSocket() s.sendto(net_test.IPV6_PING, (net_test.IPV6_ADDR, 9132)) self.assertRaisesErrno(errno.EINVAL, s.bind, ("::", 5429))
def testIPv6MTU(self): """Tests IPV6_RECVERR and path MTU discovery on ping sockets. Relevant kernel commits: upstream net-next: dcb94b8 ipv6: fix endianness error in icmpv6_err """ s = net_test.IPv6PingSocket() s.setsockopt(net_test.SOL_IPV6, csocket.IPV6_DONTFRAG, 1) s.setsockopt(net_test.SOL_IPV6, csocket.IPV6_MTU_DISCOVER, 2) s.setsockopt(net_test.SOL_IPV6, net_test.IPV6_RECVERR, 1) s.connect((net_test.IPV6_ADDR, 55)) pkt = net_test.IPV6_PING + (PingReplyThread.LINK_MTU + 100) * "a" s.send(pkt) self.assertRaisesErrno(errno.EMSGSIZE, s.recv, 32768) data, addr, cmsg = csocket.Recvmsg(s, 4096, 1024, csocket.MSG_ERRQUEUE) # Compare the offending packet with the one we sent. To do this we need to # calculate the ident of the packet we sent and blank out the checksum of # the one we received. ident = struct.pack("!H", s.getsockname()[1]) pkt = pkt[:4] + ident + pkt[6:] data = data[:2] + "\x00\x00" + pkt[4:] self.assertEquals(pkt, data) # Check the address that the packet was sent to. # ... except in 4.1, where it just returns an AF_UNSPEC, like this: # recvmsg(9, {msg_name(0)={sa_family=AF_UNSPEC, # sa_data="\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}, # msg_iov(1)=[{"\x80\x00\x04\x6b\x00\xc4\x00\x03\x61\x61\x61\x61\x61\x61"..., 4096}], # msg_controllen=64, {cmsg_len=60, cmsg_level=SOL_IPV6, cmsg_type=, ...}, # msg_flags=MSG_ERRQUEUE}, MSG_ERRQUEUE) = 1232 if net_test.LINUX_VERSION != (4, 1, 0): self.assertEquals(csocket.Sockaddr(("2001:4860:4860::8888", 0)), addr) # Check the cmsg data, including the link MTU. mtu = PingReplyThread.LINK_MTU src = self.reply_threads[self.netid].INTERMEDIATE_IPV6 msglist = [(net_test.SOL_IPV6, net_test.IPV6_RECVERR, (csocket.SockExtendedErr( (errno.EMSGSIZE, csocket.SO_ORIGIN_ICMP6, ICMPV6_PKT_TOOBIG, 0, mtu, 0)), csocket.Sockaddr((src, 0))))] # IP[V6]_RECVERR in 3.10 appears to return incorrect data for the port. # The fix might have been in 676d236, but we don't have that in 3.10 and it # touches code all over the tree. Instead, just don't check the port. if net_test.LINUX_VERSION <= (3, 14, 0): msglist[0][2][1].port = cmsg[0][2][1].port self.assertEquals(msglist, cmsg)
def testIPv6InvalidBind(self): s = net_test.IPv6PingSocket() self.assertRaisesErrno(errno.EINVAL, s.bind, ("ff02::2", 1026)) # Binding to an address we don't have only works with IPV6_TRANSPARENT. self.assertRaisesErrno(errno.EADDRNOTAVAIL, s.bind, (net_test.IPV6_ADDR, 651)) try: s.setsockopt(net_test.SOL_IPV6, net_test.IPV6_TRANSPARENT, 1) s.bind((net_test.IPV6_ADDR, 651)) except IOError, e: if e.errno == errno.EACCES: pass # We're not root. let it go for now.
def testAfUnspecBind(self): # Binding to AF_UNSPEC is treated as IPv4 if the address is 0.0.0.0. s4 = net_test.IPv4PingSocket() sockaddr = csocket.Sockaddr(("0.0.0.0", 12996)) sockaddr.family = AF_UNSPEC csocket.Bind(s4, sockaddr) self.assertEquals(("0.0.0.0", 12996), s4.getsockname()) # But not if the address is anything else. sockaddr = csocket.Sockaddr(("127.0.0.1", 58234)) sockaddr.family = AF_UNSPEC self.assertRaisesErrno(errno.EAFNOSUPPORT, csocket.Bind, s4, sockaddr) # This doesn't work for IPv6. s6 = net_test.IPv6PingSocket() sockaddr = csocket.Sockaddr(("::1", 58997)) sockaddr.family = AF_UNSPEC self.assertRaisesErrno(errno.EAFNOSUPPORT, csocket.Bind, s6, sockaddr)
def testIPv6LargePacket(self): s = net_test.IPv6PingSocket() s.bind(("::", 0xace)) data = net_test.IPV6_PING + "\x01" + 19994 * "\x00" + "aaaaa" s.sendto(data, ("::1", 953))
def testIPv6SendWithNoConnection(self): s = net_test.IPv6PingSocket() self.assertRaisesErrno(errno.EDESTADDRREQ, s.send, net_test.IPV6_PING)
def testIPv6LoopbackPingWithConnect(self): s = net_test.IPv6PingSocket() s.connect(("::1", 55)) s.send(net_test.IPV6_PING) self.assertValidPingResponse(s, net_test.IPV6_PING)
def testIPv6PingUsingSendto(self): s = net_test.IPv6PingSocket() written = s.sendto(net_test.IPV6_PING, (net_test.IPV6_ADDR, 55)) self.assertEquals(len(net_test.IPV6_PING), written) self.assertValidPingResponse(s, net_test.IPV6_PING)