def _NlAttrTcpMetricsAddr(self, address, is_source): version = net_test.GetAddressVersion(address) family = net_test.GetAddressFamily(version) if version == 5: address = address.replace("::ffff:", "") nla_name = "TCP_METRICS_ATTR_%s_IPV%d" % ("SADDR" if is_source else "ADDR", version) nla_type = globals()[nla_name] return self._NlAttrIPAddress(nla_type, family, address)
def CreateTunnel(self, direction, selector, src, dst, spi, encryption, auth_trunc, mark, output_mark, xfrm_if_id): """Create an XFRM Tunnel Consisting of a Policy and an SA. Create a unidirectional XFRM tunnel, which entails one Policy and one security association. Args: direction: XFRM_POLICY_IN or XFRM_POLICY_OUT selector: An XfrmSelector that specifies the packets to be transformed. This is only applied to the policy; the selector in the SA is always empty. If the passed-in selector is None, then the tunnel is made dual-stack. This requires two policies, one for IPv4 and one for IPv6. src: The source address of the tunneled packets dst: The destination address of the tunneled packets spi: The SPI for the IPsec SA that encapsulates the tunneled packet encryption: A tuple (XfrmAlgo, key), the encryption parameters. auth_trunc: A tuple (XfrmAlgoAuth, key), the authentication parameters. mark: An XfrmMark, the mark used for selecting packets to be tunneled, and for matching the security policy and security association. None means unspecified. output_mark: The mark used to select the underlying network for packets outbound from xfrm. None means unspecified. xfrm_if_id: The ID of the XFRM interface to use or None. """ outer_family = net_test.GetAddressFamily(net_test.GetAddressVersion(dst)) self.AddSaInfo(src, dst, spi, XFRM_MODE_TUNNEL, 0, encryption, auth_trunc, None, None, mark, output_mark, xfrm_if_id=xfrm_if_id) if selector is None: selectors = [EmptySelector(AF_INET), EmptySelector(AF_INET6)] else: selectors = [selector] for selector in selectors: policy = UserPolicy(direction, selector) tmpl = UserTemplate(outer_family, spi, 0, (src, dst)) self.AddPolicyInfo(policy, tmpl, mark, xfrm_if_id=xfrm_if_id)
def EncryptPacketWithNull(packet, spi, seq, tun_addrs): """Apply null encryption to a packet. This performs ESP encapsulation on the given packet. The returned packet will be a tunnel mode packet if tun_addrs is provided. The input packet is assumed to be a UDP packet. The input packet *MUST* have its length and checksum fields in IP and UDP headers set appropriately. This can be done by "rebuilding" the scapy object. e.g., ip6_packet = scapy.IPv6(str(ip6_packet)) TODO: Support TCP Args: packet: a scapy.IPv6 or scapy.IP packet spi: security parameter index for ESP header in host byte order seq: sequence number for ESP header tun_addrs: A tuple of (local, remote) addresses for tunnel mode, or None to request a transport mode packet. Return: The encrypted packet (scapy.IPv6 or scapy.IP) """ # The top-level packet changes in tunnel mode, which would invalidate # the passed-in packet pointer. For consistency, this function now returns # a new packet and does not modify the user's original packet. packet = packet.copy() udp_layer = packet.getlayer(scapy.UDP) if not udp_layer: raise ValueError("Expected a UDP packet") # Build an ESP header. esp_packet = scapy.Raw(xfrm.EspHdr((spi, seq)).Pack()) if tun_addrs: tsrc_addr, tdst_addr = tun_addrs outer_version = net_test.GetAddressVersion(tsrc_addr) ip_type = {4: scapy.IP, 6: scapy.IPv6}[outer_version] new_ip_layer = ip_type(src=tsrc_addr, dst=tdst_addr) inner_layer = packet esp_nexthdr = {scapy.IPv6: IPPROTO_IPV6, scapy.IP: IPPROTO_IPIP}[type(packet)] else: new_ip_layer = None inner_layer = udp_layer esp_nexthdr = IPPROTO_UDP # ESP padding per RFC 4303 section 2.4. # For a null cipher with a block size of 1, padding is only necessary to # ensure that the 1-byte Pad Length and Next Header fields are right aligned # on a 4-byte boundary. esplen = (len(inner_layer) + 2) # UDP length plus Pad Length and Next Header. padlen = util.GetPadLength(4, esplen) # The pad bytes are consecutive integers starting from 0x01. padding = "".join((chr(i) for i in xrange(1, padlen + 1))) trailer = padding + struct.pack("BB", padlen, esp_nexthdr) # Assemble the packet. esp_packet.payload = scapy.Raw(inner_layer) packet = new_ip_layer if new_ip_layer else packet packet.payload = scapy.Raw(str(esp_packet) + trailer) # TODO: Can we simplify this and avoid the initial copy()? # Fix the IPv4/IPv6 headers. if type(packet) is scapy.IPv6: packet.nh = IPPROTO_ESP # Recompute plen. packet.plen = None packet = scapy.IPv6(str(packet)) elif type(packet) is scapy.IP: packet.proto = IPPROTO_ESP # Recompute IPv4 len and checksum. packet.len = None packet.chksum = None packet = scapy.IP(str(packet)) else: raise ValueError("First layer in packet should be IPv4 or IPv6: " + repr(packet)) return packet
def _CheckVtiInputOutput(self, vti, inner_version): local_outer = vti.local remote_outer = vti.remote # Create a socket to receive packets. read_sock = socket(net_test.GetAddressFamily(inner_version), SOCK_DGRAM, 0) read_sock.bind((net_test.GetWildcardAddress(inner_version), 0)) # The second parameter of the tuple is the port number regardless of AF. port = read_sock.getsockname()[1] # Guard against the eventuality of the receive failing. csocket.SetSocketTimeout(read_sock, 100) # Send a packet out via the vti-backed network, bound for the port number # of the input socket. write_sock = socket(net_test.GetAddressFamily(inner_version), SOCK_DGRAM, 0) self.SelectInterface(write_sock, vti.netid, "mark") write_sock.sendto(net_test.UDP_PAYLOAD, (_GetRemoteInnerAddress(inner_version), port)) # Read a tunneled IP packet on the underlying (outbound) network # verifying that it is an ESP packet. self.assertSentPacket(vti) pkt = self._ExpectEspPacketOn(vti.underlying_netid, vti.out_spi, vti.tx, None, local_outer, remote_outer) # Perform an address switcheroo so that the inner address of the remote # end of the tunnel is now the address on the local VTI interface; this # way, the twisted inner packet finds a destination via the VTI once # decrypted. remote = _GetRemoteInnerAddress(inner_version) local = vti.addrs[inner_version] self._SwapInterfaceAddress(vti.iface, new_addr=remote, old_addr=local) try: # Swap the packet's IP headers and write it back to the # underlying network. pkt = TunTwister.TwistPacket(pkt) self.ReceivePacketOn(vti.underlying_netid, pkt) self.assertReceivedPacket(vti) # Receive the decrypted packet on the dest port number. read_packet = read_sock.recv(4096) self.assertEquals(read_packet, net_test.UDP_PAYLOAD) finally: # Unwind the switcheroo self._SwapInterfaceAddress(vti.iface, new_addr=local, old_addr=remote) # Now attempt to provoke an ICMP error. # TODO: deduplicate with multinetwork_test.py. version = net_test.GetAddressVersion(vti.remote) dst_prefix, intermediate = { 4: ("172.19.", "172.16.9.12"), 6: ("2001:db8::", "2001:db8::1") }[version] write_sock.sendto(net_test.UDP_PAYLOAD, (_GetRemoteInnerAddress(inner_version), port)) self.assertSentPacket(vti) pkt = self._ExpectEspPacketOn(vti.underlying_netid, vti.out_spi, vti.tx, None, local_outer, remote_outer) myaddr = self.MyAddress(version, vti.underlying_netid) _, toobig = packets.ICMPPacketTooBig(version, intermediate, myaddr, pkt) self.ReceivePacketOn(vti.underlying_netid, toobig) # Check that the packet too big reduced the MTU. routes = self.iproute.GetRoutes(vti.remote, 0, vti.underlying_netid, None) self.assertEquals(1, len(routes)) rtmsg, attributes = routes[0] self.assertEquals(iproute.RTN_UNICAST, rtmsg.type) self.assertEquals(packets.PTB_MTU, attributes["RTA_METRICS"]["RTAX_MTU"]) # Clear PMTU information so that future tests don't have to worry about it. self.InvalidateDstCache(version, vti.underlying_netid)