blob: cb8268cf51134348ee03f4e369c8a24f0d94ef55 [file] [log] [blame]
/*
* 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()]));
}
}
}