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