def _CheckNullEncryptionTunnelMode(self, version): family = net_test.GetAddressFamily(version) netid = self.RandomNetid() local_addr = self.MyAddress(version, netid) remote_addr = self.GetRemoteAddress(version) # Borrow the address of another netId as the source address of the tunnel tun_local = self.MyAddress(version, self.RandomNetid(netid)) # For generality, pick a tunnel endpoint that's not the address we # connect the socket to. tun_remote = TUNNEL_ENDPOINTS[version] # Output self.xfrm.AddSaInfo(tun_local, tun_remote, 0xABCD, xfrm.XFRM_MODE_TUNNEL, 123, xfrm_base._ALGO_CRYPT_NULL, xfrm_base._ALGO_AUTH_NULL, None, None, None, netid) # Input self.xfrm.AddSaInfo(tun_remote, tun_local, 0x9876, xfrm.XFRM_MODE_TUNNEL, 456, xfrm_base._ALGO_CRYPT_NULL, xfrm_base._ALGO_AUTH_NULL, None, None, None, None) sock = net_test.UDPSocket(family) self.SelectInterface(sock, netid, "mark") sock.bind((local_addr, 0)) local_port = sock.getsockname()[1] remote_port = 5555 xfrm_base.ApplySocketPolicy(sock, family, xfrm.XFRM_POLICY_OUT, 0xABCD, 123, (tun_local, tun_remote)) xfrm_base.ApplySocketPolicy(sock, family, xfrm.XFRM_POLICY_IN, 0x9876, 456, (tun_remote, tun_local)) # Create and receive an ESP packet. IpType = {4: scapy.IP, 6: scapy.IPv6}[version] input_pkt = (IpType(src=remote_addr, dst=local_addr) / scapy.UDP(sport=remote_port, dport=local_port) / "input hello") input_pkt = IpType(str(input_pkt)) # Compute length, checksum. input_pkt = xfrm_base.EncryptPacketWithNull(input_pkt, 0x9876, 1, (tun_remote, tun_local)) self.ReceivePacketOn(netid, input_pkt) msg, addr = sock.recvfrom(1024) self.assertEquals("input hello", msg) self.assertEquals((remote_addr, remote_port), addr[:2]) # Send and capture a packet. sock.sendto("output hello", (remote_addr, remote_port)) packets = self.ReadAllPacketsOn(netid) self.assertEquals(1, len(packets)) output_pkt = packets[0] output_pkt, esp_hdr = xfrm_base.DecryptPacketWithNull(output_pkt) self.assertEquals(output_pkt[scapy.UDP].len, len("output_hello") + 8) self.assertEquals(remote_addr, output_pkt.dst) self.assertEquals(remote_port, output_pkt[scapy.UDP].dport) # length of the payload plus the UDP header self.assertEquals("output hello", str(output_pkt[scapy.UDP].payload)) self.assertEquals(0xABCD, esp_hdr.spi)
def CheckPktinfoRouting(self, version): for _ in xrange(self.ITERATIONS): for netid in self.tuns: family = self.GetProtocolFamily(version) s = net_test.UDPSocket(family) if version == 6: # Create a flowlabel so we can use it. net_test.SetFlowLabel(s, net_test.IPV6_ADDR, 0xbeef) # Specify some arbitrary options. cmsgs = [ (net_test.SOL_IPV6, IPV6_HOPLIMIT, 39), (net_test.SOL_IPV6, IPV6_TCLASS, 0x83), (net_test.SOL_IPV6, IPV6_FLOWINFO, int(htonl(0xbeef))), ] else: # Support for setting IPv4 TOS and TTL via cmsg only appeared in 3.13. cmsgs = [] s.setsockopt(net_test.SOL_IP, IP_TTL, 39) s.setsockopt(net_test.SOL_IP, IP_TOS, 0x83) dstaddr = self.GetRemoteAddress(version) self.SendOnNetid(version, s, dstaddr, 53, netid, UDP_PAYLOAD, cmsgs) sport = s.getsockname()[1] srcaddr = self.MyAddress(version, netid) desc, expected = packets.UDPWithOptions(version, srcaddr, dstaddr, sport=sport) msg = "IPv%d UDP using pktinfo routing: expected %s on %s" % ( version, desc, self.GetInterfaceName(netid)) self.ExpectPacketOn(netid, msg, expected)
def CheckIPv6Connectivity(expect_connectivity): for netid in self.NETIDS: s = net_test.UDPSocket(AF_INET6) self.SetSocketMark(s, netid) if expect_connectivity: self.assertTrue(s.sendto(UDP_PAYLOAD, (net_test.IPV6_ADDR, 1234))) else: self.assertRaisesErrno(errno.ENETUNREACH, s.sendto, UDP_PAYLOAD, (net_test.IPV6_ADDR, 1234))
def testIPv6StickyPktinfo(self): for _ in xrange(self.ITERATIONS): for netid in self.tuns: s = net_test.UDPSocket(AF_INET6) # Set a flowlabel. net_test.SetFlowLabel(s, net_test.IPV6_ADDR, 0xdead) s.setsockopt(net_test.SOL_IPV6, net_test.IPV6_FLOWINFO_SEND, 1) # Set some destination options. nonce = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c" dstopts = "".join([ "\x11\x02", # Next header=UDP, 24 bytes of options. "\x01\x06", "\x00" * 6, # PadN, 6 bytes of padding. "\x8b\x0c", # ILNP nonce, 12 bytes. nonce ]) s.setsockopt(net_test.SOL_IPV6, IPV6_DSTOPTS, dstopts) s.setsockopt(net_test.SOL_IPV6, IPV6_UNICAST_HOPS, 255) pktinfo = multinetwork_base.MakePktInfo( 6, None, self.ifindices[netid]) # Set the sticky pktinfo option. s.setsockopt(net_test.SOL_IPV6, IPV6_PKTINFO, pktinfo) # Specify the flowlabel in the destination address. s.sendto(UDP_PAYLOAD, (net_test.IPV6_ADDR, 53, 0xdead, 0)) sport = s.getsockname()[1] srcaddr = self.MyAddress(6, netid) expected = (scapy.IPv6( src=srcaddr, dst=net_test.IPV6_ADDR, fl=0xdead, hlim=255) / scapy.IPv6ExtHdrDestOpt(options=[ scapy.PadN(optdata="\x00\x00\x00\x00\x00\x00"), scapy.HBHOptUnknown(otype=0x8b, optdata=nonce) ]) / scapy.UDP(sport=sport, dport=53) / UDP_PAYLOAD) msg = "IPv6 UDP using sticky pktinfo: expected UDP packet on %s" % ( self.GetInterfaceName(netid)) self.ExpectPacketOn(netid, msg, expected)
def testReadInterrupted(self): """Tests that read() is interrupted by SOCK_DESTROY.""" for version in [4, 5, 6]: family = {4: AF_INET, 5: AF_INET6, 6: AF_INET6}[version] s = net_test.UDPSocket(family) self.SelectInterface(s, random.choice(self.NETIDS), "mark") addr = self.GetRemoteAddress(version) # Check that reads on connected sockets are interrupted. s.connect((addr, 53)) self.assertEquals(3, s.send("foo")) self.CloseDuringBlockingCall(s, lambda sock: sock.recv(4096), ECONNABORTED) # A destroyed socket is no longer connected, but still usable. self.assertRaisesErrno(EDESTADDRREQ, s.send, "foo") self.assertEquals(3, s.sendto("foo", (addr, 53))) # Check that reads on unconnected sockets are also interrupted. self.CloseDuringBlockingCall(s, lambda sock: sock.recv(4096), ECONNABORTED)
def CheckRemarking(self, version, use_connect): # Remarking or resetting UNICAST_IF on connected sockets does not work. if use_connect: modes = ["oif"] else: modes = ["mark", "oif"] if HAVE_UNICAST_IF: modes += ["ucast_oif"] for mode in modes: s = net_test.UDPSocket(self.GetProtocolFamily(version)) # Figure out what packets to expect. unspec = {4: "0.0.0.0", 6: "::"}[version] sport = Packets.RandomPort() s.bind((unspec, sport)) dstaddr = {4: self.IPV4_ADDR, 6: self.IPV6_ADDR}[version] desc, expected = Packets.UDP(version, unspec, dstaddr, sport) # If we're testing connected sockets, connect the socket on the first # netid now. if use_connect: netid = self.tuns.keys()[0] self.SelectInterface(s, netid, mode) s.connect((dstaddr, 53)) expected.src = self.MyAddress(version, netid) # For each netid, select that network without closing the socket, and # check that the packets sent on that socket go out on the right network. for netid in self.tuns: self.SelectInterface(s, netid, mode) if not use_connect: expected.src = self.MyAddress(version, netid) s.sendto(UDP_PAYLOAD, (dstaddr, 53)) connected_str = "Connected" if use_connect else "Unconnected" msg = "%s UDPv%d socket remarked using %s: expecting %s on %s" % ( connected_str, version, mode, desc, self.GetInterfaceName(netid)) self.ExpectPacketOn(netid, msg, expected) self.SelectInterface(s, None, mode)
def testOnlinkCommunication(self): """Checks that on-link communication goes direct and not through routers.""" for netid in self.tuns: # Send a UDP packet to a random on-link destination. s = net_test.UDPSocket(AF_INET6) iface = self.GetInterfaceName(netid) self.BindToDevice(s, iface) # dstaddr can never be our address because GetRandomDestination only fills # in the lower 32 bits, but our address has 0xff in the byte before that # (since it's constructed from the EUI-64 and so has ff:fe in the middle). dstaddr = self.GetRandomDestination(self.IPv6Prefix(netid)) s.sendto(UDP_PAYLOAD, (dstaddr, 53)) # Expect an NS for that destination on the interface. myaddr = self.MyAddress(6, netid) mymac = self.MyMacAddress(netid) desc, expected = Packets.NS(myaddr, dstaddr, mymac) msg = "Sending UDP packet to on-link destination: expecting %s" % desc time.sleep( 0.0001) # Required to make the test work on kernel 3.1(!) self.ExpectPacketOn(netid, msg, expected) # Send an NA. tgtmac = "02:00:00:00:%02x:99" % netid _, reply = Packets.NA(dstaddr, myaddr, tgtmac) # Don't use ReceivePacketOn, since that uses the router's MAC address as # the source. Instead, construct our own Ethernet header with source # MAC of tgtmac. reply = scapy.Ether(src=tgtmac, dst=mymac) / reply self.ReceiveEtherPacketOn(netid, reply) # Expect the kernel to send the original UDP packet now that the ND cache # entry has been populated. sport = s.getsockname()[1] desc, expected = Packets.UDP(6, myaddr, dstaddr, sport=sport) msg = "After NA response, expecting %s" % desc self.ExpectPacketOn(netid, msg, expected)
def CheckForwardingUdp(self, netid, iface1, iface2): # TODO: Make a test for IPv4 # 1. Make version as an argument. Pick address to bind from array based # on version. # 2. The prefix length of the address is hardcoded to /64. Use the subnet # mask there instead. # 3. We recreate the address with SendRA, which obviously only works for # IPv6. Use AddAddress for IPv4. # Create a UDP socket and bind to it version = 6 s = net_test.UDPSocket(AF_INET6) self.SetSocketMark(s, netid) s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) s.bind(("::", 53)) remoteaddr = self.GetRemoteAddress(version) myaddr = self.MyAddress(version, netid) try: # Delete address and check if packet is forwarded # (and not dropped because an incorrect socket match happened) self.iproute.DelAddress(myaddr, 64, self.ifindices[netid]) hoplimit = 39 desc, udp_pkt = packets.UDPWithOptions(version, myaddr, remoteaddr, 53) # Decrements the hoplimit of a packet to simulate forwarding. desc_fwded, udp_fwd = packets.UDPWithOptions( version, myaddr, remoteaddr, 53, hoplimit - 1) msg = "Sent %s, expected %s" % (desc, desc_fwded) self.ReceivePacketOn(iface1, udp_pkt) self.ExpectPacketOn(iface2, msg, udp_fwd) finally: # Recreate the address. self.SendRA(netid) s.close()
def BindToAddress(self, address): s = net_test.UDPSocket(AF_INET6) s.bind((address, 0, 0, 0))
def CheckRemarking(self, version, use_connect): modes = ["mark", "oif", "uid"] # Setting UNICAST_IF on connected sockets does not work. if not use_connect and HAVE_UNICAST_IF: modes += ["ucast_oif"] for mode in modes: s = net_test.UDPSocket(self.GetProtocolFamily(version)) # Figure out what packets to expect. sport = net_test.BindRandomPort(version, s) dstaddr = {4: self.IPV4_ADDR, 6: self.IPV6_ADDR}[version] unspec = {4: "0.0.0.0", 6: "::"}[version] # Placeholder. desc, expected = packets.UDP(version, unspec, dstaddr, sport) # If we're testing connected sockets, connect the socket on the first # netid now. if use_connect: netid = self.tuns.keys()[0] self.SelectInterface(s, netid, mode) s.connect((dstaddr, 53)) expected.src = self.MyAddress(version, netid) # For each netid, select that network without closing the socket, and # check that the packets sent on that socket go out on the right network. # # For connected sockets, routing is cached in the socket's destination # cache entry. In this case, we check that just re-selecting the netid # (except via SO_BINDTODEVICE) does not change routing, but that # subsequently invalidating the destination cache entry does. Arguably # this is a bug in the kernel because re-selecting the netid should cause # routing to change. But it is a convenient way to check that # InvalidateDstCache actually works. prevnetid = None for netid in self.tuns: self.SelectInterface(s, netid, mode) if not use_connect: expected.src = self.MyAddress(version, netid) def ExpectSendUsesNetid(netid): connected_str = "Connected" if use_connect else "Unconnected" msg = "%s UDPv%d socket remarked using %s: expecting %s on %s" % ( connected_str, version, mode, desc, self.GetInterfaceName(netid)) if use_connect: s.send(UDP_PAYLOAD) else: s.sendto(UDP_PAYLOAD, (dstaddr, 53)) self.ExpectPacketOn(netid, msg, expected) if use_connect and mode in ["mark", "uid", "ucast_oif"]: # If we have a destination cache entry, packets are not rerouted... if prevnetid: ExpectSendUsesNetid(prevnetid) # ... until we invalidate it. self.InvalidateDstCache(version, dstaddr, prevnetid) ExpectSendUsesNetid(netid) else: ExpectSendUsesNetid(netid) self.SelectInterface(s, None, mode) prevnetid = netid