1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.net.ipsec.ike.message;
18 
19 import android.annotation.IntDef;
20 import android.net.LinkAddress;
21 import android.net.ipsec.ike.IkeManager;
22 import android.net.ipsec.ike.IkeSessionParams;
23 import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv4PcscfServer;
24 import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv6PcscfServer;
25 import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest;
26 import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Address;
27 import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer;
28 import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer;
29 import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netmask;
30 import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address;
31 import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer;
32 import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest;
33 
34 import com.android.internal.annotations.VisibleForTesting;
35 import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException;
36 
37 import java.lang.annotation.Retention;
38 import java.lang.annotation.RetentionPolicy;
39 import java.net.Inet4Address;
40 import java.net.Inet6Address;
41 import java.net.InetAddress;
42 import java.net.UnknownHostException;
43 import java.nio.ByteBuffer;
44 import java.nio.charset.Charset;
45 import java.nio.charset.StandardCharsets;
46 import java.util.LinkedList;
47 import java.util.List;
48 
49 /**
50  * This class represents Configuration payload.
51  *
52  * <p>Configuration payload is used to exchange configuration information between IKE peers.
53  *
54  * <p>Configuration type should be consistent with the IKE message direction (e.g. a request Config
55  * Payload should be in a request IKE message). IKE library will ignore Config Payload with
56  * inconsistent type or with unrecognized type.
57  *
58  * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.6">RFC 7296, Internet Key Exchange
59  *     Protocol Version 2 (IKEv2)</a>
60  */
61 public final class IkeConfigPayload extends IkePayload {
62     private static final int CONFIG_HEADER_RESERVED_LEN = 3;
63     private static final int CONFIG_HEADER_LEN = 4;
64 
65     @Retention(RetentionPolicy.SOURCE)
66     @IntDef({
67         CONFIG_ATTR_INTERNAL_IP4_ADDRESS,
68         CONFIG_ATTR_INTERNAL_IP4_NETMASK,
69         CONFIG_ATTR_INTERNAL_IP4_DNS,
70         CONFIG_ATTR_INTERNAL_IP4_DHCP,
71         CONFIG_ATTR_APPLICATION_VERSION,
72         CONFIG_ATTR_INTERNAL_IP6_ADDRESS,
73         CONFIG_ATTR_INTERNAL_IP6_DNS,
74         CONFIG_ATTR_INTERNAL_IP4_SUBNET,
75         CONFIG_ATTR_SUPPORTED_ATTRIBUTES,
76         CONFIG_ATTR_INTERNAL_IP6_SUBNET,
77         CONFIG_ATTR_IP4_PCSCF,
78         CONFIG_ATTR_IP6_PCSCF
79     })
80     public @interface ConfigAttr {}
81 
82     public static final int CONFIG_ATTR_INTERNAL_IP4_ADDRESS = 1;
83     public static final int CONFIG_ATTR_INTERNAL_IP4_NETMASK = 2;
84     public static final int CONFIG_ATTR_INTERNAL_IP4_DNS = 3;
85     public static final int CONFIG_ATTR_INTERNAL_IP4_DHCP = 6;
86     public static final int CONFIG_ATTR_APPLICATION_VERSION = 7;
87     public static final int CONFIG_ATTR_INTERNAL_IP6_ADDRESS = 8;
88     public static final int CONFIG_ATTR_INTERNAL_IP6_DNS = 10;
89     public static final int CONFIG_ATTR_INTERNAL_IP4_SUBNET = 13;
90     public static final int CONFIG_ATTR_SUPPORTED_ATTRIBUTES = 14;
91     public static final int CONFIG_ATTR_INTERNAL_IP6_SUBNET = 15;
92     public static final int CONFIG_ATTR_IP4_PCSCF = 20;
93     public static final int CONFIG_ATTR_IP6_PCSCF = 21;
94 
95     @Retention(RetentionPolicy.SOURCE)
96     @IntDef({CONFIG_TYPE_REQUEST, CONFIG_TYPE_REPLY})
97     public @interface ConfigType {}
98 
99     // We don't support CONFIG_TYPE_SET and CONFIG_TYPE_ACK
100     public static final int CONFIG_TYPE_REQUEST = 1;
101     public static final int CONFIG_TYPE_REPLY = 2;
102 
103     @ConfigType public final int configType;
104     public final List<ConfigAttribute> recognizedAttributeList;
105 
106     /** Build an IkeConfigPayload from a decoded inbound IKE packet. */
IkeConfigPayload(boolean critical, byte[] payloadBody)107     IkeConfigPayload(boolean critical, byte[] payloadBody) throws InvalidSyntaxException {
108         super(PAYLOAD_TYPE_CP, critical);
109 
110         ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody);
111         configType = Byte.toUnsignedInt(inputBuffer.get());
112         inputBuffer.get(new byte[CONFIG_HEADER_RESERVED_LEN]);
113 
114         recognizedAttributeList = ConfigAttribute.decodeAttributeFrom(inputBuffer);
115 
116         // For an inbound Config Payload, IKE library is only able to handle a Config Reply or IKE
117         // Session attribute requests in a Config Request. For interoperability, netmask validation
118         // will be skipped for Config(Request) and config payloads with unsupported config types.
119         if (configType == CONFIG_TYPE_REPLY) {
120             validateNetmaskInReply();
121         }
122     }
123 
124     /** Build an IkeConfigPayload instance for an outbound IKE packet. */
IkeConfigPayload(boolean isReply, List<ConfigAttribute> attributeList)125     public IkeConfigPayload(boolean isReply, List<ConfigAttribute> attributeList) {
126         super(PAYLOAD_TYPE_CP, false);
127         this.configType = isReply ? CONFIG_TYPE_REPLY : CONFIG_TYPE_REQUEST;
128         this.recognizedAttributeList = attributeList;
129     }
130 
validateNetmaskInReply()131     private void validateNetmaskInReply() throws InvalidSyntaxException {
132         boolean hasIpv4Address = false;
133         int numNetmask = 0;
134 
135         for (ConfigAttribute attr : recognizedAttributeList) {
136             if (attr.isEmptyValue()) {
137                 IkeManager.getIkeLog()
138                         .d(
139                                 "IkeConfigPayload",
140                                 "Found empty attribute in a Config Payload reply "
141                                         + attr.attributeType);
142             }
143             switch (attr.attributeType) {
144                 case CONFIG_ATTR_INTERNAL_IP4_ADDRESS:
145                     if (!attr.isEmptyValue()) hasIpv4Address = true;
146                     break;
147                 case CONFIG_ATTR_INTERNAL_IP4_NETMASK:
148                     if (!attr.isEmptyValue()) numNetmask++;
149                     break;
150                 default:
151                     continue;
152             }
153         }
154 
155         if (!hasIpv4Address && numNetmask > 0) {
156             throw new InvalidSyntaxException(
157                     "Found INTERNAL_IP4_NETMASK attribute but no INTERNAL_IP4_ADDRESS attribute");
158         }
159 
160         if (numNetmask > 1) {
161             throw new InvalidSyntaxException("Found more than one INTERNAL_IP4_NETMASK");
162         }
163     }
164 
165     // TODO: Create ConfigAttribute subclasses for each attribute.
166 
167     /** This class represents common information of all Configuration Attributes. */
168     public abstract static class ConfigAttribute {
169         private static final int ATTRIBUTE_TYPE_MASK = 0x7fff;
170 
171         private static final int ATTRIBUTE_HEADER_LEN = 4;
172         private static final int IPV4_PREFIX_LEN_MAX = 32;
173 
174         protected static final int VALUE_LEN_NOT_INCLUDED = 0;
175 
176         protected static final int IPV4_ADDRESS_LEN = 4;
177         protected static final int IPV6_ADDRESS_LEN = 16;
178         protected static final int PREFIX_LEN_LEN = 1;
179 
180         public final int attributeType;
181 
ConfigAttribute(int attributeType)182         protected ConfigAttribute(int attributeType) {
183             this.attributeType = attributeType;
184         }
185 
ConfigAttribute(int attributeType, int len)186         protected ConfigAttribute(int attributeType, int len) throws InvalidSyntaxException {
187             this(attributeType);
188 
189             if (!isLengthValid(len)) {
190                 throw new InvalidSyntaxException("Invalid configuration length");
191             }
192         }
193 
194         /**
195          * Package private method to decode ConfigAttribute list from an inbound packet
196          *
197          * <p>NegativeArraySizeException and BufferUnderflowException will be caught in {@link
198          * IkeMessage}
199          */
decodeAttributeFrom(ByteBuffer inputBuffer)200         static List<ConfigAttribute> decodeAttributeFrom(ByteBuffer inputBuffer)
201                 throws InvalidSyntaxException {
202             List<ConfigAttribute> configList = new LinkedList();
203 
204             while (inputBuffer.hasRemaining()) {
205                 int attributeType = Short.toUnsignedInt(inputBuffer.getShort());
206                 int length = Short.toUnsignedInt(inputBuffer.getShort());
207                 byte[] value = new byte[length];
208                 inputBuffer.get(value);
209 
210                 switch (attributeType) {
211                     case CONFIG_ATTR_INTERNAL_IP4_ADDRESS:
212                         configList.add(new ConfigAttributeIpv4Address(value));
213                         break;
214                     case CONFIG_ATTR_INTERNAL_IP4_NETMASK:
215                         configList.add(new ConfigAttributeIpv4Netmask(value));
216                         break;
217                     case CONFIG_ATTR_INTERNAL_IP4_DNS:
218                         configList.add(new ConfigAttributeIpv4Dns(value));
219                         break;
220                     case CONFIG_ATTR_INTERNAL_IP4_DHCP:
221                         configList.add(new ConfigAttributeIpv4Dhcp(value));
222                         break;
223                     case CONFIG_ATTR_APPLICATION_VERSION:
224                         configList.add(new ConfigAttributeAppVersion(value));
225                         break;
226                     case CONFIG_ATTR_INTERNAL_IP6_ADDRESS:
227                         configList.add(new ConfigAttributeIpv6Address(value));
228                         break;
229                     case CONFIG_ATTR_INTERNAL_IP6_DNS:
230                         configList.add(new ConfigAttributeIpv6Dns(value));
231                         break;
232                     case CONFIG_ATTR_INTERNAL_IP4_SUBNET:
233                         configList.add(new ConfigAttributeIpv4Subnet(value));
234                         break;
235                     case CONFIG_ATTR_INTERNAL_IP6_SUBNET:
236                         configList.add(new ConfigAttributeIpv6Subnet(value));
237                         break;
238                     case CONFIG_ATTR_IP4_PCSCF:
239                         configList.add(new ConfigAttributeIpv4Pcscf(value));
240                         break;
241                     case CONFIG_ATTR_IP6_PCSCF:
242                         configList.add(new ConfigAttributeIpv6Pcscf(value));
243                         break;
244                     default:
245                         IkeManager.getIkeLog()
246                                 .i(
247                                         "IkeConfigPayload",
248                                         "Unrecognized attribute type: " + attributeType);
249                 }
250 
251                 // TODO: Support App version and supported attribute list
252             }
253 
254             return configList;
255         }
256 
257         /** Encode attribute to ByteBuffer. */
encodeAttributeToByteBuffer(ByteBuffer buffer)258         public void encodeAttributeToByteBuffer(ByteBuffer buffer) {
259             buffer.putShort((short) (attributeType & ATTRIBUTE_TYPE_MASK))
260                     .putShort((short) getValueLength());
261             encodeValueToByteBuffer(buffer);
262         }
263 
264         /** Get attribute length. */
getAttributeLen()265         public int getAttributeLen() {
266             return ATTRIBUTE_HEADER_LEN + getValueLength();
267         }
268 
269         /** Returns if this attribute value is empty. */
isEmptyValue()270         public boolean isEmptyValue() {
271             return getValueLength() == VALUE_LEN_NOT_INCLUDED;
272         }
273 
netmaskToPrefixLen(Inet4Address address)274         protected static int netmaskToPrefixLen(Inet4Address address) {
275             byte[] bytes = address.getAddress();
276 
277             int netmaskInt = ByteBuffer.wrap(bytes).getInt();
278             int leftmostBitMask = 0x80000000;
279 
280             int prefixLen = 0;
281             while ((netmaskInt & leftmostBitMask) == leftmostBitMask) {
282                 prefixLen++;
283                 netmaskInt <<= 1;
284             }
285 
286             if (netmaskInt != 0) {
287                 throw new IllegalArgumentException("Invalid netmask address");
288             }
289 
290             return prefixLen;
291         }
292 
prefixToNetmaskBytes(int prefixLen)293         protected static byte[] prefixToNetmaskBytes(int prefixLen) {
294             if (prefixLen > IPV4_PREFIX_LEN_MAX || prefixLen < 0) {
295                 throw new IllegalArgumentException("Invalid IPv4 prefix length.");
296             }
297 
298             int netmaskInt = (int) (((long) 0xffffffff) << (IPV4_PREFIX_LEN_MAX - prefixLen));
299             byte[] netmask = new byte[IPV4_ADDRESS_LEN];
300 
301             ByteBuffer buffer = ByteBuffer.allocate(IPV4_ADDRESS_LEN);
302             buffer.putInt(netmaskInt);
303             return buffer.array();
304         }
305 
encodeValueToByteBuffer(ByteBuffer buffer)306         protected abstract void encodeValueToByteBuffer(ByteBuffer buffer);
307 
getValueLength()308         protected abstract int getValueLength();
309 
isLengthValid(int length)310         protected abstract boolean isLengthValid(int length);
311     }
312 
313     /** This class supports strong typing for IkeConfigRequest(s) */
314     public abstract static class IkeConfigAttribute extends ConfigAttribute
315             implements IkeConfigRequest {
IkeConfigAttribute(int attributeType)316         protected IkeConfigAttribute(int attributeType) {
317             super(attributeType);
318         }
319 
IkeConfigAttribute(int attributeType, int len)320         protected IkeConfigAttribute(int attributeType, int len) throws InvalidSyntaxException {
321             super(attributeType, len);
322         }
323     }
324 
325     /** This class supports strong typing for TunnelModeChildConfigRequest(s) */
326     public abstract static class TunnelModeChildConfigAttribute extends ConfigAttribute
327             implements TunnelModeChildConfigRequest {
TunnelModeChildConfigAttribute(int attributeType)328         protected TunnelModeChildConfigAttribute(int attributeType) {
329             super(attributeType);
330         }
331 
TunnelModeChildConfigAttribute(int attributeType, int len)332         protected TunnelModeChildConfigAttribute(int attributeType, int len)
333                 throws InvalidSyntaxException {
334             super(attributeType, len);
335         }
336     }
337 
338     /**
339      * This class represents common information of all Tunnel Mode Child Session Configuration
340      * Attributes for which the value is one IPv4 address or empty.
341      */
342     abstract static class TunnelModeChildConfigAttrIpv4AddressBase
343             extends TunnelModeChildConfigAttribute implements TunnelModeChildConfigRequest {
344         public final Inet4Address address;
345 
TunnelModeChildConfigAttrIpv4AddressBase( int attributeType, Inet4Address address)346         protected TunnelModeChildConfigAttrIpv4AddressBase(
347                 int attributeType, Inet4Address address) {
348             super(attributeType);
349             this.address = address;
350         }
351 
TunnelModeChildConfigAttrIpv4AddressBase(int attributeType)352         protected TunnelModeChildConfigAttrIpv4AddressBase(int attributeType) {
353             super(attributeType);
354             this.address = null;
355         }
356 
TunnelModeChildConfigAttrIpv4AddressBase(int attributeType, byte[] value)357         protected TunnelModeChildConfigAttrIpv4AddressBase(int attributeType, byte[] value)
358                 throws InvalidSyntaxException {
359             super(attributeType, value.length);
360 
361             if (value.length == VALUE_LEN_NOT_INCLUDED) {
362                 address = null;
363                 return;
364             }
365 
366             try {
367                 InetAddress netAddress = InetAddress.getByAddress(value);
368 
369                 if (!(netAddress instanceof Inet4Address)) {
370                     throw new InvalidSyntaxException("Invalid IPv4 address.");
371                 }
372                 address = (Inet4Address) netAddress;
373             } catch (UnknownHostException e) {
374                 throw new InvalidSyntaxException("Invalid attribute value", e);
375             }
376         }
377 
378         @Override
encodeValueToByteBuffer(ByteBuffer buffer)379         protected void encodeValueToByteBuffer(ByteBuffer buffer) {
380             if (address == null) return; // No encoding necessary
381 
382             buffer.put(address.getAddress());
383         }
384 
385         @Override
getValueLength()386         protected int getValueLength() {
387             return address == null ? 0 : IPV4_ADDRESS_LEN;
388         }
389 
390         @Override
isLengthValid(int length)391         protected boolean isLengthValid(int length) {
392             return length == IPV4_ADDRESS_LEN || length == VALUE_LEN_NOT_INCLUDED;
393         }
394     }
395 
396     /**
397      * This class represents common information of all IKE Session Configuration Attributes for
398      * which the value is one IPv4 address or empty.
399      */
400     abstract static class IkeConfigAttrIpv4AddressBase extends IkeConfigAttribute
401             implements IkeSessionParams.IkeConfigRequest {
402         public final Inet4Address address;
403 
IkeConfigAttrIpv4AddressBase(int attributeType, Inet4Address address)404         protected IkeConfigAttrIpv4AddressBase(int attributeType, Inet4Address address) {
405             super(attributeType);
406             this.address = address;
407         }
408 
IkeConfigAttrIpv4AddressBase(int attributeType)409         protected IkeConfigAttrIpv4AddressBase(int attributeType) {
410             super(attributeType);
411             this.address = null;
412         }
413 
IkeConfigAttrIpv4AddressBase(int attributeType, byte[] value)414         protected IkeConfigAttrIpv4AddressBase(int attributeType, byte[] value)
415                 throws InvalidSyntaxException {
416             super(attributeType, value.length);
417 
418             if (value.length == VALUE_LEN_NOT_INCLUDED) {
419                 address = null;
420                 return;
421             }
422 
423             try {
424                 InetAddress netAddress = InetAddress.getByAddress(value);
425 
426                 if (!(netAddress instanceof Inet4Address)) {
427                     throw new InvalidSyntaxException("Invalid IPv4 address.");
428                 }
429                 address = (Inet4Address) netAddress;
430             } catch (UnknownHostException e) {
431                 throw new InvalidSyntaxException("Invalid attribute value", e);
432             }
433         }
434 
435         @Override
encodeValueToByteBuffer(ByteBuffer buffer)436         protected void encodeValueToByteBuffer(ByteBuffer buffer) {
437             if (address == null) return; // No encoding necessary
438 
439             buffer.put(address.getAddress());
440         }
441 
442         @Override
getValueLength()443         protected int getValueLength() {
444             return address == null ? 0 : IPV4_ADDRESS_LEN;
445         }
446 
447         @Override
isLengthValid(int length)448         protected boolean isLengthValid(int length) {
449             return length == IPV4_ADDRESS_LEN || length == VALUE_LEN_NOT_INCLUDED;
450         }
451     }
452 
453     /** This class represents Configuration Attribute for IPv4 internal address. */
454     public static class ConfigAttributeIpv4Address extends TunnelModeChildConfigAttrIpv4AddressBase
455             implements ConfigRequestIpv4Address {
456         /** Construct an instance with specified address for an outbound packet. */
ConfigAttributeIpv4Address(Inet4Address ipv4Address)457         public ConfigAttributeIpv4Address(Inet4Address ipv4Address) {
458             super(CONFIG_ATTR_INTERNAL_IP4_ADDRESS, ipv4Address);
459         }
460 
461         /**
462          * Construct an instance without a specified address for an outbound packet.
463          *
464          * <p>It must be only used in a configuration request.
465          */
ConfigAttributeIpv4Address()466         public ConfigAttributeIpv4Address() {
467             super(CONFIG_ATTR_INTERNAL_IP4_ADDRESS);
468         }
469 
470         /** Construct an instance with a decoded inbound packet. */
471         @VisibleForTesting
ConfigAttributeIpv4Address(byte[] value)472         ConfigAttributeIpv4Address(byte[] value) throws InvalidSyntaxException {
473             super(CONFIG_ATTR_INTERNAL_IP4_ADDRESS, value);
474         }
475 
476         @Override
getAddress()477         public Inet4Address getAddress() {
478             return address;
479         }
480     }
481 
482     /**
483      * This class represents Configuration Attribute for IPv4 netmask.
484      *
485      * <p>Non-empty values for this attribute in a CFG_REQUEST do not make sense and thus MUST NOT
486      * be included
487      */
488     public static class ConfigAttributeIpv4Netmask extends TunnelModeChildConfigAttrIpv4AddressBase
489             implements ConfigRequestIpv4Netmask {
490         /**
491          * Construct an instance without a specified netmask for an outbound packet.
492          *
493          * <p>It must be only used in a configuration request.
494          */
ConfigAttributeIpv4Netmask()495         public ConfigAttributeIpv4Netmask() {
496             super(CONFIG_ATTR_INTERNAL_IP4_NETMASK);
497         }
498 
499         /** Construct an instance with a decoded inbound packet. */
500         @VisibleForTesting
ConfigAttributeIpv4Netmask(byte[] value)501         public ConfigAttributeIpv4Netmask(byte[] value) throws InvalidSyntaxException {
502             super(CONFIG_ATTR_INTERNAL_IP4_NETMASK, value);
503 
504             if (address == null) return;
505             try {
506                 netmaskToPrefixLen(address);
507             } catch (IllegalArgumentException e) {
508                 throw new InvalidSyntaxException("Invalid attribute value", e);
509             }
510         }
511 
512         /** Convert netmask to prefix length. */
getPrefixLen()513         public int getPrefixLen() {
514             return netmaskToPrefixLen(address);
515         }
516     }
517 
518     /** This class represents Configuration Attribute for IPv4 DHCP server. */
519     public static class ConfigAttributeIpv4Dhcp extends TunnelModeChildConfigAttrIpv4AddressBase
520             implements ConfigRequestIpv4DhcpServer {
521         /** Construct an instance with specified DHCP server address for an outbound packet. */
ConfigAttributeIpv4Dhcp(Inet4Address ipv4Address)522         public ConfigAttributeIpv4Dhcp(Inet4Address ipv4Address) {
523             super(CONFIG_ATTR_INTERNAL_IP4_DHCP, ipv4Address);
524         }
525 
526         /**
527          * Construct an instance without a specified DHCP server address for an outbound packet.
528          *
529          * <p>It must be only used in a configuration request.
530          */
ConfigAttributeIpv4Dhcp()531         public ConfigAttributeIpv4Dhcp() {
532             super(CONFIG_ATTR_INTERNAL_IP4_DHCP);
533         }
534 
535         /** Construct an instance with a decoded inbound packet. */
536         @VisibleForTesting
ConfigAttributeIpv4Dhcp(byte[] value)537         ConfigAttributeIpv4Dhcp(byte[] value) throws InvalidSyntaxException {
538             super(CONFIG_ATTR_INTERNAL_IP4_DHCP, value);
539         }
540 
getAddress()541         public Inet4Address getAddress() {
542             return address;
543         }
544     }
545 
546     /**
547      * This class represents Configuration Attribute for IPv4 DNS.
548      *
549      * <p>There is no use case to create a DNS request for a specfic DNS server address. As an IKE
550      * client, we will only support building an empty DNS attribute for an outbound IKE packet.
551      */
552     public static class ConfigAttributeIpv4Dns extends TunnelModeChildConfigAttrIpv4AddressBase
553             implements ConfigRequestIpv4DnsServer {
554         /** Construct an instance with specified DNS server address for an outbound packet. */
ConfigAttributeIpv4Dns(Inet4Address ipv4Address)555         public ConfigAttributeIpv4Dns(Inet4Address ipv4Address) {
556             super(CONFIG_ATTR_INTERNAL_IP4_DNS, ipv4Address);
557         }
558 
559         /**
560          * Construct an instance without a specified DNS server address for an outbound packet.
561          *
562          * <p>It must be only used in a configuration request.
563          */
ConfigAttributeIpv4Dns()564         public ConfigAttributeIpv4Dns() {
565             super(CONFIG_ATTR_INTERNAL_IP4_DNS);
566         }
567 
568         /** Construct an instance with a decoded inbound packet. */
569         @VisibleForTesting
ConfigAttributeIpv4Dns(byte[] value)570         ConfigAttributeIpv4Dns(byte[] value) throws InvalidSyntaxException {
571             super(CONFIG_ATTR_INTERNAL_IP4_DNS, value);
572         }
573 
getAddress()574         public Inet4Address getAddress() {
575             return address;
576         }
577     }
578 
579     // TODO: b/145454043 Remove constructors for building outbound
580     // INTERNAL_IP4_SUBNET/INTERNAL_IP6_SUBNET because they should never be in a config request and
581     // IKE library, as an IKE client, will never send them in a config reply either.
582 
583     /**
584      * This class represents Configuration Attribute for IPv4 subnets.
585      *
586      * <p>According to RFC 7296, INTERNAL_IP4_SUBNET in configuration requests cannot be used
587      * reliably because the meaning is unclear.
588      */
589     public static class ConfigAttributeIpv4Subnet extends TunnelModeChildConfigAttribute {
590         private static final int VALUE_LEN = 2 * IPV4_ADDRESS_LEN;
591 
592         public final LinkAddress linkAddress;
593 
594         /** Construct an instance with specified subnet for an outbound packet. */
ConfigAttributeIpv4Subnet(LinkAddress ipv4LinkAddress)595         public ConfigAttributeIpv4Subnet(LinkAddress ipv4LinkAddress) {
596             super(CONFIG_ATTR_INTERNAL_IP4_SUBNET);
597 
598             if (!ipv4LinkAddress.isIpv4()) {
599                 throw new IllegalArgumentException("Input LinkAddress is not IPv4");
600             }
601 
602             this.linkAddress = ipv4LinkAddress;
603         }
604 
605         /**
606          * Construct an instance without a specified subnet for an outbound packet.
607          *
608          * <p>It must be only used in a configuration request.
609          */
ConfigAttributeIpv4Subnet()610         public ConfigAttributeIpv4Subnet() {
611             super(CONFIG_ATTR_INTERNAL_IP4_SUBNET);
612             this.linkAddress = null;
613         }
614 
615         /** Construct an instance with a decoded inbound packet. */
616         @VisibleForTesting
ConfigAttributeIpv4Subnet(byte[] value)617         ConfigAttributeIpv4Subnet(byte[] value) throws InvalidSyntaxException {
618             super(CONFIG_ATTR_INTERNAL_IP4_SUBNET, value.length);
619 
620             if (value.length == VALUE_LEN_NOT_INCLUDED) {
621                 linkAddress = null;
622                 return;
623             }
624 
625             try {
626                 ByteBuffer inputBuffer = ByteBuffer.wrap(value);
627                 byte[] ipBytes = new byte[IPV4_ADDRESS_LEN];
628                 inputBuffer.get(ipBytes);
629                 byte[] netmaskBytes = new byte[IPV4_ADDRESS_LEN];
630                 inputBuffer.get(netmaskBytes);
631 
632                 InetAddress address = InetAddress.getByAddress(ipBytes);
633                 InetAddress netmask = InetAddress.getByAddress(netmaskBytes);
634                 validateInet4AddressTypeOrThrow(address);
635                 validateInet4AddressTypeOrThrow(netmask);
636 
637                 linkAddress = new LinkAddress(address, netmaskToPrefixLen((Inet4Address) netmask));
638             } catch (UnknownHostException | IllegalArgumentException e) {
639                 throw new InvalidSyntaxException("Invalid attribute value", e);
640             }
641         }
642 
validateInet4AddressTypeOrThrow(InetAddress address)643         private void validateInet4AddressTypeOrThrow(InetAddress address) {
644             if (!(address instanceof Inet4Address)) {
645                 throw new IllegalArgumentException("Input InetAddress is not IPv4");
646             }
647         }
648 
649         @Override
encodeValueToByteBuffer(ByteBuffer buffer)650         protected void encodeValueToByteBuffer(ByteBuffer buffer) {
651             if (linkAddress == null) {
652                 buffer.put(new byte[VALUE_LEN_NOT_INCLUDED]);
653                 return;
654             }
655             byte[] netmaskBytes = prefixToNetmaskBytes(linkAddress.getPrefixLength());
656             buffer.put(linkAddress.getAddress().getAddress()).put(netmaskBytes);
657         }
658 
659         @Override
getValueLength()660         protected int getValueLength() {
661             return linkAddress == null ? 0 : VALUE_LEN;
662         }
663 
664         @Override
isLengthValid(int length)665         protected boolean isLengthValid(int length) {
666             return length == VALUE_LEN || length == VALUE_LEN_NOT_INCLUDED;
667         }
668     }
669 
670     /** This class represents an IPv4 P_CSCF address attribute */
671     public static class ConfigAttributeIpv4Pcscf extends IkeConfigAttrIpv4AddressBase
672             implements ConfigRequestIpv4PcscfServer {
673         /** Construct an instance with a specified P_CSCF server address for an outbound packet. */
ConfigAttributeIpv4Pcscf(Inet4Address ipv4Address)674         public ConfigAttributeIpv4Pcscf(Inet4Address ipv4Address) {
675             super(CONFIG_ATTR_IP4_PCSCF, ipv4Address);
676         }
677 
678         /**
679          * Construct an instance without a specified P_CSCF server address for an outbound packet.
680          *
681          * <p>It must be only used in a configuration request.
682          */
ConfigAttributeIpv4Pcscf()683         public ConfigAttributeIpv4Pcscf() {
684             super(CONFIG_ATTR_IP4_PCSCF);
685         }
686 
687         /** Construct an instance with a decoded inbound packet. */
688         @VisibleForTesting
ConfigAttributeIpv4Pcscf(byte[] value)689         ConfigAttributeIpv4Pcscf(byte[] value) throws InvalidSyntaxException {
690             super(CONFIG_ATTR_IP4_PCSCF, value);
691         }
692 
693         @Override
getAddress()694         public Inet4Address getAddress() {
695             return address;
696         }
697     }
698 
699     /**
700      * This class represents common information of all Tunnel Mode Child Session Configuration
701      * Attributes for which the value is one IPv6 address or empty.
702      */
703     abstract static class TunnelModeChildConfigAttrIpv6AddressBase
704             extends TunnelModeChildConfigAttribute implements TunnelModeChildConfigRequest {
705         public final Inet6Address address;
706 
TunnelModeChildConfigAttrIpv6AddressBase( int attributeType, Inet6Address address)707         protected TunnelModeChildConfigAttrIpv6AddressBase(
708                 int attributeType, Inet6Address address) {
709             super(attributeType);
710             this.address = address;
711         }
712 
TunnelModeChildConfigAttrIpv6AddressBase(int attributeType)713         protected TunnelModeChildConfigAttrIpv6AddressBase(int attributeType) {
714             super(attributeType);
715             this.address = null;
716         }
717 
TunnelModeChildConfigAttrIpv6AddressBase(int attributeType, byte[] value)718         protected TunnelModeChildConfigAttrIpv6AddressBase(int attributeType, byte[] value)
719                 throws InvalidSyntaxException {
720             super(attributeType, value.length);
721 
722             if (value.length == VALUE_LEN_NOT_INCLUDED) {
723                 address = null;
724                 return;
725             }
726 
727             try {
728                 InetAddress netAddress = InetAddress.getByAddress(value);
729 
730                 if (!(netAddress instanceof Inet6Address)) {
731                     throw new InvalidSyntaxException("Invalid IPv6 address.");
732                 }
733                 address = (Inet6Address) netAddress;
734             } catch (UnknownHostException e) {
735                 throw new InvalidSyntaxException("Invalid attribute value", e);
736             }
737         }
738 
739         @Override
encodeValueToByteBuffer(ByteBuffer buffer)740         protected void encodeValueToByteBuffer(ByteBuffer buffer) {
741             if (address == null) return; // No encoding necessary
742 
743             buffer.put(address.getAddress());
744         }
745 
746         @Override
getValueLength()747         protected int getValueLength() {
748             return address == null ? 0 : IPV6_ADDRESS_LEN;
749         }
750 
751         @Override
isLengthValid(int length)752         protected boolean isLengthValid(int length) {
753             return length == IPV6_ADDRESS_LEN || length == VALUE_LEN_NOT_INCLUDED;
754         }
755     }
756 
757     /**
758      * This class represents common information of all IKE Session Configuration Attributes for
759      * which the value is one IPv6 address or empty.
760      */
761     abstract static class IkeConfigAttrIpv6AddressBase extends IkeConfigAttribute
762             implements IkeConfigRequest {
763         public final Inet6Address address;
764 
IkeConfigAttrIpv6AddressBase(int attributeType, Inet6Address address)765         protected IkeConfigAttrIpv6AddressBase(int attributeType, Inet6Address address) {
766             super(attributeType);
767             this.address = address;
768         }
769 
IkeConfigAttrIpv6AddressBase(int attributeType)770         protected IkeConfigAttrIpv6AddressBase(int attributeType) {
771             super(attributeType);
772             this.address = null;
773         }
774 
IkeConfigAttrIpv6AddressBase(int attributeType, byte[] value)775         protected IkeConfigAttrIpv6AddressBase(int attributeType, byte[] value)
776                 throws InvalidSyntaxException {
777             super(attributeType, value.length);
778 
779             if (value.length == VALUE_LEN_NOT_INCLUDED) {
780                 address = null;
781                 return;
782             }
783 
784             try {
785                 InetAddress netAddress = InetAddress.getByAddress(value);
786 
787                 if (!(netAddress instanceof Inet6Address)) {
788                     throw new InvalidSyntaxException("Invalid IPv6 address.");
789                 }
790                 address = (Inet6Address) netAddress;
791             } catch (UnknownHostException e) {
792                 throw new InvalidSyntaxException("Invalid attribute value", e);
793             }
794         }
795 
796         @Override
encodeValueToByteBuffer(ByteBuffer buffer)797         protected void encodeValueToByteBuffer(ByteBuffer buffer) {
798             if (address == null) return; // No encoding necessary
799 
800             buffer.put(address.getAddress());
801         }
802 
803         @Override
getValueLength()804         protected int getValueLength() {
805             return address == null ? 0 : IPV6_ADDRESS_LEN;
806         }
807 
808         @Override
isLengthValid(int length)809         protected boolean isLengthValid(int length) {
810             return length == IPV6_ADDRESS_LEN || length == VALUE_LEN_NOT_INCLUDED;
811         }
812     }
813 
814     /**
815      * This class represents common information of all Configuration Attributes for which the value
816      * is an IPv6 address range.
817      *
818      * <p>These attributes contains an IPv6 address and a prefix length.
819      */
820     abstract static class TunnelModeChildConfigAttrIpv6AddrRangeBase
821             extends TunnelModeChildConfigAttribute {
822         private static final int VALUE_LEN = IPV6_ADDRESS_LEN + PREFIX_LEN_LEN;
823 
824         public final LinkAddress linkAddress;
825 
TunnelModeChildConfigAttrIpv6AddrRangeBase( int attributeType, LinkAddress ipv6LinkAddress)826         protected TunnelModeChildConfigAttrIpv6AddrRangeBase(
827                 int attributeType, LinkAddress ipv6LinkAddress) {
828             super(attributeType);
829 
830             validateIpv6LinkAddressTypeOrThrow(ipv6LinkAddress);
831             linkAddress = ipv6LinkAddress;
832         }
833 
TunnelModeChildConfigAttrIpv6AddrRangeBase(int attributeType)834         protected TunnelModeChildConfigAttrIpv6AddrRangeBase(int attributeType) {
835             super(attributeType);
836             linkAddress = null;
837         }
838 
TunnelModeChildConfigAttrIpv6AddrRangeBase(int attributeType, byte[] value)839         protected TunnelModeChildConfigAttrIpv6AddrRangeBase(int attributeType, byte[] value)
840                 throws InvalidSyntaxException {
841             super(attributeType, value.length);
842 
843             if (value.length == VALUE_LEN_NOT_INCLUDED) {
844                 linkAddress = null;
845                 return;
846             }
847 
848             try {
849                 ByteBuffer inputBuffer = ByteBuffer.wrap(value);
850                 byte[] ip6AddrBytes = new byte[IPV6_ADDRESS_LEN];
851                 inputBuffer.get(ip6AddrBytes);
852                 InetAddress address = InetAddress.getByAddress(ip6AddrBytes);
853 
854                 int prefixLen = Byte.toUnsignedInt(inputBuffer.get());
855 
856                 linkAddress = new LinkAddress(address, prefixLen);
857                 validateIpv6LinkAddressTypeOrThrow(linkAddress);
858             } catch (UnknownHostException | IllegalArgumentException e) {
859                 throw new InvalidSyntaxException("Invalid attribute value", e);
860             }
861         }
862 
validateIpv6LinkAddressTypeOrThrow(LinkAddress address)863         private void validateIpv6LinkAddressTypeOrThrow(LinkAddress address) {
864             if (!address.isIpv6()) {
865                 throw new IllegalArgumentException("Input LinkAddress is not IPv6");
866             }
867         }
868 
869         @Override
encodeValueToByteBuffer(ByteBuffer buffer)870         protected void encodeValueToByteBuffer(ByteBuffer buffer) {
871             if (linkAddress == null) {
872                 buffer.put(new byte[VALUE_LEN_NOT_INCLUDED]);
873                 return;
874             }
875 
876             buffer.put(linkAddress.getAddress().getAddress())
877                     .put((byte) linkAddress.getPrefixLength());
878         }
879 
880         @Override
getValueLength()881         protected int getValueLength() {
882             return linkAddress == null ? VALUE_LEN_NOT_INCLUDED : VALUE_LEN;
883         }
884 
885         @Override
isLengthValid(int length)886         protected boolean isLengthValid(int length) {
887             return length == VALUE_LEN || length == VALUE_LEN_NOT_INCLUDED;
888         }
889     }
890 
891     /** This class represents Configuration Attribute for IPv6 internal addresses. */
892     public static class ConfigAttributeIpv6Address
893             extends TunnelModeChildConfigAttrIpv6AddrRangeBase implements ConfigRequestIpv6Address {
894         /** Construct an instance with specified address for an outbound packet. */
ConfigAttributeIpv6Address(LinkAddress ipv6LinkAddress)895         public ConfigAttributeIpv6Address(LinkAddress ipv6LinkAddress) {
896             super(CONFIG_ATTR_INTERNAL_IP6_ADDRESS, ipv6LinkAddress);
897         }
898 
899         /**
900          * Construct an instance without a specified address for an outbound packet.
901          *
902          * <p>It must be only used in a configuration request.
903          */
ConfigAttributeIpv6Address()904         public ConfigAttributeIpv6Address() {
905             super(CONFIG_ATTR_INTERNAL_IP6_ADDRESS);
906         }
907 
908         /** Construct an instance with a decoded inbound packet. */
909         @VisibleForTesting
ConfigAttributeIpv6Address(byte[] value)910         ConfigAttributeIpv6Address(byte[] value) throws InvalidSyntaxException {
911             super(CONFIG_ATTR_INTERNAL_IP6_ADDRESS, value);
912         }
913 
914         @Override
getAddress()915         public Inet6Address getAddress() {
916             return linkAddress == null ? null : (Inet6Address) linkAddress.getAddress();
917         }
918 
919         @Override
getPrefixLength()920         public int getPrefixLength() {
921             return linkAddress == null ? null : linkAddress.getPrefixLength();
922         }
923     }
924 
925     /**
926      * This class represents Configuration Attribute for IPv6 subnets.
927      *
928      * <p>According to RFC 7296, INTERNAL_IP6_SUBNET in configuration requests cannot be used
929      * reliably because the meaning is unclear.
930      */
931     public static class ConfigAttributeIpv6Subnet
932             extends TunnelModeChildConfigAttrIpv6AddrRangeBase {
933         /** Construct an instance with specified subnet for an outbound packet. */
ConfigAttributeIpv6Subnet(LinkAddress ipv6LinkAddress)934         public ConfigAttributeIpv6Subnet(LinkAddress ipv6LinkAddress) {
935             super(CONFIG_ATTR_INTERNAL_IP6_SUBNET, ipv6LinkAddress);
936         }
937 
938         /**
939          * Construct an instance without a specified subnet for an outbound packet.
940          *
941          * <p>It must be only used in a configuration request.
942          */
ConfigAttributeIpv6Subnet()943         public ConfigAttributeIpv6Subnet() {
944             super(CONFIG_ATTR_INTERNAL_IP6_SUBNET);
945         }
946 
947         /** Construct an instance with a decoded inbound packet. */
948         @VisibleForTesting
ConfigAttributeIpv6Subnet(byte[] value)949         ConfigAttributeIpv6Subnet(byte[] value) throws InvalidSyntaxException {
950             super(CONFIG_ATTR_INTERNAL_IP6_SUBNET, value);
951         }
952     }
953 
954     /**
955      * This class represents Configuration Attribute for IPv6 DNS.
956      *
957      * <p>There is no use case to create a DNS request for a specfic DNS server address. As an IKE
958      * client, we will only support building an empty DNS attribute for an outbound IKE packet.
959      */
960     public static class ConfigAttributeIpv6Dns extends TunnelModeChildConfigAttrIpv6AddressBase
961             implements ConfigRequestIpv6DnsServer {
962         /** Construct an instance with specified DNS server address for an outbound packet. */
ConfigAttributeIpv6Dns(Inet6Address ipv6Address)963         public ConfigAttributeIpv6Dns(Inet6Address ipv6Address) {
964             super(CONFIG_ATTR_INTERNAL_IP6_DNS, ipv6Address);
965         }
966 
967         /**
968          * Construct an instance without a specified DNS server address for an outbound packet.
969          *
970          * <p>It must be only used in a configuration request.
971          */
ConfigAttributeIpv6Dns()972         public ConfigAttributeIpv6Dns() {
973             super(CONFIG_ATTR_INTERNAL_IP6_DNS);
974         }
975 
ConfigAttributeIpv6Dns(byte[] value)976         protected ConfigAttributeIpv6Dns(byte[] value) throws InvalidSyntaxException {
977             super(CONFIG_ATTR_INTERNAL_IP6_DNS, value);
978         }
979 
getAddress()980         public Inet6Address getAddress() {
981             return address;
982         }
983     }
984 
985     /** This class represents an IPv6 P_CSCF address attribute */
986     public static class ConfigAttributeIpv6Pcscf extends IkeConfigAttrIpv6AddressBase
987             implements ConfigRequestIpv6PcscfServer {
988         /** Construct an instance with a specified P_CSCF server address for an outbound packet. */
ConfigAttributeIpv6Pcscf(Inet6Address ipv6Address)989         public ConfigAttributeIpv6Pcscf(Inet6Address ipv6Address) {
990             super(CONFIG_ATTR_IP6_PCSCF, ipv6Address);
991         }
992 
993         /**
994          * Construct an instance without a specified P_CSCF server address for an outbound packet.
995          *
996          * <p>It must be only used in a configuration request.
997          */
ConfigAttributeIpv6Pcscf()998         public ConfigAttributeIpv6Pcscf() {
999             super(CONFIG_ATTR_IP6_PCSCF);
1000         }
1001 
ConfigAttributeIpv6Pcscf(byte[] value)1002         protected ConfigAttributeIpv6Pcscf(byte[] value) throws InvalidSyntaxException {
1003             super(CONFIG_ATTR_IP6_PCSCF, value);
1004         }
1005 
1006         @Override
getAddress()1007         public Inet6Address getAddress() {
1008             return address;
1009         }
1010     }
1011 
1012     /** This class represents an application version attribute */
1013     public static class ConfigAttributeAppVersion extends ConfigAttribute {
1014         private static final Charset ASCII = StandardCharsets.US_ASCII;
1015         private static final String APP_VERSION_NONE = "";
1016 
1017         public final String applicationVersion;
1018 
1019         /**
1020          * Construct an instance for an outbound packet for requesting remote application version.
1021          */
ConfigAttributeAppVersion()1022         public ConfigAttributeAppVersion() {
1023             this(APP_VERSION_NONE);
1024         }
1025 
1026         /** Construct an instance for an outbound packet with local application version. */
ConfigAttributeAppVersion(String localAppVersion)1027         public ConfigAttributeAppVersion(String localAppVersion) {
1028             super(CONFIG_ATTR_APPLICATION_VERSION);
1029             applicationVersion = localAppVersion;
1030         }
1031 
1032         /** Construct an instance from a decoded inbound packet. */
ConfigAttributeAppVersion(byte[] value)1033         protected ConfigAttributeAppVersion(byte[] value) throws InvalidSyntaxException {
1034             super(CONFIG_ATTR_APPLICATION_VERSION);
1035             applicationVersion = new String(value, ASCII);
1036         }
1037 
encodeValueToByteBuffer(ByteBuffer buffer)1038         protected void encodeValueToByteBuffer(ByteBuffer buffer) {
1039             buffer.put(applicationVersion.getBytes(ASCII));
1040         }
1041 
getValueLength()1042         protected int getValueLength() {
1043             return applicationVersion.getBytes(ASCII).length;
1044         }
1045 
1046         @Override
isLengthValid(int length)1047         protected boolean isLengthValid(int length) {
1048             return length >= 0;
1049         }
1050     }
1051 
1052     /**
1053      * Encode Configuration payload to ByteBUffer.
1054      *
1055      * @param nextPayload type of payload that follows this payload.
1056      * @param byteBuffer destination ByteBuffer that stores encoded payload.
1057      */
1058     @Override
encodeToByteBuffer(@ayloadType int nextPayload, ByteBuffer byteBuffer)1059     protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
1060         encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer);
1061         byteBuffer.put((byte) configType).put(new byte[CONFIG_HEADER_RESERVED_LEN]);
1062 
1063         for (ConfigAttribute attr : recognizedAttributeList) {
1064             attr.encodeAttributeToByteBuffer(byteBuffer);
1065         }
1066     }
1067 
1068     /**
1069      * Get entire payload length.
1070      *
1071      * @return entire payload length.
1072      */
1073     @Override
getPayloadLength()1074     protected int getPayloadLength() {
1075         int len = GENERIC_HEADER_LENGTH + CONFIG_HEADER_LEN;
1076 
1077         for (ConfigAttribute attr : recognizedAttributeList) {
1078             len += attr.getAttributeLen();
1079         }
1080 
1081         return len;
1082     }
1083 
1084     /**
1085      * Return the payload type as a String.
1086      *
1087      * @return the payload type as a String.
1088      */
1089     @Override
getTypeString()1090     public String getTypeString() {
1091         switch (configType) {
1092             case CONFIG_TYPE_REQUEST:
1093                 return "CP(Req)";
1094             case CONFIG_TYPE_REPLY:
1095                 return "CP(Reply)";
1096             default:
1097                 return "CP(" + configType + ")";
1098         }
1099     }
1100 }
1101