def testCrossProtocolCrash(self): # Checks that an ICMP error containing a ping packet that matches the ID # of a socket of the wrong protocol (which can happen when using 464xlat) # doesn't crash the kernel. # We can only test this using IPv6 unreachables and IPv4 ping sockets, # because IPv4 packets sent by scapy.send() on loopback are not received by # the kernel. So we don't actually use this function yet. def GetIPv4Unreachable(port): # pylint: disable=unused-variable return (scapy.IP(src="192.0.2.1", dst="127.0.0.1") / scapy.ICMP(type=3, code=0) / scapy.IP(src="127.0.0.1", dst="127.0.0.1") / scapy.ICMP(type=8, id=port, seq=1)) def GetIPv6Unreachable(port): return (scapy.IPv6(src="::1", dst="::1") / scapy.ICMPv6DestUnreach() / scapy.IPv6(src="::1", dst="::1") / scapy.ICMPv6EchoRequest(id=port, seq=1, data="foobarbaz")) # An unreachable matching the ID of a socket of the wrong protocol # shouldn't crash. s = net_test.IPv4PingSocket() s.connect(("127.0.0.1", 12345)) _, port = s.getsockname() scapy.send(GetIPv6Unreachable(port))
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 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 testIPv4Error(self): s = net_test.IPv4PingSocket() s.setsockopt(SOL_IP, IP_TTL, 2) s.setsockopt(SOL_IP, net_test.IP_RECVERR, 1) s.sendto(net_test.IPV4_PING, (net_test.IPV4_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 testIPv4NoCrash(self): # Python 2.x does not provide either read() or recvmsg. s = net_test.IPv4PingSocket() written = s.sendto(net_test.IPV4_PING, ("127.0.0.1", 55)) self.assertEquals(len(net_test.IPV4_PING), written) fd = s.fileno() reply = posix.read(fd, 4096) self.assertEquals(written, len(reply))
def testIPv4InvalidBind(self): s = net_test.IPv4PingSocket() self.assertRaisesErrno(errno.EADDRNOTAVAIL, s.bind, ("255.255.255.255", 1026)) self.assertRaisesErrno(errno.EADDRNOTAVAIL, s.bind, ("224.0.0.1", 651)) # Binding to an address we don't have only works with IP_TRANSPARENT. self.assertRaisesErrno(errno.EADDRNOTAVAIL, s.bind, (net_test.IPV4_ADDR, 651)) try: s.setsockopt(SOL_IP, net_test.IP_TRANSPARENT, 1) s.bind((net_test.IPV4_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 testIPv4Bind(self): # Bind to unspecified address. s = net_test.IPv4PingSocket() s.bind(("0.0.0.0", 544)) self.assertEquals(("0.0.0.0", 544), s.getsockname()) # Bind to loopback. s = net_test.IPv4PingSocket() s.bind(("127.0.0.1", 99)) self.assertEquals(("127.0.0.1", 99), s.getsockname()) # Binding twice is not allowed. self.assertRaisesErrno(errno.EINVAL, s.bind, ("127.0.0.1", 22)) # But binding two different sockets to the same ID is allowed. s2 = net_test.IPv4PingSocket() s2.bind(("127.0.0.1", 99)) self.assertEquals(("127.0.0.1", 99), s2.getsockname()) s3 = net_test.IPv4PingSocket() s3.bind(("127.0.0.1", 99)) self.assertEquals(("127.0.0.1", 99), s3.getsockname()) # If two sockets bind to the same port, the first one to call read() gets # the response. s4 = net_test.IPv4PingSocket() s5 = net_test.IPv4PingSocket() s4.bind(("0.0.0.0", 167)) s5.bind(("0.0.0.0", 167)) s4.sendto(net_test.IPV4_PING, (net_test.IPV4_ADDR, 44)) self.assertValidPingResponse(s5, net_test.IPV4_PING) net_test.SetSocketTimeout(s4, 100) self.assertRaisesErrno(errno.EAGAIN, s4.recv, 32768) # If SO_REUSEADDR is turned off, then we get EADDRINUSE. s6 = net_test.IPv4PingSocket() s4.setsockopt(SOL_SOCKET, SO_REUSEADDR, 0) self.assertRaisesErrno(errno.EADDRINUSE, s6.bind, ("0.0.0.0", 167)) # Can't bind after sendto. s = net_test.IPv4PingSocket() s.sendto(net_test.IPV4_PING, (net_test.IPV4_ADDR, 9132)) self.assertRaisesErrno(errno.EINVAL, s.bind, ("0.0.0.0", 5429))
def testIPv4LargePacket(self): s = net_test.IPv4PingSocket() data = net_test.IPV4_PING + 20000 * "a" s.sendto(data, ("127.0.0.1", 987)) self.assertValidPingResponse(s, data)
def testIPv4PingUsingSendto(self): s = net_test.IPv4PingSocket() written = s.sendto(net_test.IPV4_PING, (net_test.IPV4_ADDR, 55)) self.assertEquals(len(net_test.IPV4_PING), written) self.assertValidPingResponse(s, net_test.IPV4_PING)
def testIPv4LoopbackPingWithConnect(self): s = net_test.IPv4PingSocket() s.connect(("127.0.0.1", 55)) data = net_test.IPV4_PING + "foobarbaz" s.send(data) self.assertValidPingResponse(s, data)
def testIPv4SendWithNoConnection(self): s = net_test.IPv4PingSocket() self.assertRaisesErrno(errno.EDESTADDRREQ, s.send, net_test.IPV4_PING)