xref: /aosp_15_r20/kernel/tests/net/test/xfrm_base.py (revision 2f2c4c7ab4226c71756b9c31670392fdd6887c4f)
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