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 android.net.ipsec.ike; 18 19 import static android.system.OsConstants.AF_INET; 20 import static android.system.OsConstants.AF_INET6; 21 22 import android.annotation.IntRange; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.SuppressLint; 26 import android.annotation.SystemApi; 27 import android.net.LinkAddress; 28 import android.os.PersistableBundle; 29 30 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute; 31 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Address; 32 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Dhcp; 33 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Dns; 34 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Netmask; 35 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Address; 36 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Dns; 37 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.TunnelModeChildConfigAttribute; 38 import com.android.server.vcn.util.PersistableBundleUtils; 39 40 import java.net.Inet4Address; 41 import java.net.Inet6Address; 42 import java.net.InetAddress; 43 import java.util.ArrayList; 44 import java.util.Arrays; 45 import java.util.Collections; 46 import java.util.List; 47 import java.util.Objects; 48 49 /** 50 * TunnelModeChildSessionParams represents proposed configurations for negotiating a tunnel mode 51 * Child Session. 52 */ 53 public final class TunnelModeChildSessionParams extends ChildSessionParams { 54 /** @hide */ 55 private static final String CONFIG_ATTRIBUTES_KEY = "mConfigRequests"; 56 57 @NonNull private final TunnelModeChildConfigAttribute[] mConfigRequests; 58 TunnelModeChildSessionParams( @onNull IkeTrafficSelector[] inboundTs, @NonNull IkeTrafficSelector[] outboundTs, @NonNull ChildSaProposal[] proposals, @NonNull TunnelModeChildConfigAttribute[] configRequests, int hardLifetimeSec, int softLifetimeSec)59 private TunnelModeChildSessionParams( 60 @NonNull IkeTrafficSelector[] inboundTs, 61 @NonNull IkeTrafficSelector[] outboundTs, 62 @NonNull ChildSaProposal[] proposals, 63 @NonNull TunnelModeChildConfigAttribute[] configRequests, 64 int hardLifetimeSec, 65 int softLifetimeSec) { 66 super( 67 inboundTs, 68 outboundTs, 69 proposals, 70 hardLifetimeSec, 71 softLifetimeSec, 72 false /*isTransport*/); 73 mConfigRequests = configRequests; 74 } 75 76 /** 77 * Constructs this object by deserializing a PersistableBundle 78 * 79 * <p>Constructed TunnelModeChildSessionParams is guaranteed to be valid, as checked by the 80 * TunnelModeChildSessionParams.Builder 81 * 82 * @hide 83 */ 84 @NonNull fromPersistableBundle( @onNull PersistableBundle in)85 public static TunnelModeChildSessionParams fromPersistableBundle( 86 @NonNull PersistableBundle in) { 87 Objects.requireNonNull(in, "PersistableBundle not provided"); 88 89 TunnelModeChildSessionParams.Builder builder = new TunnelModeChildSessionParams.Builder(); 90 91 for (ChildSaProposal p : getProposalsFromPersistableBundle(in)) { 92 builder.addSaProposal(p); 93 } 94 95 for (IkeTrafficSelector ts : getTsFromPersistableBundle(in, INBOUND_TS_KEY)) { 96 builder.addInboundTrafficSelectors(ts); 97 } 98 99 for (IkeTrafficSelector ts : getTsFromPersistableBundle(in, OUTBOUND_TS_KEY)) { 100 builder.addOutboundTrafficSelectors(ts); 101 } 102 103 builder.setLifetimeSeconds( 104 in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY)); 105 106 PersistableBundle configAttributeBundle = in.getPersistableBundle(CONFIG_ATTRIBUTES_KEY); 107 List<ConfigAttribute> configReqList = 108 PersistableBundleUtils.toList( 109 configAttributeBundle, ConfigAttribute::fromPersistableBundle); 110 111 for (ConfigAttribute a : configReqList) { 112 builder.addConfigRequest((TunnelModeChildConfigAttribute) a); 113 } 114 115 return builder.build(); 116 } 117 118 /** 119 * Serializes this object to a PersistableBundle 120 * 121 * @hide 122 */ 123 @Override 124 @NonNull toPersistableBundle()125 public PersistableBundle toPersistableBundle() { 126 final PersistableBundle result = super.toPersistableBundle(); 127 128 PersistableBundle configAttributeBundle = 129 PersistableBundleUtils.fromList( 130 Arrays.asList(mConfigRequests), 131 TunnelModeChildConfigAttribute::toPersistableBundle); 132 result.putPersistableBundle(CONFIG_ATTRIBUTES_KEY, configAttributeBundle); 133 134 return result; 135 } 136 137 /** @hide */ getConfigurationAttributesInternal()138 public TunnelModeChildConfigAttribute[] getConfigurationAttributesInternal() { 139 return mConfigRequests; 140 } 141 142 /** Retrieves the list of Configuration Requests */ 143 @NonNull getConfigurationRequests()144 public List<TunnelModeChildConfigRequest> getConfigurationRequests() { 145 return Collections.unmodifiableList(Arrays.asList(mConfigRequests)); 146 } 147 148 /** Represents a tunnel mode child session configuration request type */ 149 public interface TunnelModeChildConfigRequest {} 150 151 /** Represents an IPv4 Internal Address request */ 152 public interface ConfigRequestIpv4Address extends TunnelModeChildConfigRequest { 153 /** 154 * Retrieves the requested internal IPv4 address 155 * 156 * @return The requested IPv4 address, or null if no specific internal address was requested 157 */ 158 @Nullable getAddress()159 Inet4Address getAddress(); 160 } 161 162 /** Represents an IPv4 DHCP server request */ 163 public interface ConfigRequestIpv4DhcpServer extends TunnelModeChildConfigRequest {} 164 165 /** Represents an IPv4 DNS Server request */ 166 public interface ConfigRequestIpv4DnsServer extends TunnelModeChildConfigRequest {} 167 168 /** Represents an IPv4 Netmask request */ 169 public interface ConfigRequestIpv4Netmask extends TunnelModeChildConfigRequest {} 170 171 /** Represents an IPv6 Internal Address request */ 172 public interface ConfigRequestIpv6Address extends TunnelModeChildConfigRequest { 173 /** 174 * Retrieves the requested internal IPv6 address 175 * 176 * @return The requested IPv6 address, or null if no specific internal address was requested 177 */ 178 @Nullable getAddress()179 Inet6Address getAddress(); 180 181 /** 182 * Retrieves the prefix length 183 * 184 * @return The requested prefix length, or -1 if no specific IPv6 address was requested 185 */ getPrefixLength()186 int getPrefixLength(); 187 } 188 189 /** Represents an IPv6 DNS Server request */ 190 public interface ConfigRequestIpv6DnsServer extends TunnelModeChildConfigRequest {} 191 192 @Override hashCode()193 public int hashCode() { 194 return Objects.hash(super.hashCode(), Arrays.hashCode(mConfigRequests)); 195 } 196 197 @Override equals(Object o)198 public boolean equals(Object o) { 199 if (!super.equals(o) || !(o instanceof ChildSessionParams)) { 200 return false; 201 } 202 203 TunnelModeChildSessionParams other = (TunnelModeChildSessionParams) o; 204 205 return Arrays.equals(mConfigRequests, other.mConfigRequests); 206 } 207 208 /** This class can be used to incrementally construct a {@link TunnelModeChildSessionParams}. */ 209 public static final class Builder extends ChildSessionParams.Builder { 210 private static final int IPv4_DEFAULT_PREFIX_LEN = 32; 211 212 private boolean mHasIp4AddressRequest; 213 private boolean mHasIp4NetmaskRequest; 214 private List<TunnelModeChildConfigAttribute> mConfigRequestList = new ArrayList<>(); 215 216 /** Create a Builder for negotiating a tunnel mode Child Session. */ Builder()217 public Builder() { 218 super(); 219 mHasIp4AddressRequest = false; 220 mHasIp4NetmaskRequest = false; 221 } 222 223 /** 224 * Construct Builder from the {@link TunnelModeChildSessionParams} object. 225 * 226 * @param childParams the object this Builder will be constructed with. 227 */ Builder(@onNull TunnelModeChildSessionParams childParams)228 public Builder(@NonNull TunnelModeChildSessionParams childParams) { 229 super(childParams); 230 mConfigRequestList.addAll(Arrays.asList(childParams.mConfigRequests)); 231 for (TunnelModeChildConfigAttribute config : mConfigRequestList) { 232 if (config instanceof ConfigAttributeIpv4Address) { 233 mHasIp4AddressRequest = true; 234 } else if (config instanceof ConfigAttributeIpv4Netmask) { 235 mHasIp4NetmaskRequest = true; 236 } 237 } 238 } 239 240 /** 241 * Adds an Child SA proposal to the {@link TunnelModeChildSessionParams} being built. 242 * 243 * @param proposal Child SA proposal. 244 * @return Builder this, to facilitate chaining. 245 * @deprecated Callers should use {@link #addChildSaProposal(ChildSaProposal)}. This method 246 * is deprecated because its name does not match the input type. 247 * @hide 248 */ 249 // The matching getter is defined in the super class. Please see 250 // {@link ChildSessionParams#getSaProposals} 251 @SuppressLint("MissingGetterMatchingBuilder") 252 @Deprecated 253 @SystemApi 254 @NonNull addSaProposal(@onNull ChildSaProposal proposal)255 public Builder addSaProposal(@NonNull ChildSaProposal proposal) { 256 return addChildSaProposal(proposal); 257 } 258 259 /** 260 * Adds an Child SA proposal to the {@link TunnelModeChildSessionParams} being built. 261 * 262 * @param proposal Child SA proposal. 263 * @return Builder this, to facilitate chaining. 264 */ 265 // The matching getter is defined in the super class. Please see 266 // {@link ChildSessionParams#getChildSaProposals} 267 @SuppressLint("MissingGetterMatchingBuilder") 268 @NonNull addChildSaProposal(@onNull ChildSaProposal proposal)269 public Builder addChildSaProposal(@NonNull ChildSaProposal proposal) { 270 if (proposal == null) { 271 throw new NullPointerException("Required argument not provided"); 272 } 273 274 addProposal(proposal); 275 return this; 276 } 277 278 /** 279 * Adds an inbound {@link IkeTrafficSelector} to the {@link TunnelModeChildSessionParams} 280 * being built. 281 * 282 * <p>This method allows callers to limit the inbound traffic transmitted over the Child 283 * Session to the given range. The IKE server may further narrow the range. Callers should 284 * refer to {@link ChildSessionConfiguration} for the negotiated traffic selectors. 285 * 286 * <p>If no inbound {@link IkeTrafficSelector} is provided, a default value will be used 287 * that covers all IP addresses and ports. 288 * 289 * @param trafficSelector the inbound {@link IkeTrafficSelector}. 290 * @return Builder this, to facilitate chaining. 291 */ 292 // The matching getter is defined in the super class. Please see {@link 293 // ChildSessionParams#getInboundTrafficSelectors} 294 @SuppressLint("MissingGetterMatchingBuilder") 295 @NonNull addInboundTrafficSelectors(@onNull IkeTrafficSelector trafficSelector)296 public Builder addInboundTrafficSelectors(@NonNull IkeTrafficSelector trafficSelector) { 297 Objects.requireNonNull(trafficSelector, "Required argument not provided"); 298 addInboundTs(trafficSelector); 299 return this; 300 } 301 302 /** 303 * Adds an outbound {@link IkeTrafficSelector} to the {@link TunnelModeChildSessionParams} 304 * being built. 305 * 306 * <p>This method allows callers to limit the outbound traffic transmitted over the Child 307 * Session to the given range. The IKE server may further narrow the range. Callers should 308 * refer to {@link ChildSessionConfiguration} for the negotiated traffic selectors. 309 * 310 * <p>If no outbound {@link IkeTrafficSelector} is provided, a default value will be used 311 * that covers all IP addresses and ports. 312 * 313 * @param trafficSelector the outbound {@link IkeTrafficSelector}. 314 * @return Builder this, to facilitate chaining. 315 */ 316 // The matching getter is defined in the super class. Please see {@link 317 // ChildSessionParams#getOutboundTrafficSelectors} 318 @SuppressLint("MissingGetterMatchingBuilder") 319 @NonNull addOutboundTrafficSelectors(@onNull IkeTrafficSelector trafficSelector)320 public Builder addOutboundTrafficSelectors(@NonNull IkeTrafficSelector trafficSelector) { 321 Objects.requireNonNull(trafficSelector, "Required argument not provided"); 322 addOutboundTs(trafficSelector); 323 return this; 324 } 325 326 /** 327 * Sets hard and soft lifetimes. 328 * 329 * <p>Lifetimes will not be negotiated with the remote IKE server. 330 * 331 * @param hardLifetimeSeconds number of seconds after which Child SA will expire. Defaults 332 * to 7200 seconds (2 hours). Considering IPsec packet lifetime, IKE library requires 333 * hard lifetime to be a value from 300 seconds (5 minutes) to 14400 seconds (4 hours), 334 * inclusive. 335 * @param softLifetimeSeconds number of seconds after which Child SA will request rekey. 336 * Defaults to 3600 seconds (1 hour). MUST be at least 120 seconds (2 minutes), and at 337 * least 60 seconds (1 minute) shorter than the hard lifetime. 338 */ 339 // The matching getters are defined in the super class. Please see {@link 340 // ChildSessionParams#getHardLifetimeSeconds and {@link 341 // ChildSessionParams#getSoftLifetimeSeconds} 342 @SuppressLint("MissingGetterMatchingBuilder") 343 @NonNull setLifetimeSeconds( @ntRange from = CHILD_HARD_LIFETIME_SEC_MINIMUM, to = CHILD_HARD_LIFETIME_SEC_MAXIMUM) int hardLifetimeSeconds, @IntRange( from = CHILD_SOFT_LIFETIME_SEC_MINIMUM, to = CHILD_HARD_LIFETIME_SEC_MAXIMUM) int softLifetimeSeconds)344 public Builder setLifetimeSeconds( 345 @IntRange( 346 from = CHILD_HARD_LIFETIME_SEC_MINIMUM, 347 to = CHILD_HARD_LIFETIME_SEC_MAXIMUM) 348 int hardLifetimeSeconds, 349 @IntRange( 350 from = CHILD_SOFT_LIFETIME_SEC_MINIMUM, 351 to = CHILD_HARD_LIFETIME_SEC_MAXIMUM) 352 int softLifetimeSeconds) { 353 validateAndSetLifetime(hardLifetimeSeconds, softLifetimeSeconds); 354 mHardLifetimeSec = hardLifetimeSeconds; 355 mSoftLifetimeSec = softLifetimeSeconds; 356 return this; 357 } 358 359 /** 360 * Adds an internal IP address request to the {@link TunnelModeChildSessionParams} being 361 * built. 362 * 363 * @param addressFamily the address family. Only {@code AF_INET} and {@code AF_INET6} are 364 * allowed 365 * @return Builder this, to facilitate chaining. 366 */ 367 // #getConfigurationRequests has been defined for callers to retrieve internal address 368 // requests 369 @SuppressLint("MissingGetterMatchingBuilder") 370 @NonNull addInternalAddressRequest(int addressFamily)371 public Builder addInternalAddressRequest(int addressFamily) { 372 if (addressFamily == AF_INET) { 373 mHasIp4AddressRequest = true; 374 mConfigRequestList.add(new ConfigAttributeIpv4Address()); 375 return this; 376 } else if (addressFamily == AF_INET6) { 377 mConfigRequestList.add(new ConfigAttributeIpv6Address()); 378 return this; 379 } else { 380 throw new IllegalArgumentException("Invalid address family: " + addressFamily); 381 } 382 } 383 384 /** 385 * Adds a specific internal IPv4 address request to the {@link TunnelModeChildSessionParams} 386 * being built. 387 * 388 * @param address the requested IPv4 address. 389 * @return Builder this, to facilitate chaining. 390 */ 391 // #getConfigurationRequests has been defined for callers to retrieve internal address 392 // requests 393 @SuppressLint("MissingGetterMatchingBuilder") 394 @NonNull addInternalAddressRequest(@onNull Inet4Address address)395 public Builder addInternalAddressRequest(@NonNull Inet4Address address) { 396 if (address == null) { 397 throw new NullPointerException("Required argument not provided"); 398 } 399 400 mHasIp4AddressRequest = true; 401 mConfigRequestList.add(new ConfigAttributeIpv4Address((Inet4Address) address)); 402 return this; 403 } 404 405 /** 406 * Adds a specific internal IPv6 address request to the {@link TunnelModeChildSessionParams} 407 * being built. 408 * 409 * @param address the requested IPv6 address. 410 * @param prefixLen length of the IPv6 address prefix length. 411 * @return Builder this, to facilitate chaining. 412 */ 413 // #getConfigurationRequests has been defined for callers to retrieve internal address 414 // requests 415 @SuppressLint("MissingGetterMatchingBuilder") 416 @NonNull addInternalAddressRequest(@onNull Inet6Address address, int prefixLen)417 public Builder addInternalAddressRequest(@NonNull Inet6Address address, int prefixLen) { 418 if (address == null) { 419 throw new NullPointerException("Required argument not provided"); 420 } 421 422 mConfigRequestList.add( 423 new ConfigAttributeIpv6Address(new LinkAddress(address, prefixLen))); 424 return this; 425 } 426 427 /** 428 * Adds an internal DNS server request to the {@link TunnelModeChildSessionParams} being 429 * built. 430 * 431 * @param addressFamily the address family. Only {@code AF_INET} and {@code AF_INET6} are 432 * allowed 433 * @return Builder this, to facilitate chaining. 434 */ 435 // #getConfigurationRequests has been defined for callers to retrieve internal DNS server 436 // requests 437 @SuppressLint("MissingGetterMatchingBuilder") 438 @NonNull addInternalDnsServerRequest(int addressFamily)439 public Builder addInternalDnsServerRequest(int addressFamily) { 440 if (addressFamily == AF_INET) { 441 mConfigRequestList.add(new ConfigAttributeIpv4Dns()); 442 return this; 443 } else if (addressFamily == AF_INET6) { 444 mConfigRequestList.add(new ConfigAttributeIpv6Dns()); 445 return this; 446 } else { 447 throw new IllegalArgumentException("Invalid address family: " + addressFamily); 448 } 449 } 450 451 /** 452 * Adds a specific internal DNS server request to the {@link TunnelModeChildSessionParams} 453 * being built. 454 * 455 * @param address the requested DNS server address. 456 * @return Builder this, to facilitate chaining. 457 * @hide 458 */ 459 @NonNull addInternalDnsServerRequest(@onNull InetAddress address)460 public Builder addInternalDnsServerRequest(@NonNull InetAddress address) { 461 if (address == null) { 462 throw new NullPointerException("Required argument not provided"); 463 } 464 465 if (address instanceof Inet4Address) { 466 mConfigRequestList.add(new ConfigAttributeIpv4Dns((Inet4Address) address)); 467 return this; 468 } else if (address instanceof Inet6Address) { 469 mConfigRequestList.add(new ConfigAttributeIpv6Dns((Inet6Address) address)); 470 return this; 471 } else { 472 throw new IllegalArgumentException("Invalid address " + address); 473 } 474 } 475 476 /** 477 * Adds an internal DHCP server request to the {@link TunnelModeChildSessionParams} being 478 * built. 479 * 480 * <p>Only DHCPv4 server requests are supported. 481 * 482 * @param addressFamily the address family. Only {@code AF_INET} is allowed 483 * @return Builder this, to facilitate chaining. 484 */ 485 // #getConfigurationRequests has been defined for callers to retrieve internal DHCP server 486 // requests. 487 @SuppressLint("MissingGetterMatchingBuilder") 488 @NonNull addInternalDhcpServerRequest(int addressFamily)489 public Builder addInternalDhcpServerRequest(int addressFamily) { 490 if (addressFamily == AF_INET) { 491 mConfigRequestList.add(new ConfigAttributeIpv4Dhcp()); 492 return this; 493 } else { 494 throw new IllegalArgumentException("Invalid address family: " + addressFamily); 495 } 496 } 497 498 /** 499 * Adds a specific internal DHCP server request to the {@link TunnelModeChildSessionParams} 500 * being built. 501 * 502 * <p>Only DHCPv4 server requests are supported. 503 * 504 * @param address the requested DHCP server address. 505 * @return Builder this, to facilitate chaining. 506 * @hide 507 */ 508 @NonNull addInternalDhcpServerRequest(@onNull InetAddress address)509 public Builder addInternalDhcpServerRequest(@NonNull InetAddress address) { 510 if (address == null) { 511 throw new NullPointerException("Required argument not provided"); 512 } 513 514 if (address instanceof Inet4Address) { 515 mConfigRequestList.add(new ConfigAttributeIpv4Dhcp((Inet4Address) address)); 516 return this; 517 } else { 518 throw new IllegalArgumentException("Invalid address " + address); 519 } 520 } 521 522 /** 523 * Adds Configuration requests. Internal use only. 524 * 525 * @hide 526 */ 527 @NonNull addConfigRequest(@onNull TunnelModeChildConfigAttribute attribute)528 public Builder addConfigRequest(@NonNull TunnelModeChildConfigAttribute attribute) { 529 if (attribute instanceof ConfigAttributeIpv4Address) { 530 mHasIp4AddressRequest = true; 531 } else if (attribute instanceof ConfigAttributeIpv4Netmask) { 532 if (((ConfigAttributeIpv4Netmask) attribute).address != null) { 533 throw new IllegalArgumentException( 534 "Requesting specific a netmask is disallowed"); 535 } else { 536 mHasIp4NetmaskRequest = true; 537 } 538 } 539 540 mConfigRequestList.add(attribute); 541 return this; 542 } 543 544 /** 545 * Validates and builds the {@link TunnelModeChildSessionParams}. 546 * 547 * @return the validated {@link TunnelModeChildSessionParams}. 548 */ 549 @NonNull build()550 public TunnelModeChildSessionParams build() { 551 addDefaultTsIfNotConfigured(); 552 validateOrThrow(); 553 554 if (!mHasIp4AddressRequest && mHasIp4NetmaskRequest) { 555 throw new IllegalArgumentException( 556 "Requesting netmask without IPv4 address is disallowed"); 557 } 558 if (mHasIp4AddressRequest && !mHasIp4NetmaskRequest) { 559 mConfigRequestList.add(new ConfigAttributeIpv4Netmask()); 560 } 561 562 return new TunnelModeChildSessionParams( 563 mInboundTsList.toArray(new IkeTrafficSelector[0]), 564 mOutboundTsList.toArray(new IkeTrafficSelector[0]), 565 mSaProposalList.toArray(new ChildSaProposal[0]), 566 mConfigRequestList.toArray(new TunnelModeChildConfigAttribute[0]), 567 mHardLifetimeSec, 568 mSoftLifetimeSec); 569 } 570 } 571 } 572