1 /* 2 * Copyright (C) 2020 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.server.connectivity; 18 19 import static android.net.ConnectivityManager.NetworkCallback; 20 import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP; 21 import static android.net.ipsec.ike.SaProposal.DH_GROUP_3072_BIT_MODP; 22 import static android.net.ipsec.ike.SaProposal.DH_GROUP_4096_BIT_MODP; 23 import static android.net.ipsec.ike.SaProposal.DH_GROUP_CURVE_25519; 24 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC; 25 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CTR; 26 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12; 27 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16; 28 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8; 29 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305; 30 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96; 31 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96; 32 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128; 33 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192; 34 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256; 35 import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128; 36 import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_192; 37 import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256; 38 import static android.net.ipsec.ike.SaProposal.KEY_LEN_UNUSED; 39 import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_CMAC; 40 import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC; 41 import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1; 42 import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256; 43 import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384; 44 import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512; 45 46 import android.annotation.NonNull; 47 import android.content.Context; 48 import android.net.Ikev2VpnProfile; 49 import android.net.InetAddresses; 50 import android.net.IpPrefix; 51 import android.net.IpSecAlgorithm; 52 import android.net.IpSecTransform; 53 import android.net.LinkProperties; 54 import android.net.Network; 55 import android.net.NetworkCapabilities; 56 import android.net.RouteInfo; 57 import android.net.eap.EapSessionConfig; 58 import android.net.ipsec.ike.ChildSaProposal; 59 import android.net.ipsec.ike.ChildSessionCallback; 60 import android.net.ipsec.ike.ChildSessionConfiguration; 61 import android.net.ipsec.ike.ChildSessionParams; 62 import android.net.ipsec.ike.IkeFqdnIdentification; 63 import android.net.ipsec.ike.IkeIdentification; 64 import android.net.ipsec.ike.IkeIpv4AddrIdentification; 65 import android.net.ipsec.ike.IkeIpv6AddrIdentification; 66 import android.net.ipsec.ike.IkeKeyIdIdentification; 67 import android.net.ipsec.ike.IkeRfc822AddrIdentification; 68 import android.net.ipsec.ike.IkeSaProposal; 69 import android.net.ipsec.ike.IkeSessionCallback; 70 import android.net.ipsec.ike.IkeSessionConfiguration; 71 import android.net.ipsec.ike.IkeSessionConnectionInfo; 72 import android.net.ipsec.ike.IkeSessionParams; 73 import android.net.ipsec.ike.IkeTrafficSelector; 74 import android.net.ipsec.ike.TunnelModeChildSessionParams; 75 import android.net.ipsec.ike.exceptions.IkeException; 76 import android.net.ipsec.ike.exceptions.IkeProtocolException; 77 import android.system.OsConstants; 78 import android.util.Log; 79 80 import com.android.internal.net.VpnProfile; 81 import com.android.internal.util.HexDump; 82 import com.android.net.module.util.IpRange; 83 84 import java.net.Inet4Address; 85 import java.net.Inet6Address; 86 import java.net.InetAddress; 87 import java.util.ArrayList; 88 import java.util.Arrays; 89 import java.util.Collection; 90 import java.util.HashSet; 91 import java.util.List; 92 import java.util.concurrent.Executor; 93 94 /** 95 * Utility class to build and convert IKEv2/IPsec parameters. 96 * 97 * @hide 98 */ 99 public class VpnIkev2Utils { 100 private static final String TAG = VpnIkev2Utils.class.getSimpleName(); 101 makeIkeSessionParamsBuilder( @onNull Context context, @NonNull Ikev2VpnProfile profile, @NonNull Network network)102 static IkeSessionParams.Builder makeIkeSessionParamsBuilder( 103 @NonNull Context context, @NonNull Ikev2VpnProfile profile, @NonNull Network network) { 104 final IkeIdentification localId = parseIkeIdentification(profile.getUserIdentity()); 105 final IkeIdentification remoteId = parseIkeIdentification(profile.getServerAddr()); 106 107 final IkeSessionParams.Builder ikeOptionsBuilder = 108 new IkeSessionParams.Builder(context) 109 .setServerHostname(profile.getServerAddr()) 110 .setNetwork(network) 111 .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE) 112 .setLocalIdentification(localId) 113 .setRemoteIdentification(remoteId); 114 setIkeAuth(profile, ikeOptionsBuilder); 115 116 for (final IkeSaProposal ikeProposal : getIkeSaProposals()) { 117 ikeOptionsBuilder.addSaProposal(ikeProposal); 118 } 119 120 return ikeOptionsBuilder; 121 } 122 buildChildSessionParams(List<String> allowedAlgorithms)123 static ChildSessionParams buildChildSessionParams(List<String> allowedAlgorithms) { 124 final TunnelModeChildSessionParams.Builder childOptionsBuilder = 125 new TunnelModeChildSessionParams.Builder(); 126 127 for (final ChildSaProposal childProposal : getChildSaProposals(allowedAlgorithms)) { 128 childOptionsBuilder.addSaProposal(childProposal); 129 } 130 131 childOptionsBuilder.addInternalAddressRequest(OsConstants.AF_INET); 132 childOptionsBuilder.addInternalAddressRequest(OsConstants.AF_INET6); 133 childOptionsBuilder.addInternalDnsServerRequest(OsConstants.AF_INET); 134 childOptionsBuilder.addInternalDnsServerRequest(OsConstants.AF_INET6); 135 136 return childOptionsBuilder.build(); 137 } 138 setIkeAuth( @onNull Ikev2VpnProfile profile, @NonNull IkeSessionParams.Builder builder)139 private static void setIkeAuth( 140 @NonNull Ikev2VpnProfile profile, @NonNull IkeSessionParams.Builder builder) { 141 switch (profile.getType()) { 142 case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: 143 final EapSessionConfig eapConfig = 144 new EapSessionConfig.Builder() 145 .setEapMsChapV2Config(profile.getUsername(), profile.getPassword()) 146 .build(); 147 builder.setAuthEap(profile.getServerRootCaCert(), eapConfig); 148 break; 149 case VpnProfile.TYPE_IKEV2_IPSEC_PSK: 150 builder.setAuthPsk(profile.getPresharedKey()); 151 break; 152 case VpnProfile.TYPE_IKEV2_IPSEC_RSA: 153 builder.setAuthDigitalSignature( 154 profile.getServerRootCaCert(), 155 profile.getUserCert(), 156 profile.getRsaPrivateKey()); 157 break; 158 default: 159 throw new IllegalArgumentException("Unknown auth method set"); 160 } 161 } 162 getIkeSaProposals()163 private static List<IkeSaProposal> getIkeSaProposals() { 164 // TODO: Add ability to filter this when IKEv2 API is made Public API 165 final List<IkeSaProposal> proposals = new ArrayList<>(); 166 167 final IkeSaProposal.Builder normalModeBuilder = new IkeSaProposal.Builder(); 168 169 // Add normal mode encryption algorithms 170 normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CTR, KEY_LEN_AES_256); 171 normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256); 172 normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CTR, KEY_LEN_AES_192); 173 normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192); 174 normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CTR, KEY_LEN_AES_128); 175 normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128); 176 177 // Authentication/Integrity Algorithms 178 normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256); 179 normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192); 180 normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128); 181 normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_XCBC_96); 182 normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_CMAC_96); 183 184 // Add AEAD options 185 final IkeSaProposal.Builder aeadBuilder = new IkeSaProposal.Builder(); 186 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_CHACHA20_POLY1305, KEY_LEN_UNUSED); 187 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256); 188 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256); 189 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256); 190 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_192); 191 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192); 192 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_192); 193 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_128); 194 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_128); 195 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128); 196 197 // Add dh, prf for both builders 198 for (final IkeSaProposal.Builder builder : Arrays.asList(normalModeBuilder, aeadBuilder)) { 199 builder.addDhGroup(DH_GROUP_4096_BIT_MODP); 200 201 // Curve25519 has the same security strength as MODP 3072 and cost less bytes 202 builder.addDhGroup(DH_GROUP_CURVE_25519); 203 204 builder.addDhGroup(DH_GROUP_3072_BIT_MODP); 205 builder.addDhGroup(DH_GROUP_2048_BIT_MODP); 206 builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_SHA2_512); 207 builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_SHA2_384); 208 builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_SHA2_256); 209 builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC); 210 builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_CMAC); 211 builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_HMAC_SHA1); 212 } 213 214 proposals.add(normalModeBuilder.build()); 215 proposals.add(aeadBuilder.build()); 216 return proposals; 217 } 218 219 /** Builds a child SA proposal based on the allowed IPsec algorithms */ getChildSaProposals(List<String> allowedAlgorithms)220 private static List<ChildSaProposal> getChildSaProposals(List<String> allowedAlgorithms) { 221 final List<ChildSaProposal> proposals = new ArrayList<>(); 222 223 final List<Integer> aesKeyLenOptions = 224 Arrays.asList(KEY_LEN_AES_256, KEY_LEN_AES_192, KEY_LEN_AES_128); 225 226 // Add non-AEAD options 227 if (Ikev2VpnProfile.hasNormalModeAlgorithms(allowedAlgorithms)) { 228 final ChildSaProposal.Builder normalModeBuilder = new ChildSaProposal.Builder(); 229 230 // Encryption Algorithms: 231 // AES-CBC and AES_CTR are currently the only supported encryption algorithms. 232 for (int len : aesKeyLenOptions) { 233 if (allowedAlgorithms.contains(IpSecAlgorithm.CRYPT_AES_CTR)) { 234 normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CTR, len); 235 } 236 if (allowedAlgorithms.contains(IpSecAlgorithm.CRYPT_AES_CBC)) { 237 normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, len); 238 } 239 } 240 241 // Authentication/Integrity Algorithms: 242 // Guaranteed by Ikev2VpnProfile constructor to contain at least one of these. 243 if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_HMAC_SHA512)) { 244 normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256); 245 } 246 if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_HMAC_SHA384)) { 247 normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192); 248 } 249 if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_HMAC_SHA256)) { 250 normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128); 251 } 252 if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_AES_XCBC)) { 253 normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_XCBC_96); 254 } 255 if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_AES_CMAC)) { 256 normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_CMAC_96); 257 } 258 259 ChildSaProposal proposal = normalModeBuilder.build(); 260 if (proposal.getIntegrityAlgorithms().isEmpty()) { 261 // Should be impossible; Verified in Ikev2VpnProfile. 262 Log.wtf(TAG, "Missing integrity algorithm when buildling Child SA proposal"); 263 } else { 264 proposals.add(normalModeBuilder.build()); 265 } 266 } 267 268 // Add AEAD options 269 if (Ikev2VpnProfile.hasAeadAlgorithms(allowedAlgorithms)) { 270 final ChildSaProposal.Builder aeadBuilder = new ChildSaProposal.Builder(); 271 272 if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305)) { 273 aeadBuilder.addEncryptionAlgorithm( 274 ENCRYPTION_ALGORITHM_CHACHA20_POLY1305, KEY_LEN_UNUSED); 275 } 276 if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_CRYPT_AES_GCM)) { 277 aeadBuilder.addEncryptionAlgorithm( 278 ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256); 279 aeadBuilder.addEncryptionAlgorithm( 280 ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256); 281 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256); 282 aeadBuilder.addEncryptionAlgorithm( 283 ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_192); 284 aeadBuilder.addEncryptionAlgorithm( 285 ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192); 286 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_192); 287 aeadBuilder.addEncryptionAlgorithm( 288 ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_128); 289 aeadBuilder.addEncryptionAlgorithm( 290 ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_128); 291 aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128); 292 } 293 294 proposals.add(aeadBuilder.build()); 295 } 296 297 return proposals; 298 } 299 300 static class IkeSessionCallbackImpl implements IkeSessionCallback { 301 private final String mTag; 302 private final Vpn.IkeV2VpnRunnerCallback mCallback; 303 private final int mToken; 304 IkeSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, int token)305 IkeSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, int token) { 306 mTag = tag; 307 mCallback = callback; 308 mToken = token; 309 } 310 311 @Override onOpened(@onNull IkeSessionConfiguration ikeSessionConfig)312 public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) { 313 Log.d(mTag, "IkeOpened for token " + mToken); 314 mCallback.onIkeOpened(mToken, ikeSessionConfig); 315 } 316 317 @Override onClosed()318 public void onClosed() { 319 Log.d(mTag, "IkeClosed for token " + mToken); 320 mCallback.onSessionLost(mToken, null); // Server requested session closure. Retry? 321 } 322 323 @Override onClosedExceptionally(@onNull IkeException exception)324 public void onClosedExceptionally(@NonNull IkeException exception) { 325 Log.d(mTag, "IkeClosedExceptionally for token " + mToken, exception); 326 mCallback.onSessionLost(mToken, exception); 327 } 328 329 @Override onError(@onNull IkeProtocolException exception)330 public void onError(@NonNull IkeProtocolException exception) { 331 Log.d(mTag, "IkeError for token " + mToken, exception); 332 // Non-fatal, log and continue. 333 } 334 335 @Override onIkeSessionConnectionInfoChanged( @onNull IkeSessionConnectionInfo connectionInfo)336 public void onIkeSessionConnectionInfoChanged( 337 @NonNull IkeSessionConnectionInfo connectionInfo) { 338 Log.d(mTag, "onIkeSessionConnectionInfoChanged for token " + mToken); 339 mCallback.onIkeConnectionInfoChanged(mToken, connectionInfo); 340 } 341 } 342 343 static class ChildSessionCallbackImpl implements ChildSessionCallback { 344 private final String mTag; 345 private final Vpn.IkeV2VpnRunnerCallback mCallback; 346 private final int mToken; 347 ChildSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, int token)348 ChildSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, int token) { 349 mTag = tag; 350 mCallback = callback; 351 mToken = token; 352 } 353 354 @Override onOpened(@onNull ChildSessionConfiguration childConfig)355 public void onOpened(@NonNull ChildSessionConfiguration childConfig) { 356 Log.d(mTag, "ChildOpened for token " + mToken); 357 mCallback.onChildOpened(mToken, childConfig); 358 } 359 360 @Override onClosed()361 public void onClosed() { 362 Log.d(mTag, "ChildClosed for token " + mToken); 363 mCallback.onSessionLost(mToken, null); 364 } 365 366 @Override onClosedExceptionally(@onNull IkeException exception)367 public void onClosedExceptionally(@NonNull IkeException exception) { 368 Log.d(mTag, "ChildClosedExceptionally for token " + mToken, exception); 369 mCallback.onSessionLost(mToken, exception); 370 } 371 372 @Override onIpSecTransformCreated(@onNull IpSecTransform transform, int direction)373 public void onIpSecTransformCreated(@NonNull IpSecTransform transform, int direction) { 374 Log.d(mTag, "ChildTransformCreated; Direction: " + direction + "; token " + mToken); 375 mCallback.onChildTransformCreated(mToken, transform, direction); 376 } 377 378 @Override onIpSecTransformDeleted(@onNull IpSecTransform transform, int direction)379 public void onIpSecTransformDeleted(@NonNull IpSecTransform transform, int direction) { 380 // Nothing to be done; no references to the IpSecTransform are held by the 381 // Ikev2VpnRunner (or this callback class), and this transform will be closed by the 382 // IKE library. 383 Log.d(mTag, "ChildTransformDeleted; Direction: " + direction + "; for token " + mToken); 384 } 385 386 @Override onIpSecTransformsMigrated( @onNull IpSecTransform inIpSecTransform, @NonNull IpSecTransform outIpSecTransform)387 public void onIpSecTransformsMigrated( 388 @NonNull IpSecTransform inIpSecTransform, 389 @NonNull IpSecTransform outIpSecTransform) { 390 Log.d(mTag, "ChildTransformsMigrated; token " + mToken); 391 mCallback.onChildMigrated(mToken, inIpSecTransform, outIpSecTransform); 392 } 393 } 394 395 static class Ikev2VpnNetworkCallback extends NetworkCallback { 396 private final String mTag; 397 private final Vpn.IkeV2VpnRunnerCallback mCallback; 398 private final Executor mExecutor; 399 Ikev2VpnNetworkCallback(String tag, Vpn.IkeV2VpnRunnerCallback callback, Executor executor)400 Ikev2VpnNetworkCallback(String tag, Vpn.IkeV2VpnRunnerCallback callback, 401 Executor executor) { 402 mTag = tag; 403 mCallback = callback; 404 mExecutor = executor; 405 } 406 407 @Override onAvailable(@onNull Network network)408 public void onAvailable(@NonNull Network network) { 409 Log.d(mTag, "onAvailable called for network: " + network); 410 mExecutor.execute(() -> mCallback.onDefaultNetworkChanged(network)); 411 } 412 413 @Override onCapabilitiesChanged(@onNull Network network, @NonNull NetworkCapabilities networkCapabilities)414 public void onCapabilitiesChanged(@NonNull Network network, 415 @NonNull NetworkCapabilities networkCapabilities) { 416 Log.d(mTag, "NC changed for net " + network + " : " + networkCapabilities); 417 mExecutor.execute( 418 () -> mCallback.onDefaultNetworkCapabilitiesChanged(networkCapabilities)); 419 } 420 421 @Override onLinkPropertiesChanged(@onNull Network network, @NonNull LinkProperties linkProperties)422 public void onLinkPropertiesChanged(@NonNull Network network, 423 @NonNull LinkProperties linkProperties) { 424 Log.d(mTag, "LP changed for net " + network + " : " + linkProperties); 425 mExecutor.execute( 426 () -> mCallback.onDefaultNetworkLinkPropertiesChanged(linkProperties)); 427 } 428 429 @Override onLost(@onNull Network network)430 public void onLost(@NonNull Network network) { 431 Log.d(mTag, "onLost called for network: " + network); 432 mExecutor.execute(() -> mCallback.onDefaultNetworkLost(network)); 433 } 434 } 435 436 /** 437 * Identity parsing logic using similar logic to open source implementations of IKEv2 438 * 439 * <p>This method does NOT support using type-prefixes (eg 'fqdn:' or 'keyid'), or ASN.1 encoded 440 * identities. 441 */ parseIkeIdentification(@onNull String identityStr)442 private static IkeIdentification parseIkeIdentification(@NonNull String identityStr) { 443 // TODO: Add identity formatting to public API javadocs. 444 if (identityStr.contains("@")) { 445 if (identityStr.startsWith("@#")) { 446 // KEY_ID 447 final String hexStr = identityStr.substring(2); 448 return new IkeKeyIdIdentification(HexDump.hexStringToByteArray(hexStr)); 449 } else if (identityStr.startsWith("@@")) { 450 // RFC822 (USER_FQDN) 451 return new IkeRfc822AddrIdentification(identityStr.substring(2)); 452 } else if (identityStr.startsWith("@")) { 453 // FQDN 454 return new IkeFqdnIdentification(identityStr.substring(1)); 455 } else { 456 // RFC822 (USER_FQDN) 457 return new IkeRfc822AddrIdentification(identityStr); 458 } 459 } else if (InetAddresses.isNumericAddress(identityStr)) { 460 final InetAddress addr = InetAddresses.parseNumericAddress(identityStr); 461 if (addr instanceof Inet4Address) { 462 // IPv4 463 return new IkeIpv4AddrIdentification((Inet4Address) addr); 464 } else if (addr instanceof Inet6Address) { 465 // IPv6 466 return new IkeIpv6AddrIdentification((Inet6Address) addr); 467 } else { 468 throw new IllegalArgumentException("IP version not supported"); 469 } 470 } else { 471 if (identityStr.contains(":")) { 472 // KEY_ID 473 return new IkeKeyIdIdentification(identityStr.getBytes()); 474 } else { 475 // FQDN 476 return new IkeFqdnIdentification(identityStr); 477 } 478 } 479 } 480 getRoutesFromTrafficSelectors( List<IkeTrafficSelector> trafficSelectors)481 static Collection<RouteInfo> getRoutesFromTrafficSelectors( 482 List<IkeTrafficSelector> trafficSelectors) { 483 final HashSet<RouteInfo> routes = new HashSet<>(); 484 485 for (final IkeTrafficSelector selector : trafficSelectors) { 486 for (final IpPrefix prefix : 487 new IpRange(selector.startingAddress, selector.endingAddress).asIpPrefixes()) { 488 routes.add(new RouteInfo(prefix, null /*gateway*/, null /*iface*/, 489 RouteInfo.RTN_UNICAST)); 490 } 491 } 492 493 return routes; 494 } 495 } 496