Loading core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java +171 −3 Original line number Diff line number Diff line Loading @@ -16,17 +16,34 @@ package android.net.vcn.persistablebundleutils; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.InetAddresses; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeTrafficSelector; import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Address; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netmask; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer; import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest; import android.os.PersistableBundle; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.util.ArrayList; import java.util.List; import java.util.Objects; Loading @@ -37,15 +54,99 @@ import java.util.Objects; */ @VisibleForTesting(visibility = Visibility.PRIVATE) public final class TunnelModeChildSessionParamsUtils { private static final String TAG = TunnelModeChildSessionParamsUtils.class.getSimpleName(); private static final String INBOUND_TS_KEY = "INBOUND_TS_KEY"; private static final String OUTBOUND_TS_KEY = "OUTBOUND_TS_KEY"; private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY"; private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY"; private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY"; private static final String CONFIG_REQUESTS_KEY = "CONFIG_REQUESTS_KEY"; private static class ConfigRequest { private static final int TYPE_IPV4_ADDRESS = 1; private static final int TYPE_IPV6_ADDRESS = 2; private static final int TYPE_IPV4_DNS = 3; private static final int TYPE_IPV6_DNS = 4; private static final int TYPE_IPV4_DHCP = 5; private static final int TYPE_IPV4_NETMASK = 6; private static final String TYPE_KEY = "type"; private static final String VALUE_KEY = "address"; private static final String IP6_PREFIX_LEN = "ip6PrefixLen"; private static final int PREFIX_LEN_UNUSED = -1; public final int type; public final int ip6PrefixLen; // Null when it is an empty request @Nullable public final InetAddress address; ConfigRequest(TunnelModeChildConfigRequest config) { int prefixLen = PREFIX_LEN_UNUSED; if (config instanceof ConfigRequestIpv4Address) { type = TYPE_IPV4_ADDRESS; address = ((ConfigRequestIpv4Address) config).getAddress(); } else if (config instanceof ConfigRequestIpv6Address) { type = TYPE_IPV6_ADDRESS; address = ((ConfigRequestIpv6Address) config).getAddress(); if (address != null) { prefixLen = ((ConfigRequestIpv6Address) config).getPrefixLength(); } } else if (config instanceof ConfigRequestIpv4DnsServer) { type = TYPE_IPV4_DNS; address = null; } else if (config instanceof ConfigRequestIpv6DnsServer) { type = TYPE_IPV6_DNS; address = null; } else if (config instanceof ConfigRequestIpv4DhcpServer) { type = TYPE_IPV4_DHCP; address = null; } else if (config instanceof ConfigRequestIpv4Netmask) { type = TYPE_IPV4_NETMASK; address = null; } else { throw new IllegalStateException("Unknown TunnelModeChildConfigRequest"); } ip6PrefixLen = prefixLen; } ConfigRequest(PersistableBundle in) { Objects.requireNonNull(in, "PersistableBundle was null"); type = in.getInt(TYPE_KEY); ip6PrefixLen = in.getInt(IP6_PREFIX_LEN); String addressStr = in.getString(VALUE_KEY); if (addressStr == null) { address = null; } else { address = InetAddresses.parseNumericAddress(addressStr); } } @NonNull public PersistableBundle toPersistableBundle() { final PersistableBundle result = new PersistableBundle(); result.putInt(TYPE_KEY, type); result.putInt(IP6_PREFIX_LEN, ip6PrefixLen); if (address != null) { result.putString(VALUE_KEY, address.getHostAddress()); } return result; } } /** Serializes a TunnelModeChildSessionParams to a PersistableBundle. */ @NonNull public static PersistableBundle toPersistableBundle(TunnelModeChildSessionParams params) { public static PersistableBundle toPersistableBundle( @NonNull TunnelModeChildSessionParams params) { final PersistableBundle result = new PersistableBundle(); final PersistableBundle saProposalBundle = Loading @@ -68,7 +169,13 @@ public final class TunnelModeChildSessionParamsUtils { result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds()); result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds()); // TODO: b/163604823 Support serializing configuration requests. final List<ConfigRequest> reqList = new ArrayList<>(); for (TunnelModeChildConfigRequest req : params.getConfigurationRequests()) { reqList.add(new ConfigRequest(req)); } final PersistableBundle configReqListBundle = PersistableBundleUtils.fromList(reqList, ConfigRequest::toPersistableBundle); result.putPersistableBundle(CONFIG_REQUESTS_KEY, configReqListBundle); return result; } Loading Loading @@ -109,8 +216,69 @@ public final class TunnelModeChildSessionParamsUtils { builder.setLifetimeSeconds( in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY)); final PersistableBundle configReqListBundle = in.getPersistableBundle(CONFIG_REQUESTS_KEY); Objects.requireNonNull(configReqListBundle, "Config request list was null"); final List<ConfigRequest> reqList = PersistableBundleUtils.toList(configReqListBundle, ConfigRequest::new); // TODO: b/163604823 Support deserializing configuration requests. boolean hasIpv4AddressReq = false; boolean hasIpv4NetmaskReq = false; for (ConfigRequest req : reqList) { switch (req.type) { case ConfigRequest.TYPE_IPV4_ADDRESS: hasIpv4AddressReq = true; if (req.address == null) { builder.addInternalAddressRequest(AF_INET); } else { builder.addInternalAddressRequest((Inet4Address) req.address); } break; case ConfigRequest.TYPE_IPV6_ADDRESS: if (req.address == null) { builder.addInternalAddressRequest(AF_INET6); } else { builder.addInternalAddressRequest( (Inet6Address) req.address, req.ip6PrefixLen); } break; case ConfigRequest.TYPE_IPV4_NETMASK: // Do not need to set netmask because it will be automatically set by the // builder when an IPv4 internal address request is set. hasIpv4NetmaskReq = true; break; case ConfigRequest.TYPE_IPV4_DNS: if (req.address != null) { Log.w(TAG, "Requesting a specific IPv4 DNS server is unsupported"); } builder.addInternalDnsServerRequest(AF_INET); break; case ConfigRequest.TYPE_IPV6_DNS: if (req.address != null) { Log.w(TAG, "Requesting a specific IPv6 DNS server is unsupported"); } builder.addInternalDnsServerRequest(AF_INET6); break; case ConfigRequest.TYPE_IPV4_DHCP: if (req.address != null) { Log.w(TAG, "Requesting a specific IPv4 DHCP server is unsupported"); } builder.addInternalDhcpServerRequest(AF_INET); break; default: throw new IllegalArgumentException( "Unrecognized config request type: " + req.type); } } if (hasIpv4AddressReq != hasIpv4NetmaskReq) { Log.w( TAG, String.format( "Expect IPv4 address request and IPv4 netmask request either both" + " exist or both absent, but found hasIpv4AddressReq exists? %b," + " hasIpv4AddressReq exists? %b, ", hasIpv4AddressReq, hasIpv4NetmaskReq)); } return builder.build(); } Loading tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java +26 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.net.vcn.persistablebundleutils; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import static org.junit.Assert.assertEquals; import android.net.InetAddresses; Loading @@ -30,6 +33,8 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import java.net.Inet4Address; import java.net.Inet6Address; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) Loading Loading @@ -88,4 +93,25 @@ public class TunnelModeChildSessionParamsUtilsTest { createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build(); verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); } @Test public void testSetConfigRequestsEncodeDecodeIsLossless() throws Exception { final int ipv6PrefixLen = 64; final Inet4Address ipv4Address = (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100"); final Inet6Address ipv6Address = (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1"); final TunnelModeChildSessionParams sessionParams = createBuilderMinimum() .addInternalAddressRequest(AF_INET) .addInternalAddressRequest(AF_INET6) .addInternalAddressRequest(ipv4Address) .addInternalAddressRequest(ipv6Address, ipv6PrefixLen) .addInternalDnsServerRequest(AF_INET) .addInternalDnsServerRequest(AF_INET6) .addInternalDhcpServerRequest(AF_INET) .build(); verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); } } Loading
core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java +171 −3 Original line number Diff line number Diff line Loading @@ -16,17 +16,34 @@ package android.net.vcn.persistablebundleutils; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.InetAddresses; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeTrafficSelector; import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Address; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netmask; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address; import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer; import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest; import android.os.PersistableBundle; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.util.ArrayList; import java.util.List; import java.util.Objects; Loading @@ -37,15 +54,99 @@ import java.util.Objects; */ @VisibleForTesting(visibility = Visibility.PRIVATE) public final class TunnelModeChildSessionParamsUtils { private static final String TAG = TunnelModeChildSessionParamsUtils.class.getSimpleName(); private static final String INBOUND_TS_KEY = "INBOUND_TS_KEY"; private static final String OUTBOUND_TS_KEY = "OUTBOUND_TS_KEY"; private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY"; private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY"; private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY"; private static final String CONFIG_REQUESTS_KEY = "CONFIG_REQUESTS_KEY"; private static class ConfigRequest { private static final int TYPE_IPV4_ADDRESS = 1; private static final int TYPE_IPV6_ADDRESS = 2; private static final int TYPE_IPV4_DNS = 3; private static final int TYPE_IPV6_DNS = 4; private static final int TYPE_IPV4_DHCP = 5; private static final int TYPE_IPV4_NETMASK = 6; private static final String TYPE_KEY = "type"; private static final String VALUE_KEY = "address"; private static final String IP6_PREFIX_LEN = "ip6PrefixLen"; private static final int PREFIX_LEN_UNUSED = -1; public final int type; public final int ip6PrefixLen; // Null when it is an empty request @Nullable public final InetAddress address; ConfigRequest(TunnelModeChildConfigRequest config) { int prefixLen = PREFIX_LEN_UNUSED; if (config instanceof ConfigRequestIpv4Address) { type = TYPE_IPV4_ADDRESS; address = ((ConfigRequestIpv4Address) config).getAddress(); } else if (config instanceof ConfigRequestIpv6Address) { type = TYPE_IPV6_ADDRESS; address = ((ConfigRequestIpv6Address) config).getAddress(); if (address != null) { prefixLen = ((ConfigRequestIpv6Address) config).getPrefixLength(); } } else if (config instanceof ConfigRequestIpv4DnsServer) { type = TYPE_IPV4_DNS; address = null; } else if (config instanceof ConfigRequestIpv6DnsServer) { type = TYPE_IPV6_DNS; address = null; } else if (config instanceof ConfigRequestIpv4DhcpServer) { type = TYPE_IPV4_DHCP; address = null; } else if (config instanceof ConfigRequestIpv4Netmask) { type = TYPE_IPV4_NETMASK; address = null; } else { throw new IllegalStateException("Unknown TunnelModeChildConfigRequest"); } ip6PrefixLen = prefixLen; } ConfigRequest(PersistableBundle in) { Objects.requireNonNull(in, "PersistableBundle was null"); type = in.getInt(TYPE_KEY); ip6PrefixLen = in.getInt(IP6_PREFIX_LEN); String addressStr = in.getString(VALUE_KEY); if (addressStr == null) { address = null; } else { address = InetAddresses.parseNumericAddress(addressStr); } } @NonNull public PersistableBundle toPersistableBundle() { final PersistableBundle result = new PersistableBundle(); result.putInt(TYPE_KEY, type); result.putInt(IP6_PREFIX_LEN, ip6PrefixLen); if (address != null) { result.putString(VALUE_KEY, address.getHostAddress()); } return result; } } /** Serializes a TunnelModeChildSessionParams to a PersistableBundle. */ @NonNull public static PersistableBundle toPersistableBundle(TunnelModeChildSessionParams params) { public static PersistableBundle toPersistableBundle( @NonNull TunnelModeChildSessionParams params) { final PersistableBundle result = new PersistableBundle(); final PersistableBundle saProposalBundle = Loading @@ -68,7 +169,13 @@ public final class TunnelModeChildSessionParamsUtils { result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds()); result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds()); // TODO: b/163604823 Support serializing configuration requests. final List<ConfigRequest> reqList = new ArrayList<>(); for (TunnelModeChildConfigRequest req : params.getConfigurationRequests()) { reqList.add(new ConfigRequest(req)); } final PersistableBundle configReqListBundle = PersistableBundleUtils.fromList(reqList, ConfigRequest::toPersistableBundle); result.putPersistableBundle(CONFIG_REQUESTS_KEY, configReqListBundle); return result; } Loading Loading @@ -109,8 +216,69 @@ public final class TunnelModeChildSessionParamsUtils { builder.setLifetimeSeconds( in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY)); final PersistableBundle configReqListBundle = in.getPersistableBundle(CONFIG_REQUESTS_KEY); Objects.requireNonNull(configReqListBundle, "Config request list was null"); final List<ConfigRequest> reqList = PersistableBundleUtils.toList(configReqListBundle, ConfigRequest::new); // TODO: b/163604823 Support deserializing configuration requests. boolean hasIpv4AddressReq = false; boolean hasIpv4NetmaskReq = false; for (ConfigRequest req : reqList) { switch (req.type) { case ConfigRequest.TYPE_IPV4_ADDRESS: hasIpv4AddressReq = true; if (req.address == null) { builder.addInternalAddressRequest(AF_INET); } else { builder.addInternalAddressRequest((Inet4Address) req.address); } break; case ConfigRequest.TYPE_IPV6_ADDRESS: if (req.address == null) { builder.addInternalAddressRequest(AF_INET6); } else { builder.addInternalAddressRequest( (Inet6Address) req.address, req.ip6PrefixLen); } break; case ConfigRequest.TYPE_IPV4_NETMASK: // Do not need to set netmask because it will be automatically set by the // builder when an IPv4 internal address request is set. hasIpv4NetmaskReq = true; break; case ConfigRequest.TYPE_IPV4_DNS: if (req.address != null) { Log.w(TAG, "Requesting a specific IPv4 DNS server is unsupported"); } builder.addInternalDnsServerRequest(AF_INET); break; case ConfigRequest.TYPE_IPV6_DNS: if (req.address != null) { Log.w(TAG, "Requesting a specific IPv6 DNS server is unsupported"); } builder.addInternalDnsServerRequest(AF_INET6); break; case ConfigRequest.TYPE_IPV4_DHCP: if (req.address != null) { Log.w(TAG, "Requesting a specific IPv4 DHCP server is unsupported"); } builder.addInternalDhcpServerRequest(AF_INET); break; default: throw new IllegalArgumentException( "Unrecognized config request type: " + req.type); } } if (hasIpv4AddressReq != hasIpv4NetmaskReq) { Log.w( TAG, String.format( "Expect IPv4 address request and IPv4 netmask request either both" + " exist or both absent, but found hasIpv4AddressReq exists? %b," + " hasIpv4AddressReq exists? %b, ", hasIpv4AddressReq, hasIpv4NetmaskReq)); } return builder.build(); } Loading
tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java +26 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.net.vcn.persistablebundleutils; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import static org.junit.Assert.assertEquals; import android.net.InetAddresses; Loading @@ -30,6 +33,8 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import java.net.Inet4Address; import java.net.Inet6Address; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) Loading Loading @@ -88,4 +93,25 @@ public class TunnelModeChildSessionParamsUtilsTest { createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build(); verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); } @Test public void testSetConfigRequestsEncodeDecodeIsLossless() throws Exception { final int ipv6PrefixLen = 64; final Inet4Address ipv4Address = (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100"); final Inet6Address ipv6Address = (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1"); final TunnelModeChildSessionParams sessionParams = createBuilderMinimum() .addInternalAddressRequest(AF_INET) .addInternalAddressRequest(AF_INET6) .addInternalAddressRequest(ipv4Address) .addInternalAddressRequest(ipv6Address, ipv6PrefixLen) .addInternalDnsServerRequest(AF_INET) .addInternalDnsServerRequest(AF_INET6) .addInternalDhcpServerRequest(AF_INET) .build(); verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); } }