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