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