+ 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))
+ # No crash? Good.
+
+ def testCrossProtocolCalls(self):
+ """Tests that passing in the wrong family returns EAFNOSUPPORT.
+
+ Relevant kernel commits:
+ upstream net:
+ 91a0b60 net/ping: handle protocol mismatching scenario
+ 9145736d net: ping: Return EAFNOSUPPORT when appropriate.
+
+ android-3.10:
+ 78a6809 net/ping: handle protocol mismatching scenario
+ 428e6d6 net: ping: Return EAFNOSUPPORT when appropriate.
+ """
+
+ 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)
+