| /* |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.net.ipsec.ike; |
| |
| import static android.system.OsConstants.AF_INET; |
| import static android.system.OsConstants.AF_INET6; |
| |
| import android.annotation.NonNull; |
| import android.net.LinkAddress; |
| |
| import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute; |
| import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Address; |
| import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Dhcp; |
| import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Dns; |
| import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Netmask; |
| import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Subnet; |
| import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Address; |
| import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Dns; |
| import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Subnet; |
| |
| import java.net.Inet4Address; |
| import java.net.Inet6Address; |
| import java.net.InetAddress; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| /** |
| * This class contains all user provided configuration options for negotiating a tunnel mode Child |
| * Session. |
| */ |
| public final class TunnelModeChildSessionOptions extends ChildSessionOptions { |
| private final ConfigAttribute[] mConfigRequests; |
| |
| private TunnelModeChildSessionOptions( |
| IkeTrafficSelector[] localTs, |
| IkeTrafficSelector[] remoteTs, |
| ChildSaProposal[] proposals, |
| ConfigAttribute[] configRequests) { |
| super(localTs, remoteTs, proposals, false /*isTransport*/); |
| mConfigRequests = configRequests; |
| } |
| |
| public ConfigAttribute[] getConfigurationRequests() { |
| return mConfigRequests; |
| } |
| |
| /** This class can be used to incrementally construct a TunnelModeChildSessionOptions. */ |
| public static final class Builder extends ChildSessionOptions.Builder { |
| private static final int IPv4_DEFAULT_PREFIX_LEN = 32; |
| |
| private boolean mHasIp4AddressRequest; |
| private List<ConfigAttribute> mConfigRequestList; |
| |
| /** Create a Builder for negotiating a transport mode Child Session. */ |
| public Builder() { |
| super(); |
| mHasIp4AddressRequest = false; |
| mConfigRequestList = new LinkedList<>(); |
| } |
| |
| /** |
| * Adds an Child SA proposal to TunnelModeChildSessionOptions being built. |
| * |
| * @param proposal Child SA proposal. |
| * @return Builder this, to facilitate chaining. |
| * @throws IllegalArgumentException if input proposal is not a Child SA proposal. |
| */ |
| public Builder addSaProposal(@NonNull ChildSaProposal proposal) { |
| validateAndAddSaProposal(proposal); |
| return this; |
| } |
| |
| /** |
| * Adds internal IP address requests to TunnelModeChildSessionOptions being built. |
| * |
| * @param addressFamily the address family. Only {@link OsConstants.AF_INET} and {@link |
| * OsConstants.AF_INET6} are allowed. |
| * @param numOfRequest the number of requests for this type of address. |
| * @return Builder this, to facilitate chaining. |
| */ |
| public Builder addInternalAddressRequest(int addressFamily, int numOfRequest) { |
| if (addressFamily == AF_INET) { |
| mHasIp4AddressRequest = true; |
| for (int i = 0; i < numOfRequest; i++) { |
| mConfigRequestList.add(new ConfigAttributeIpv4Address()); |
| } |
| return this; |
| } else if (addressFamily == AF_INET6) { |
| for (int i = 0; i < numOfRequest; i++) { |
| mConfigRequestList.add(new ConfigAttributeIpv6Address()); |
| } |
| return this; |
| } else { |
| throw new IllegalArgumentException("Invalid address family: " + addressFamily); |
| } |
| } |
| |
| /** |
| * Adds specific internal IP address request to TunnelModeChildSessionOptions being built. |
| * |
| * @param address the requested address. |
| * @param prefixLen length of the InetAddress prefix. When requesting an IPv4 address, |
| * prefixLen MUST be 32. |
| * @return Builder this, to facilitate chaining. |
| */ |
| public Builder addInternalAddressRequest(@NonNull InetAddress address, int prefixLen) { |
| if (address instanceof Inet4Address) { |
| if (prefixLen != IPv4_DEFAULT_PREFIX_LEN) { |
| throw new IllegalArgumentException("Invalid IPv4 prefix length: " + prefixLen); |
| } |
| mHasIp4AddressRequest = true; |
| mConfigRequestList.add(new ConfigAttributeIpv4Address((Inet4Address) address)); |
| return this; |
| } else if (address instanceof Inet6Address) { |
| mConfigRequestList.add( |
| new ConfigAttributeIpv6Address(new LinkAddress(address, prefixLen))); |
| return this; |
| } else { |
| throw new IllegalArgumentException("Invalid address " + address); |
| } |
| } |
| |
| /** |
| * Adds internal DNS server requests to TunnelModeChildSessionOptions being built. |
| * |
| * @param addressFamily the address family. Only {@link OsConstants.AF_INET} and {@link |
| * OsConstants.AF_INET6} are allowed. |
| * @param numOfRequest the number of requests for this type of address. |
| * @return Builder this, to facilitate chaining. |
| */ |
| public Builder addInternalDnsServerRequest(int addressFamily, int numOfRequest) { |
| if (addressFamily == AF_INET) { |
| for (int i = 0; i < numOfRequest; i++) { |
| mConfigRequestList.add(new ConfigAttributeIpv4Dns()); |
| } |
| return this; |
| } else if (addressFamily == AF_INET6) { |
| for (int i = 0; i < numOfRequest; i++) { |
| mConfigRequestList.add(new ConfigAttributeIpv6Dns()); |
| } |
| return this; |
| } else { |
| throw new IllegalArgumentException("Invalid address family: " + addressFamily); |
| } |
| } |
| |
| /** |
| * Adds internal DNS server requests to TunnelModeChildSessionOptions being built. |
| * |
| * @param address the requested DNS server address. |
| * @return Builder this, to facilitate chaining. |
| */ |
| public Builder addInternalDnsServerRequest(@NonNull InetAddress address) { |
| if (address instanceof Inet4Address) { |
| mConfigRequestList.add(new ConfigAttributeIpv4Dns((Inet4Address) address)); |
| return this; |
| } else if (address instanceof Inet6Address) { |
| mConfigRequestList.add(new ConfigAttributeIpv6Dns((Inet6Address) address)); |
| return this; |
| } else { |
| throw new IllegalArgumentException("Invalid address " + address); |
| } |
| } |
| |
| /** |
| * Adds internal subnet requests to TunnelModeChildSessionOptions being built. |
| * |
| * @param addressFamily the address family. Only {@link OsConstants.AF_INET} and {@link |
| * OsConstants.AF_INET6} are allowed. |
| * @param numOfRequest the number of requests for this type of address. |
| * @return Builder this, to facilitate chaining. |
| */ |
| public Builder addInternalSubnetRequest(int addressFamily, int numOfRequest) { |
| if (addressFamily == AF_INET) { |
| for (int i = 0; i < numOfRequest; i++) { |
| mConfigRequestList.add(new ConfigAttributeIpv4Subnet()); |
| } |
| return this; |
| } else if (addressFamily == AF_INET6) { |
| for (int i = 0; i < numOfRequest; i++) { |
| mConfigRequestList.add(new ConfigAttributeIpv6Subnet()); |
| } |
| return this; |
| } else { |
| throw new IllegalArgumentException("Invalid address family: " + addressFamily); |
| } |
| } |
| |
| /** |
| * Adds internal DHCP server requests to TunnelModeChildSessionOptions being built. |
| * |
| * <p>Only DHCP4 server requests are supported. |
| * |
| * @param addressFamily the address family. Only {@link OsConstants.AF_INET} is allowed. |
| * @param numOfRequest the number of requests for this type of address. |
| * @return Builder this, to facilitate chaining. |
| */ |
| public Builder addInternalDhcpServerRequest(int addressFamily, int numOfRequest) { |
| if (addressFamily == AF_INET) { |
| for (int i = 0; i < numOfRequest; i++) { |
| mConfigRequestList.add(new ConfigAttributeIpv4Dhcp()); |
| } |
| return this; |
| } else { |
| throw new IllegalArgumentException("Invalid address family: " + addressFamily); |
| } |
| } |
| |
| /** |
| * Adds internal DHCP server requests to TunnelModeChildSessionOptions being built. |
| * |
| * <p>Only DHCP4 server requests are supported. |
| * |
| * @param address the requested DHCP server address. |
| * @return Builder this, to facilitate chaining. |
| */ |
| public Builder addInternalDhcpServerRequest(@NonNull InetAddress address) { |
| if (address instanceof Inet4Address) { |
| mConfigRequestList.add(new ConfigAttributeIpv4Dhcp((Inet4Address) address)); |
| return this; |
| } else { |
| throw new IllegalArgumentException("Invalid address " + address); |
| } |
| } |
| |
| /** |
| * Validates, builds and returns the TunnelModeChildSessionOptions. |
| * |
| * @return the validated TunnelModeChildSessionOptions. |
| * @throws IllegalArgumentException if no Child SA proposal is provided. |
| */ |
| public TunnelModeChildSessionOptions build() { |
| validateOrThrow(); |
| |
| if (mHasIp4AddressRequest) { |
| mConfigRequestList.add(new ConfigAttributeIpv4Netmask()); |
| } |
| |
| return new TunnelModeChildSessionOptions( |
| mLocalTsList.toArray(new IkeTrafficSelector[mLocalTsList.size()]), |
| mRemoteTsList.toArray(new IkeTrafficSelector[mRemoteTsList.size()]), |
| mSaProposalList.toArray(new ChildSaProposal[mSaProposalList.size()]), |
| mConfigRequestList.toArray(new ConfigAttribute[mConfigRequestList.size()])); |
| } |
| } |
| } |