1*2f2c4c7aSAndroid Build Coastguard Worker#!/usr/bin/python3 2*2f2c4c7aSAndroid Build Coastguard Worker# 3*2f2c4c7aSAndroid Build Coastguard Worker# Copyright 2017 The Android Open Source Project 4*2f2c4c7aSAndroid Build Coastguard Worker# 5*2f2c4c7aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*2f2c4c7aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*2f2c4c7aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*2f2c4c7aSAndroid Build Coastguard Worker# 9*2f2c4c7aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*2f2c4c7aSAndroid Build Coastguard Worker# 11*2f2c4c7aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*2f2c4c7aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*2f2c4c7aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*2f2c4c7aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*2f2c4c7aSAndroid Build Coastguard Worker# limitations under the License. 16*2f2c4c7aSAndroid Build Coastguard Worker 17*2f2c4c7aSAndroid Build Coastguard Workerfrom socket import * # pylint: disable=wildcard-import 18*2f2c4c7aSAndroid Build Coastguard Workerfrom scapy import all as scapy 19*2f2c4c7aSAndroid Build Coastguard Workerimport binascii 20*2f2c4c7aSAndroid Build Coastguard Workerimport struct 21*2f2c4c7aSAndroid Build Coastguard Worker 22*2f2c4c7aSAndroid Build Coastguard Workerimport csocket 23*2f2c4c7aSAndroid Build Coastguard Workerimport cstruct 24*2f2c4c7aSAndroid Build Coastguard Workerimport multinetwork_base 25*2f2c4c7aSAndroid Build Coastguard Workerimport net_test 26*2f2c4c7aSAndroid Build Coastguard Workerimport util 27*2f2c4c7aSAndroid Build Coastguard Workerimport xfrm 28*2f2c4c7aSAndroid Build Coastguard Worker 29*2f2c4c7aSAndroid Build Coastguard Worker_ENCRYPTION_KEY_256 = binascii.unhexlify("308146eb3bd84b044573d60f5a5fd159" 30*2f2c4c7aSAndroid Build Coastguard Worker "57c7d4fe567a2120f35bae0f9869ec22") 31*2f2c4c7aSAndroid Build Coastguard Worker_AUTHENTICATION_KEY_128 = binascii.unhexlify("af442892cdcd0ef650e9c299f9a8436a") 32*2f2c4c7aSAndroid Build Coastguard Worker 33*2f2c4c7aSAndroid Build Coastguard Worker_ALGO_AUTH_NULL = (xfrm.XfrmAlgoAuth((b"digest_null", 0, 0)), b"") 34*2f2c4c7aSAndroid Build Coastguard Worker_ALGO_HMAC_SHA1 = (xfrm.XfrmAlgoAuth((xfrm.XFRM_AALG_HMAC_SHA1, 128, 96)), 35*2f2c4c7aSAndroid Build Coastguard Worker _AUTHENTICATION_KEY_128) 36*2f2c4c7aSAndroid Build Coastguard Worker 37*2f2c4c7aSAndroid Build Coastguard Worker_ALGO_CRYPT_NULL = (xfrm.XfrmAlgo((b"ecb(cipher_null)", 0)), b"") 38*2f2c4c7aSAndroid Build Coastguard Worker_ALGO_CBC_AES_256 = (xfrm.XfrmAlgo((xfrm.XFRM_EALG_CBC_AES, 256)), 39*2f2c4c7aSAndroid Build Coastguard Worker _ENCRYPTION_KEY_256) 40*2f2c4c7aSAndroid Build Coastguard Worker 41*2f2c4c7aSAndroid Build Coastguard Worker# Match all bits of the mark 42*2f2c4c7aSAndroid Build Coastguard WorkerMARK_MASK_ALL = 0xffffffff 43*2f2c4c7aSAndroid Build Coastguard Worker 44*2f2c4c7aSAndroid Build Coastguard Worker 45*2f2c4c7aSAndroid Build Coastguard Workerdef SetPolicySockopt(sock, family, opt_data): 46*2f2c4c7aSAndroid Build Coastguard Worker optlen = len(opt_data) if opt_data is not None else 0 47*2f2c4c7aSAndroid Build Coastguard Worker if family == AF_INET: 48*2f2c4c7aSAndroid Build Coastguard Worker csocket.Setsockopt(sock, IPPROTO_IP, xfrm.IP_XFRM_POLICY, opt_data, optlen) 49*2f2c4c7aSAndroid Build Coastguard Worker else: 50*2f2c4c7aSAndroid Build Coastguard Worker csocket.Setsockopt(sock, IPPROTO_IPV6, xfrm.IPV6_XFRM_POLICY, opt_data, 51*2f2c4c7aSAndroid Build Coastguard Worker optlen) 52*2f2c4c7aSAndroid Build Coastguard Worker 53*2f2c4c7aSAndroid Build Coastguard Worker 54*2f2c4c7aSAndroid Build Coastguard Workerdef ApplySocketPolicy(sock, family, direction, spi, reqid, tun_addrs): 55*2f2c4c7aSAndroid Build Coastguard Worker """Create and apply an ESP policy to a socket. 56*2f2c4c7aSAndroid Build Coastguard Worker 57*2f2c4c7aSAndroid Build Coastguard Worker A socket may have only one policy per direction, so applying a policy will 58*2f2c4c7aSAndroid Build Coastguard Worker remove any policy that was previously applied in that direction. 59*2f2c4c7aSAndroid Build Coastguard Worker 60*2f2c4c7aSAndroid Build Coastguard Worker Args: 61*2f2c4c7aSAndroid Build Coastguard Worker sock: The socket that needs a policy 62*2f2c4c7aSAndroid Build Coastguard Worker family: AF_INET or AF_INET6 63*2f2c4c7aSAndroid Build Coastguard Worker direction: XFRM_POLICY_IN or XFRM_POLICY_OUT 64*2f2c4c7aSAndroid Build Coastguard Worker spi: 32-bit SPI in host byte order 65*2f2c4c7aSAndroid Build Coastguard Worker reqid: 32-bit ID matched against SAs 66*2f2c4c7aSAndroid Build Coastguard Worker tun_addrs: A tuple of (local, remote) addresses for tunnel mode, or None 67*2f2c4c7aSAndroid Build Coastguard Worker to request a transport mode SA. 68*2f2c4c7aSAndroid Build Coastguard Worker """ 69*2f2c4c7aSAndroid Build Coastguard Worker # Create a selector that matches all packets of the specified address family. 70*2f2c4c7aSAndroid Build Coastguard Worker selector = xfrm.EmptySelector(family) 71*2f2c4c7aSAndroid Build Coastguard Worker 72*2f2c4c7aSAndroid Build Coastguard Worker # Create an XFRM policy and template. 73*2f2c4c7aSAndroid Build Coastguard Worker policy = xfrm.UserPolicy(direction, selector) 74*2f2c4c7aSAndroid Build Coastguard Worker template = xfrm.UserTemplate(family, spi, reqid, tun_addrs) 75*2f2c4c7aSAndroid Build Coastguard Worker 76*2f2c4c7aSAndroid Build Coastguard Worker # Set the policy and template on our socket. 77*2f2c4c7aSAndroid Build Coastguard Worker opt_data = policy.Pack() + template.Pack() 78*2f2c4c7aSAndroid Build Coastguard Worker 79*2f2c4c7aSAndroid Build Coastguard Worker # The policy family might not match the socket family. For example, we might 80*2f2c4c7aSAndroid Build Coastguard Worker # have an IPv4 policy on a dual-stack socket. 81*2f2c4c7aSAndroid Build Coastguard Worker sockfamily = sock.getsockopt(SOL_SOCKET, net_test.SO_DOMAIN) 82*2f2c4c7aSAndroid Build Coastguard Worker SetPolicySockopt(sock, sockfamily, opt_data) 83*2f2c4c7aSAndroid Build Coastguard Worker 84*2f2c4c7aSAndroid Build Coastguard Workerdef _GetCryptParameters(crypt_alg): 85*2f2c4c7aSAndroid Build Coastguard Worker """Looks up encryption algorithm's block and IV lengths. 86*2f2c4c7aSAndroid Build Coastguard Worker 87*2f2c4c7aSAndroid Build Coastguard Worker Args: 88*2f2c4c7aSAndroid Build Coastguard Worker crypt_alg: the encryption algorithm constant 89*2f2c4c7aSAndroid Build Coastguard Worker Returns: 90*2f2c4c7aSAndroid Build Coastguard Worker A tuple of the block size, and IV length 91*2f2c4c7aSAndroid Build Coastguard Worker """ 92*2f2c4c7aSAndroid Build Coastguard Worker if crypt_alg == _ALGO_CRYPT_NULL: 93*2f2c4c7aSAndroid Build Coastguard Worker return (4, 0) 94*2f2c4c7aSAndroid Build Coastguard Worker if crypt_alg == _ALGO_CBC_AES_256: 95*2f2c4c7aSAndroid Build Coastguard Worker return (16, 16) 96*2f2c4c7aSAndroid Build Coastguard Worker return (0, 0) 97*2f2c4c7aSAndroid Build Coastguard Worker 98*2f2c4c7aSAndroid Build Coastguard Worker 99*2f2c4c7aSAndroid Build Coastguard Workerdef GetEspPacketLength(mode, version, udp_encap, payload, 100*2f2c4c7aSAndroid Build Coastguard Worker auth_alg, crypt_alg): 101*2f2c4c7aSAndroid Build Coastguard Worker """Calculates encrypted length of a UDP packet with the given payload. 102*2f2c4c7aSAndroid Build Coastguard Worker 103*2f2c4c7aSAndroid Build Coastguard Worker Args: 104*2f2c4c7aSAndroid Build Coastguard Worker mode: XFRM_MODE_TRANSPORT or XFRM_MODE_TUNNEL. 105*2f2c4c7aSAndroid Build Coastguard Worker version: IPPROTO_IP for IPv4, IPPROTO_IPV6 for IPv6. The inner header. 106*2f2c4c7aSAndroid Build Coastguard Worker udp_encap: whether UDP encap overhead should be accounted for. Since the 107*2f2c4c7aSAndroid Build Coastguard Worker outermost IP header is ignored (payload only), only add for udp 108*2f2c4c7aSAndroid Build Coastguard Worker encap'd packets. 109*2f2c4c7aSAndroid Build Coastguard Worker payload: UDP payload bytes. 110*2f2c4c7aSAndroid Build Coastguard Worker auth_alg: The xfrm_base authentication algorithm used in the SA. 111*2f2c4c7aSAndroid Build Coastguard Worker crypt_alg: The xfrm_base encryption algorithm used in the SA. 112*2f2c4c7aSAndroid Build Coastguard Worker 113*2f2c4c7aSAndroid Build Coastguard Worker Return: the packet length. 114*2f2c4c7aSAndroid Build Coastguard Worker """ 115*2f2c4c7aSAndroid Build Coastguard Worker 116*2f2c4c7aSAndroid Build Coastguard Worker crypt_iv_len, crypt_blk_size=_GetCryptParameters(crypt_alg) 117*2f2c4c7aSAndroid Build Coastguard Worker auth_trunc_len = auth_alg[0].trunc_len 118*2f2c4c7aSAndroid Build Coastguard Worker 119*2f2c4c7aSAndroid Build Coastguard Worker # Wrap in UDP payload 120*2f2c4c7aSAndroid Build Coastguard Worker payload_len = len(payload) + net_test.UDP_HDR_LEN 121*2f2c4c7aSAndroid Build Coastguard Worker 122*2f2c4c7aSAndroid Build Coastguard Worker # Size constants 123*2f2c4c7aSAndroid Build Coastguard Worker esp_hdr_len = len(xfrm.EspHdr) # SPI + Seq number 124*2f2c4c7aSAndroid Build Coastguard Worker icv_len = auth_trunc_len // 8 125*2f2c4c7aSAndroid Build Coastguard Worker 126*2f2c4c7aSAndroid Build Coastguard Worker # Add inner IP header if tunnel mode 127*2f2c4c7aSAndroid Build Coastguard Worker if mode == xfrm.XFRM_MODE_TUNNEL: 128*2f2c4c7aSAndroid Build Coastguard Worker payload_len += net_test.GetIpHdrLength(version) 129*2f2c4c7aSAndroid Build Coastguard Worker 130*2f2c4c7aSAndroid Build Coastguard Worker # Add ESP trailer 131*2f2c4c7aSAndroid Build Coastguard Worker payload_len += 2 # Pad Length + Next Header fields 132*2f2c4c7aSAndroid Build Coastguard Worker 133*2f2c4c7aSAndroid Build Coastguard Worker # Align to block size of encryption algorithm 134*2f2c4c7aSAndroid Build Coastguard Worker payload_len += util.GetPadLength(crypt_blk_size, payload_len) 135*2f2c4c7aSAndroid Build Coastguard Worker 136*2f2c4c7aSAndroid Build Coastguard Worker # Add initialization vector, header length and ICV length 137*2f2c4c7aSAndroid Build Coastguard Worker payload_len += esp_hdr_len + crypt_iv_len + icv_len 138*2f2c4c7aSAndroid Build Coastguard Worker 139*2f2c4c7aSAndroid Build Coastguard Worker # Add encap as needed 140*2f2c4c7aSAndroid Build Coastguard Worker if udp_encap: 141*2f2c4c7aSAndroid Build Coastguard Worker payload_len += net_test.UDP_HDR_LEN 142*2f2c4c7aSAndroid Build Coastguard Worker 143*2f2c4c7aSAndroid Build Coastguard Worker return payload_len 144*2f2c4c7aSAndroid Build Coastguard Worker 145*2f2c4c7aSAndroid Build Coastguard Worker 146*2f2c4c7aSAndroid Build Coastguard Workerdef GetEspTrailer(length, nexthdr): 147*2f2c4c7aSAndroid Build Coastguard Worker # ESP padding per RFC 4303 section 2.4. 148*2f2c4c7aSAndroid Build Coastguard Worker # For a null cipher with a block size of 1, padding is only necessary to 149*2f2c4c7aSAndroid Build Coastguard Worker # ensure that the 1-byte Pad Length and Next Header fields are right aligned 150*2f2c4c7aSAndroid Build Coastguard Worker # on a 4-byte boundary. 151*2f2c4c7aSAndroid Build Coastguard Worker esplen = length + 2 # Packet length plus Pad Length and Next Header. 152*2f2c4c7aSAndroid Build Coastguard Worker padlen = util.GetPadLength(4, esplen) 153*2f2c4c7aSAndroid Build Coastguard Worker # The pad bytes are consecutive integers starting from 0x01. 154*2f2c4c7aSAndroid Build Coastguard Worker padding = "".join((chr(i) for i in range(1, padlen + 1))).encode("utf-8") 155*2f2c4c7aSAndroid Build Coastguard Worker return padding + struct.pack("BB", padlen, nexthdr) 156*2f2c4c7aSAndroid Build Coastguard Worker 157*2f2c4c7aSAndroid Build Coastguard Worker 158*2f2c4c7aSAndroid Build Coastguard Workerdef EncryptPacketWithNull(packet, spi, seq, tun_addrs): 159*2f2c4c7aSAndroid Build Coastguard Worker """Apply null encryption to a packet. 160*2f2c4c7aSAndroid Build Coastguard Worker 161*2f2c4c7aSAndroid Build Coastguard Worker This performs ESP encapsulation on the given packet. The returned packet will 162*2f2c4c7aSAndroid Build Coastguard Worker be a tunnel mode packet if tun_addrs is provided. 163*2f2c4c7aSAndroid Build Coastguard Worker 164*2f2c4c7aSAndroid Build Coastguard Worker The input packet is assumed to be a UDP packet. The input packet *MUST* have 165*2f2c4c7aSAndroid Build Coastguard Worker its length and checksum fields in IP and UDP headers set appropriately. This 166*2f2c4c7aSAndroid Build Coastguard Worker can be done by "rebuilding" the scapy object. e.g., 167*2f2c4c7aSAndroid Build Coastguard Worker ip6_packet = scapy.IPv6(bytes(ip6_packet)) 168*2f2c4c7aSAndroid Build Coastguard Worker 169*2f2c4c7aSAndroid Build Coastguard Worker TODO: Support TCP 170*2f2c4c7aSAndroid Build Coastguard Worker 171*2f2c4c7aSAndroid Build Coastguard Worker Args: 172*2f2c4c7aSAndroid Build Coastguard Worker packet: a scapy.IPv6 or scapy.IP packet 173*2f2c4c7aSAndroid Build Coastguard Worker spi: security parameter index for ESP header in host byte order 174*2f2c4c7aSAndroid Build Coastguard Worker seq: sequence number for ESP header 175*2f2c4c7aSAndroid Build Coastguard Worker tun_addrs: A tuple of (local, remote) addresses for tunnel mode, or None 176*2f2c4c7aSAndroid Build Coastguard Worker to request a transport mode packet. 177*2f2c4c7aSAndroid Build Coastguard Worker 178*2f2c4c7aSAndroid Build Coastguard Worker Return: 179*2f2c4c7aSAndroid Build Coastguard Worker The encrypted packet (scapy.IPv6 or scapy.IP) 180*2f2c4c7aSAndroid Build Coastguard Worker """ 181*2f2c4c7aSAndroid Build Coastguard Worker # The top-level packet changes in tunnel mode, which would invalidate 182*2f2c4c7aSAndroid Build Coastguard Worker # the passed-in packet pointer. For consistency, this function now returns 183*2f2c4c7aSAndroid Build Coastguard Worker # a new packet and does not modify the user's original packet. 184*2f2c4c7aSAndroid Build Coastguard Worker packet = packet.copy() 185*2f2c4c7aSAndroid Build Coastguard Worker udp_layer = packet.getlayer(scapy.UDP) 186*2f2c4c7aSAndroid Build Coastguard Worker if not udp_layer: 187*2f2c4c7aSAndroid Build Coastguard Worker raise ValueError("Expected a UDP packet") 188*2f2c4c7aSAndroid Build Coastguard Worker # Build an ESP header. 189*2f2c4c7aSAndroid Build Coastguard Worker esp_packet = scapy.Raw(xfrm.EspHdr((spi, seq)).Pack()) 190*2f2c4c7aSAndroid Build Coastguard Worker 191*2f2c4c7aSAndroid Build Coastguard Worker if tun_addrs: 192*2f2c4c7aSAndroid Build Coastguard Worker tsrc_addr, tdst_addr = tun_addrs 193*2f2c4c7aSAndroid Build Coastguard Worker outer_version = net_test.GetAddressVersion(tsrc_addr) 194*2f2c4c7aSAndroid Build Coastguard Worker ip_type = {4: scapy.IP, 6: scapy.IPv6}[outer_version] 195*2f2c4c7aSAndroid Build Coastguard Worker new_ip_layer = ip_type(src=tsrc_addr, dst=tdst_addr) 196*2f2c4c7aSAndroid Build Coastguard Worker inner_layer = packet 197*2f2c4c7aSAndroid Build Coastguard Worker esp_nexthdr = {scapy.IPv6: IPPROTO_IPV6, 198*2f2c4c7aSAndroid Build Coastguard Worker scapy.IP: IPPROTO_IPIP}[type(packet)] 199*2f2c4c7aSAndroid Build Coastguard Worker else: 200*2f2c4c7aSAndroid Build Coastguard Worker new_ip_layer = None 201*2f2c4c7aSAndroid Build Coastguard Worker inner_layer = udp_layer 202*2f2c4c7aSAndroid Build Coastguard Worker esp_nexthdr = IPPROTO_UDP 203*2f2c4c7aSAndroid Build Coastguard Worker 204*2f2c4c7aSAndroid Build Coastguard Worker trailer = GetEspTrailer(len(inner_layer), esp_nexthdr) 205*2f2c4c7aSAndroid Build Coastguard Worker 206*2f2c4c7aSAndroid Build Coastguard Worker # Assemble the packet. 207*2f2c4c7aSAndroid Build Coastguard Worker esp_packet.payload = scapy.Raw(inner_layer) 208*2f2c4c7aSAndroid Build Coastguard Worker packet = new_ip_layer if new_ip_layer else packet 209*2f2c4c7aSAndroid Build Coastguard Worker packet.payload = scapy.Raw(bytes(esp_packet) + trailer) 210*2f2c4c7aSAndroid Build Coastguard Worker 211*2f2c4c7aSAndroid Build Coastguard Worker # TODO: Can we simplify this and avoid the initial copy()? 212*2f2c4c7aSAndroid Build Coastguard Worker # Fix the IPv4/IPv6 headers. 213*2f2c4c7aSAndroid Build Coastguard Worker if type(packet) is scapy.IPv6: 214*2f2c4c7aSAndroid Build Coastguard Worker packet.nh = IPPROTO_ESP 215*2f2c4c7aSAndroid Build Coastguard Worker # Recompute plen. 216*2f2c4c7aSAndroid Build Coastguard Worker packet.plen = None 217*2f2c4c7aSAndroid Build Coastguard Worker packet = scapy.IPv6(bytes(packet)) 218*2f2c4c7aSAndroid Build Coastguard Worker elif type(packet) is scapy.IP: 219*2f2c4c7aSAndroid Build Coastguard Worker packet.proto = IPPROTO_ESP 220*2f2c4c7aSAndroid Build Coastguard Worker # Recompute IPv4 len and checksum. 221*2f2c4c7aSAndroid Build Coastguard Worker packet.len = None 222*2f2c4c7aSAndroid Build Coastguard Worker packet.chksum = None 223*2f2c4c7aSAndroid Build Coastguard Worker packet = scapy.IP(bytes(packet)) 224*2f2c4c7aSAndroid Build Coastguard Worker else: 225*2f2c4c7aSAndroid Build Coastguard Worker raise ValueError("First layer in packet should be IPv4 or IPv6: " + repr(packet)) 226*2f2c4c7aSAndroid Build Coastguard Worker return packet 227*2f2c4c7aSAndroid Build Coastguard Worker 228*2f2c4c7aSAndroid Build Coastguard Worker 229*2f2c4c7aSAndroid Build Coastguard Workerdef DecryptPacketWithNull(packet): 230*2f2c4c7aSAndroid Build Coastguard Worker """Apply null decryption to a packet. 231*2f2c4c7aSAndroid Build Coastguard Worker 232*2f2c4c7aSAndroid Build Coastguard Worker This performs ESP decapsulation on the given packet. The input packet is 233*2f2c4c7aSAndroid Build Coastguard Worker assumed to be a UDP packet. This function will remove the ESP header and 234*2f2c4c7aSAndroid Build Coastguard Worker trailer bytes from an ESP packet. 235*2f2c4c7aSAndroid Build Coastguard Worker 236*2f2c4c7aSAndroid Build Coastguard Worker TODO: Support TCP 237*2f2c4c7aSAndroid Build Coastguard Worker 238*2f2c4c7aSAndroid Build Coastguard Worker Args: 239*2f2c4c7aSAndroid Build Coastguard Worker packet: a scapy.IPv6 or scapy.IP packet 240*2f2c4c7aSAndroid Build Coastguard Worker 241*2f2c4c7aSAndroid Build Coastguard Worker Returns: 242*2f2c4c7aSAndroid Build Coastguard Worker A tuple of decrypted packet (scapy.IPv6 or scapy.IP) and EspHdr 243*2f2c4c7aSAndroid Build Coastguard Worker """ 244*2f2c4c7aSAndroid Build Coastguard Worker esp_hdr, esp_data = cstruct.Read(bytes(packet.payload), xfrm.EspHdr) 245*2f2c4c7aSAndroid Build Coastguard Worker # Parse and strip ESP trailer. 246*2f2c4c7aSAndroid Build Coastguard Worker pad_len, esp_nexthdr = struct.unpack("BB", esp_data[-2:]) 247*2f2c4c7aSAndroid Build Coastguard Worker trailer_len = pad_len + 2 # Add the size of the pad_len and next_hdr fields. 248*2f2c4c7aSAndroid Build Coastguard Worker LayerType = { 249*2f2c4c7aSAndroid Build Coastguard Worker IPPROTO_IPIP: scapy.IP, 250*2f2c4c7aSAndroid Build Coastguard Worker IPPROTO_IPV6: scapy.IPv6, 251*2f2c4c7aSAndroid Build Coastguard Worker IPPROTO_UDP: scapy.UDP}[esp_nexthdr] 252*2f2c4c7aSAndroid Build Coastguard Worker next_layer = LayerType(esp_data[:-trailer_len]) 253*2f2c4c7aSAndroid Build Coastguard Worker if esp_nexthdr in [IPPROTO_IPIP, IPPROTO_IPV6]: 254*2f2c4c7aSAndroid Build Coastguard Worker # Tunnel mode decap is simple. Return the inner packet. 255*2f2c4c7aSAndroid Build Coastguard Worker return next_layer, esp_hdr 256*2f2c4c7aSAndroid Build Coastguard Worker 257*2f2c4c7aSAndroid Build Coastguard Worker # Cut out the ESP header. 258*2f2c4c7aSAndroid Build Coastguard Worker packet.payload = next_layer 259*2f2c4c7aSAndroid Build Coastguard Worker # Fix the IPv4/IPv6 headers. 260*2f2c4c7aSAndroid Build Coastguard Worker if type(packet) is scapy.IPv6: 261*2f2c4c7aSAndroid Build Coastguard Worker packet.nh = IPPROTO_UDP 262*2f2c4c7aSAndroid Build Coastguard Worker packet.plen = None # Recompute packet length. 263*2f2c4c7aSAndroid Build Coastguard Worker packet = scapy.IPv6(bytes(packet)) 264*2f2c4c7aSAndroid Build Coastguard Worker elif type(packet) is scapy.IP: 265*2f2c4c7aSAndroid Build Coastguard Worker packet.proto = IPPROTO_UDP 266*2f2c4c7aSAndroid Build Coastguard Worker packet.len = None # Recompute packet length. 267*2f2c4c7aSAndroid Build Coastguard Worker packet.chksum = None # Recompute IPv4 checksum. 268*2f2c4c7aSAndroid Build Coastguard Worker packet = scapy.IP(bytes(packet)) 269*2f2c4c7aSAndroid Build Coastguard Worker else: 270*2f2c4c7aSAndroid Build Coastguard Worker raise ValueError("First layer in packet should be IPv4 or IPv6: " + repr(packet)) 271*2f2c4c7aSAndroid Build Coastguard Worker return packet, esp_hdr 272*2f2c4c7aSAndroid Build Coastguard Worker 273*2f2c4c7aSAndroid Build Coastguard Worker 274*2f2c4c7aSAndroid Build Coastguard Workerclass XfrmBaseTest(multinetwork_base.MultiNetworkBaseTest): 275*2f2c4c7aSAndroid Build Coastguard Worker """Base test class for all XFRM-related testing.""" 276*2f2c4c7aSAndroid Build Coastguard Worker 277*2f2c4c7aSAndroid Build Coastguard Worker def _isIcmpv6(self, payload): 278*2f2c4c7aSAndroid Build Coastguard Worker if not isinstance(payload, scapy.IPv6): 279*2f2c4c7aSAndroid Build Coastguard Worker return False 280*2f2c4c7aSAndroid Build Coastguard Worker if payload.nh == IPPROTO_ICMPV6: 281*2f2c4c7aSAndroid Build Coastguard Worker return True 282*2f2c4c7aSAndroid Build Coastguard Worker return payload.nh == IPPROTO_HOPOPTS and payload.payload.nh == IPPROTO_ICMPV6 283*2f2c4c7aSAndroid Build Coastguard Worker 284*2f2c4c7aSAndroid Build Coastguard Worker def _ExpectEspPacketOn(self, netid, spi, seq, length, src_addr, dst_addr): 285*2f2c4c7aSAndroid Build Coastguard Worker """Read a packet from a netid and verify its properties. 286*2f2c4c7aSAndroid Build Coastguard Worker 287*2f2c4c7aSAndroid Build Coastguard Worker Args: 288*2f2c4c7aSAndroid Build Coastguard Worker netid: netid from which to read an ESP packet 289*2f2c4c7aSAndroid Build Coastguard Worker spi: SPI of the ESP packet in host byte order 290*2f2c4c7aSAndroid Build Coastguard Worker seq: sequence number of the ESP packet 291*2f2c4c7aSAndroid Build Coastguard Worker length: length of the packet's ESP payload or None to skip this check 292*2f2c4c7aSAndroid Build Coastguard Worker src_addr: source address of the packet or None to skip this check 293*2f2c4c7aSAndroid Build Coastguard Worker dst_addr: destination address of the packet or None to skip this check 294*2f2c4c7aSAndroid Build Coastguard Worker 295*2f2c4c7aSAndroid Build Coastguard Worker Returns: 296*2f2c4c7aSAndroid Build Coastguard Worker scapy.IP/IPv6: the read packet 297*2f2c4c7aSAndroid Build Coastguard Worker """ 298*2f2c4c7aSAndroid Build Coastguard Worker packets = [] 299*2f2c4c7aSAndroid Build Coastguard Worker for packet in self.ReadAllPacketsOn(netid): 300*2f2c4c7aSAndroid Build Coastguard Worker if not self._isIcmpv6(packet): 301*2f2c4c7aSAndroid Build Coastguard Worker packets.append(packet) 302*2f2c4c7aSAndroid Build Coastguard Worker 303*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(1, len(packets)) 304*2f2c4c7aSAndroid Build Coastguard Worker packet = packets[0] 305*2f2c4c7aSAndroid Build Coastguard Worker if length is not None: 306*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(length, len(packet.payload)) 307*2f2c4c7aSAndroid Build Coastguard Worker if dst_addr is not None: 308*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(dst_addr, packet.dst) 309*2f2c4c7aSAndroid Build Coastguard Worker if src_addr is not None: 310*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(src_addr, packet.src) 311*2f2c4c7aSAndroid Build Coastguard Worker # extract the ESP header 312*2f2c4c7aSAndroid Build Coastguard Worker esp_hdr, _ = cstruct.Read(bytes(packet.payload), xfrm.EspHdr) 313*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(xfrm.EspHdr((spi, seq)), esp_hdr) 314*2f2c4c7aSAndroid Build Coastguard Worker return packet 315*2f2c4c7aSAndroid Build Coastguard Worker 316*2f2c4c7aSAndroid Build Coastguard Worker 317*2f2c4c7aSAndroid Build Coastguard Worker# TODO: delete this when we're more diligent about deleting our SAs. 318*2f2c4c7aSAndroid Build Coastguard Workerclass XfrmLazyTest(XfrmBaseTest): 319*2f2c4c7aSAndroid Build Coastguard Worker """Base test class Xfrm tests that cleans XFRM state on teardown.""" 320*2f2c4c7aSAndroid Build Coastguard Worker def setUp(self): 321*2f2c4c7aSAndroid Build Coastguard Worker super(XfrmBaseTest, self).setUp() 322*2f2c4c7aSAndroid Build Coastguard Worker self.xfrm = xfrm.Xfrm() 323*2f2c4c7aSAndroid Build Coastguard Worker self.xfrm.FlushSaInfo() 324*2f2c4c7aSAndroid Build Coastguard Worker self.xfrm.FlushPolicyInfo() 325*2f2c4c7aSAndroid Build Coastguard Worker 326*2f2c4c7aSAndroid Build Coastguard Worker def tearDown(self): 327*2f2c4c7aSAndroid Build Coastguard Worker super(XfrmBaseTest, self).tearDown() 328*2f2c4c7aSAndroid Build Coastguard Worker self.xfrm.FlushSaInfo() 329*2f2c4c7aSAndroid Build Coastguard Worker self.xfrm.FlushPolicyInfo() 330*2f2c4c7aSAndroid Build Coastguard Worker self.xfrm.close() 331