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.SystemApi;
26 import android.net.LinkAddress;
27 
28 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Address;
29 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Dhcp;
30 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Dns;
31 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Netmask;
32 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Address;
33 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Dns;
34 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.TunnelModeChildConfigAttribute;
35 
36 import java.net.Inet4Address;
37 import java.net.Inet6Address;
38 import java.net.InetAddress;
39 import java.util.Arrays;
40 import java.util.Collections;
41 import java.util.LinkedList;
42 import java.util.List;
43 import java.util.Objects;
44 
45 /**
46  * TunnelModeChildSessionParams represents proposed configurations for negotiating a tunnel mode
47  * Child Session.
48  *
49  * @hide
50  */
51 @SystemApi
52 public final class TunnelModeChildSessionParams extends ChildSessionParams {
53     @NonNull private final TunnelModeChildConfigAttribute[] mConfigRequests;
54 
TunnelModeChildSessionParams( @onNull IkeTrafficSelector[] inboundTs, @NonNull IkeTrafficSelector[] outboundTs, @NonNull ChildSaProposal[] proposals, @NonNull TunnelModeChildConfigAttribute[] configRequests, int hardLifetimeSec, int softLifetimeSec)55     private TunnelModeChildSessionParams(
56             @NonNull IkeTrafficSelector[] inboundTs,
57             @NonNull IkeTrafficSelector[] outboundTs,
58             @NonNull ChildSaProposal[] proposals,
59             @NonNull TunnelModeChildConfigAttribute[] configRequests,
60             int hardLifetimeSec,
61             int softLifetimeSec) {
62         super(
63                 inboundTs,
64                 outboundTs,
65                 proposals,
66                 hardLifetimeSec,
67                 softLifetimeSec,
68                 false /*isTransport*/);
69         mConfigRequests = configRequests;
70     }
71 
72     /** @hide */
getConfigurationAttributesInternal()73     public TunnelModeChildConfigAttribute[] getConfigurationAttributesInternal() {
74         return mConfigRequests;
75     }
76 
77     /** Retrieves the list of Configuration Requests */
78     @NonNull
getConfigurationRequests()79     public List<TunnelModeChildConfigRequest> getConfigurationRequests() {
80         return Collections.unmodifiableList(Arrays.asList(mConfigRequests));
81     }
82 
83     /** Represents a tunnel mode child session configuration request type */
84     public interface TunnelModeChildConfigRequest {}
85 
86     /** Represents an IPv4 Internal Address request */
87     public interface ConfigRequestIpv4Address extends TunnelModeChildConfigRequest {
88         /**
89          * Retrieves the requested internal IPv4 address
90          *
91          * @return The requested IPv4 address, or null if no specific internal address was requested
92          */
93         @Nullable
getAddress()94         Inet4Address getAddress();
95     }
96 
97     /** Represents an IPv4 DHCP server request */
98     public interface ConfigRequestIpv4DhcpServer extends TunnelModeChildConfigRequest {}
99 
100     /** Represents an IPv4 DNS Server request */
101     public interface ConfigRequestIpv4DnsServer extends TunnelModeChildConfigRequest {}
102 
103     /** Represents an IPv4 Netmask request */
104     public interface ConfigRequestIpv4Netmask extends TunnelModeChildConfigRequest {}
105 
106     /** Represents an IPv6 Internal Address request */
107     public interface ConfigRequestIpv6Address extends TunnelModeChildConfigRequest {
108         /**
109          * Retrieves the requested internal IPv6 address
110          *
111          * @return The requested IPv6 address, or null if no specific internal address was requested
112          */
113         @Nullable
getAddress()114         Inet6Address getAddress();
115 
116         /**
117          * Retrieves the prefix length
118          *
119          * @return The requested prefix length, or -1 if no specific IPv6 address was requested
120          */
getPrefixLength()121         int getPrefixLength();
122     }
123 
124     /** Represents an IPv6 DNS Server request */
125     public interface ConfigRequestIpv6DnsServer extends TunnelModeChildConfigRequest {}
126 
127     /** This class can be used to incrementally construct a {@link TunnelModeChildSessionParams}. */
128     public static final class Builder extends ChildSessionParams.Builder {
129         private static final int IPv4_DEFAULT_PREFIX_LEN = 32;
130 
131         private boolean mHasIp4AddressRequest;
132         private List<TunnelModeChildConfigAttribute> mConfigRequestList;
133 
134         /** Create a Builder for negotiating a transport mode Child Session. */
Builder()135         public Builder() {
136             super();
137             mHasIp4AddressRequest = false;
138             mConfigRequestList = new LinkedList<>();
139         }
140 
141         /**
142          * Adds an Child SA proposal to the {@link TunnelModeChildSessionParams} being built.
143          *
144          * @param proposal Child SA proposal.
145          * @return Builder this, to facilitate chaining.
146          */
147         @NonNull
addSaProposal(@onNull ChildSaProposal proposal)148         public Builder addSaProposal(@NonNull ChildSaProposal proposal) {
149             if (proposal == null) {
150                 throw new NullPointerException("Required argument not provided");
151             }
152 
153             addProposal(proposal);
154             return this;
155         }
156 
157         /**
158          * Adds an inbound {@link IkeTrafficSelector} to the {@link TunnelModeChildSessionParams}
159          * being built.
160          *
161          * <p>This method allows callers to limit the inbound traffic transmitted over the Child
162          * Session to the given range. The IKE server may further narrow the range. Callers should
163          * refer to {@link ChildSessionConfiguration} for the negotiated traffic selectors.
164          *
165          * <p>If no inbound {@link IkeTrafficSelector} is provided, a default value will be used
166          * that covers all IP addresses and ports.
167          *
168          * @param trafficSelector the inbound {@link IkeTrafficSelector}.
169          * @return Builder this, to facilitate chaining.
170          */
171         @NonNull
addInboundTrafficSelectors(@onNull IkeTrafficSelector trafficSelector)172         public Builder addInboundTrafficSelectors(@NonNull IkeTrafficSelector trafficSelector) {
173             Objects.requireNonNull(trafficSelector, "Required argument not provided");
174             addInboundTs(trafficSelector);
175             return this;
176         }
177 
178         /**
179          * Adds an outbound {@link IkeTrafficSelector} to the {@link TunnelModeChildSessionParams}
180          * being built.
181          *
182          * <p>This method allows callers to limit the outbound traffic transmitted over the Child
183          * Session to the given range. The IKE server may further narrow the range. Callers should
184          * refer to {@link ChildSessionConfiguration} for the negotiated traffic selectors.
185          *
186          * <p>If no outbound {@link IkeTrafficSelector} is provided, a default value will be used
187          * that covers all IP addresses and ports.
188          *
189          * @param trafficSelector the outbound {@link IkeTrafficSelector}.
190          * @return Builder this, to facilitate chaining.
191          */
192         @NonNull
addOutboundTrafficSelectors(@onNull IkeTrafficSelector trafficSelector)193         public Builder addOutboundTrafficSelectors(@NonNull IkeTrafficSelector trafficSelector) {
194             Objects.requireNonNull(trafficSelector, "Required argument not provided");
195             addOutboundTs(trafficSelector);
196             return this;
197         }
198 
199         /**
200          * Sets hard and soft lifetimes.
201          *
202          * <p>Lifetimes will not be negotiated with the remote IKE server.
203          *
204          * @param hardLifetimeSeconds number of seconds after which Child SA will expire. Defaults
205          *     to 7200 seconds (2 hours). Considering IPsec packet lifetime, IKE library requires
206          *     hard lifetime to be a value from 300 seconds (5 minutes) to 14400 seconds (4 hours),
207          *     inclusive.
208          * @param softLifetimeSeconds number of seconds after which Child SA will request rekey.
209          *     Defaults to 3600 seconds (1 hour). MUST be at least 120 seconds (2 minutes), and at
210          *     least 60 seconds (1 minute) shorter than the hard lifetime.
211          */
212         @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)213         public Builder setLifetimeSeconds(
214                 @IntRange(
215                                 from = CHILD_HARD_LIFETIME_SEC_MINIMUM,
216                                 to = CHILD_HARD_LIFETIME_SEC_MAXIMUM)
217                         int hardLifetimeSeconds,
218                 @IntRange(
219                                 from = CHILD_SOFT_LIFETIME_SEC_MINIMUM,
220                                 to = CHILD_HARD_LIFETIME_SEC_MAXIMUM)
221                         int softLifetimeSeconds) {
222             validateAndSetLifetime(hardLifetimeSeconds, softLifetimeSeconds);
223             mHardLifetimeSec = hardLifetimeSeconds;
224             mSoftLifetimeSec = softLifetimeSeconds;
225             return this;
226         }
227 
228         /**
229          * Adds an internal IP address request to the {@link TunnelModeChildSessionParams} being
230          * built.
231          *
232          * @param addressFamily the address family. Only {@link OsConstants.AF_INET} and {@link
233          *     OsConstants.AF_INET6} are allowed.
234          * @return Builder this, to facilitate chaining.
235          */
236         @NonNull
addInternalAddressRequest(int addressFamily)237         public Builder addInternalAddressRequest(int addressFamily) {
238             if (addressFamily == AF_INET) {
239                 mHasIp4AddressRequest = true;
240                 mConfigRequestList.add(new ConfigAttributeIpv4Address());
241                 return this;
242             } else if (addressFamily == AF_INET6) {
243                 mConfigRequestList.add(new ConfigAttributeIpv6Address());
244                 return this;
245             } else {
246                 throw new IllegalArgumentException("Invalid address family: " + addressFamily);
247             }
248         }
249 
250         /**
251          * Adds a specific internal IPv4 address request to the {@link TunnelModeChildSessionParams}
252          * being built.
253          *
254          * @param address the requested IPv4 address.
255          * @return Builder this, to facilitate chaining.
256          */
257         @NonNull
addInternalAddressRequest(@onNull Inet4Address address)258         public Builder addInternalAddressRequest(@NonNull Inet4Address address) {
259             if (address == null) {
260                 throw new NullPointerException("Required argument not provided");
261             }
262 
263             mHasIp4AddressRequest = true;
264             mConfigRequestList.add(new ConfigAttributeIpv4Address((Inet4Address) address));
265             return this;
266         }
267 
268         /**
269          * Adds a specific internal IPv6 address request to the {@link TunnelModeChildSessionParams}
270          * being built.
271          *
272          * @param address the requested IPv6 address.
273          * @param prefixLen length of the IPv6 address prefix length.
274          * @return Builder this, to facilitate chaining.
275          */
276         @NonNull
addInternalAddressRequest(@onNull Inet6Address address, int prefixLen)277         public Builder addInternalAddressRequest(@NonNull Inet6Address address, int prefixLen) {
278             if (address == null) {
279                 throw new NullPointerException("Required argument not provided");
280             }
281 
282             mConfigRequestList.add(
283                     new ConfigAttributeIpv6Address(new LinkAddress(address, prefixLen)));
284             return this;
285         }
286 
287         /**
288          * Adds an internal DNS server request to the {@link TunnelModeChildSessionParams} being
289          * built.
290          *
291          * @param addressFamily the address family. Only {@link OsConstants.AF_INET} and {@link
292          *     OsConstants.AF_INET6} are allowed.
293          * @return Builder this, to facilitate chaining.
294          */
295         @NonNull
addInternalDnsServerRequest(int addressFamily)296         public Builder addInternalDnsServerRequest(int addressFamily) {
297             if (addressFamily == AF_INET) {
298                 mConfigRequestList.add(new ConfigAttributeIpv4Dns());
299                 return this;
300             } else if (addressFamily == AF_INET6) {
301                 mConfigRequestList.add(new ConfigAttributeIpv6Dns());
302                 return this;
303             } else {
304                 throw new IllegalArgumentException("Invalid address family: " + addressFamily);
305             }
306         }
307 
308         /**
309          * Adds a specific internal DNS server request to the {@link TunnelModeChildSessionParams}
310          * being built.
311          *
312          * @param address the requested DNS server address.
313          * @return Builder this, to facilitate chaining.
314          * @hide
315          */
316         @NonNull
addInternalDnsServerRequest(@onNull InetAddress address)317         public Builder addInternalDnsServerRequest(@NonNull InetAddress address) {
318             if (address == null) {
319                 throw new NullPointerException("Required argument not provided");
320             }
321 
322             if (address instanceof Inet4Address) {
323                 mConfigRequestList.add(new ConfigAttributeIpv4Dns((Inet4Address) address));
324                 return this;
325             } else if (address instanceof Inet6Address) {
326                 mConfigRequestList.add(new ConfigAttributeIpv6Dns((Inet6Address) address));
327                 return this;
328             } else {
329                 throw new IllegalArgumentException("Invalid address " + address);
330             }
331         }
332 
333         /**
334          * Adds internal DHCP server requests to the {@link TunnelModeChildSessionParams} being
335          * built.
336          *
337          * <p>Only DHCPv4 server requests are supported.
338          *
339          * @param addressFamily the address family. Only {@link OsConstants.AF_INET} is allowed.
340          * @return Builder this, to facilitate chaining.
341          */
342         @NonNull
addInternalDhcpServerRequest(int addressFamily)343         public Builder addInternalDhcpServerRequest(int addressFamily) {
344             if (addressFamily == AF_INET) {
345                 mConfigRequestList.add(new ConfigAttributeIpv4Dhcp());
346                 return this;
347             } else {
348                 throw new IllegalArgumentException("Invalid address family: " + addressFamily);
349             }
350         }
351 
352         /**
353          * Adds a specific internal DHCP server request to the {@link TunnelModeChildSessionParams}
354          * being built.
355          *
356          * <p>Only DHCPv4 server requests are supported.
357          *
358          * @param address the requested DHCP server address.
359          * @return Builder this, to facilitate chaining.
360          * @hide
361          */
362         @NonNull
addInternalDhcpServerRequest(@onNull InetAddress address)363         public Builder addInternalDhcpServerRequest(@NonNull InetAddress address) {
364             if (address == null) {
365                 throw new NullPointerException("Required argument not provided");
366             }
367 
368             if (address instanceof Inet4Address) {
369                 mConfigRequestList.add(new ConfigAttributeIpv4Dhcp((Inet4Address) address));
370                 return this;
371             } else {
372                 throw new IllegalArgumentException("Invalid address " + address);
373             }
374         }
375 
376         /**
377          * Validates and builds the {@link TunnelModeChildSessionParams}.
378          *
379          * @return the validated {@link TunnelModeChildSessionParams}.
380          */
381         @NonNull
build()382         public TunnelModeChildSessionParams build() {
383             addDefaultTsIfNotConfigured();
384             validateOrThrow();
385 
386             if (mHasIp4AddressRequest) {
387                 mConfigRequestList.add(new ConfigAttributeIpv4Netmask());
388             }
389 
390             return new TunnelModeChildSessionParams(
391                     mInboundTsList.toArray(new IkeTrafficSelector[0]),
392                     mOutboundTsList.toArray(new IkeTrafficSelector[0]),
393                     mSaProposalList.toArray(new ChildSaProposal[0]),
394                     mConfigRequestList.toArray(new TunnelModeChildConfigAttribute[0]),
395                     mHardLifetimeSec,
396                     mSoftLifetimeSec);
397         }
398     }
399 }
400