def CheckRawGrePacket(self, version, netid, routing_mode, dstaddr): s = self.BuildSocket(version, net_test.RawGRESocket, netid, routing_mode) inner_version = {4: 6, 6: 4}[version] inner_src = self.MyAddress(inner_version, netid) inner_dst = self.GetRemoteAddress(inner_version) inner = str(packets.UDP(inner_version, inner_src, inner_dst, sport=None)[1]) ethertype = {4: net_test.ETH_P_IP, 6: net_test.ETH_P_IPV6}[inner_version] # A GRE header can be as simple as two zero bytes and the ethertype. packet = struct.pack("!i", ethertype) + inner myaddr = self.MyAddress(version, netid) s.sendto(packet, (dstaddr, IPPROTO_GRE)) desc, expected = packets.GRE(version, myaddr, dstaddr, ethertype, inner) msg = "Raw IPv%d GRE with inner IPv%d UDP: expected %s on %s" % ( version, inner_version, desc, self.GetInterfaceName(netid)) self.ExpectPacketOn(netid, msg, expected)
def CheckUDPPacket(self, version, netid, routing_mode, dstaddr): s = self.BuildSocket(version, net_test.UDPSocket, netid, routing_mode) if version == 6 and dstaddr.startswith("::ffff"): version = 4 myaddr = self.MyAddress(version, netid) desc, expected = packets.UDP(version, myaddr, dstaddr, sport=None) msg = "IPv%s UDP %%s: expected %s on %s" % ( version, desc, self.GetInterfaceName(netid)) s.sendto(UDP_PAYLOAD, (dstaddr, 53)) self.ExpectPacketOn(netid, msg % "sendto", expected) # IP_UNICAST_IF doesn't seem to work on connected sockets, so no TCP. if routing_mode != "ucast_oif": s.connect((dstaddr, 53)) s.send(UDP_PAYLOAD) self.ExpectPacketOn(netid, msg % "connect/send", expected) s.close()
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 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
def _TestSocketPolicy(self, version): # Open a UDP socket and connect it. family = net_test.GetAddressFamily(version) s = socket(family, SOCK_DGRAM, 0) netid = self.RandomNetid() self.SelectInterface(s, netid, "mark") remotesockaddr = self.GetRemoteSocketAddress(version) s.connect((remotesockaddr, 53)) saddr, sport = s.getsockname()[:2] daddr, dport = s.getpeername()[:2] if version == 5: saddr = saddr.replace("::ffff:", "") daddr = daddr.replace("::ffff:", "") reqid = 0 desc, pkt = packets.UDP(version, saddr, daddr, sport=sport) s.sendto(net_test.UDP_PAYLOAD, (remotesockaddr, 53)) self.ExpectPacketOn(netid, "Send after socket, expected %s" % desc, pkt) # Using IPv4 XFRM on a dual-stack socket requires setting an AF_INET policy # that's written in terms of IPv4 addresses. xfrm_version = 4 if version == 5 else version xfrm_family = net_test.GetAddressFamily(xfrm_version) xfrm_base.ApplySocketPolicy(s, xfrm_family, xfrm.XFRM_POLICY_OUT, TEST_SPI, reqid, None) # Because the policy has level set to "require" (the default), attempting # to send a packet results in an error, because there is no SA that # matches the socket policy we set. self.assertRaisesErrno(EAGAIN, s.sendto, net_test.UDP_PAYLOAD, (remotesockaddr, 53)) # Adding a matching SA causes the packet to go out encrypted. The SA's # SPI must match the one in our template, and the destination address must # match the packet's destination address (in tunnel mode, it has to match # the tunnel destination). self.CreateNewSa(net_test.GetWildcardAddress(xfrm_version), self.GetRemoteAddress(xfrm_version), TEST_SPI, reqid, None) s.sendto(net_test.UDP_PAYLOAD, (remotesockaddr, 53)) expected_length = xfrm_base.GetEspPacketLength( xfrm.XFRM_MODE_TRANSPORT, version, False, net_test.UDP_PAYLOAD, xfrm_base._ALGO_HMAC_SHA1, xfrm_base._ALGO_CBC_AES_256) self._ExpectEspPacketOn(netid, TEST_SPI, 1, expected_length, None, None) # Sending to another destination doesn't work: again, no matching SA. remoteaddr2 = self.GetOtherRemoteSocketAddress(version) self.assertRaisesErrno(EAGAIN, s.sendto, net_test.UDP_PAYLOAD, (remoteaddr2, 53)) # Sending on another socket without the policy applied results in an # unencrypted packet going out. s2 = socket(family, SOCK_DGRAM, 0) self.SelectInterface(s2, netid, "mark") s2.sendto(net_test.UDP_PAYLOAD, (remotesockaddr, 53)) pkts = self.ReadAllPacketsOn(netid) self.assertEquals(1, len(pkts)) packet = pkts[0] protocol = packet.nh if version == 6 else packet.proto self.assertEquals(IPPROTO_UDP, protocol) # Deleting the SA causes the first socket to return errors again. self.xfrm.DeleteSaInfo(self.GetRemoteAddress(xfrm_version), TEST_SPI, IPPROTO_ESP) self.assertRaisesErrno(EAGAIN, s.sendto, net_test.UDP_PAYLOAD, (remotesockaddr, 53)) # Clear the socket policy and expect a cleartext packet. xfrm_base.SetPolicySockopt(s, family, None) s.sendto(net_test.UDP_PAYLOAD, (remotesockaddr, 53)) self.ExpectPacketOn(netid, "Send after clear, expected %s" % desc, pkt) # Clearing the policy twice is safe. xfrm_base.SetPolicySockopt(s, family, None) s.sendto(net_test.UDP_PAYLOAD, (remotesockaddr, 53)) self.ExpectPacketOn(netid, "Send after clear 2, expected %s" % desc, pkt) # Clearing if a policy was never set is safe. s = socket(AF_INET6, SOCK_DGRAM, 0) xfrm_base.SetPolicySockopt(s, family, None)