• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.SuppressLint;
26 import android.annotation.SystemApi;
27 import android.net.LinkAddress;
28 import android.os.PersistableBundle;
29 
30 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute;
31 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Address;
32 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Dhcp;
33 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Dns;
34 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Netmask;
35 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Address;
36 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Dns;
37 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.TunnelModeChildConfigAttribute;
38 import com.android.server.vcn.util.PersistableBundleUtils;
39 
40 import java.net.Inet4Address;
41 import java.net.Inet6Address;
42 import java.net.InetAddress;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Collections;
46 import java.util.List;
47 import java.util.Objects;
48 
49 /**
50  * TunnelModeChildSessionParams represents proposed configurations for negotiating a tunnel mode
51  * Child Session.
52  */
53 public final class TunnelModeChildSessionParams extends ChildSessionParams {
54     /** @hide */
55     private static final String CONFIG_ATTRIBUTES_KEY = "mConfigRequests";
56 
57     @NonNull private final TunnelModeChildConfigAttribute[] mConfigRequests;
58 
TunnelModeChildSessionParams( @onNull IkeTrafficSelector[] inboundTs, @NonNull IkeTrafficSelector[] outboundTs, @NonNull ChildSaProposal[] proposals, @NonNull TunnelModeChildConfigAttribute[] configRequests, int hardLifetimeSec, int softLifetimeSec)59     private TunnelModeChildSessionParams(
60             @NonNull IkeTrafficSelector[] inboundTs,
61             @NonNull IkeTrafficSelector[] outboundTs,
62             @NonNull ChildSaProposal[] proposals,
63             @NonNull TunnelModeChildConfigAttribute[] configRequests,
64             int hardLifetimeSec,
65             int softLifetimeSec) {
66         super(
67                 inboundTs,
68                 outboundTs,
69                 proposals,
70                 hardLifetimeSec,
71                 softLifetimeSec,
72                 false /*isTransport*/);
73         mConfigRequests = configRequests;
74     }
75 
76     /**
77      * Constructs this object by deserializing a PersistableBundle
78      *
79      * <p>Constructed TunnelModeChildSessionParams is guaranteed to be valid, as checked by the
80      * TunnelModeChildSessionParams.Builder
81      *
82      * @hide
83      */
84     @NonNull
fromPersistableBundle( @onNull PersistableBundle in)85     public static TunnelModeChildSessionParams fromPersistableBundle(
86             @NonNull PersistableBundle in) {
87         Objects.requireNonNull(in, "PersistableBundle not provided");
88 
89         TunnelModeChildSessionParams.Builder builder = new TunnelModeChildSessionParams.Builder();
90 
91         for (ChildSaProposal p : getProposalsFromPersistableBundle(in)) {
92             builder.addSaProposal(p);
93         }
94 
95         for (IkeTrafficSelector ts : getTsFromPersistableBundle(in, INBOUND_TS_KEY)) {
96             builder.addInboundTrafficSelectors(ts);
97         }
98 
99         for (IkeTrafficSelector ts : getTsFromPersistableBundle(in, OUTBOUND_TS_KEY)) {
100             builder.addOutboundTrafficSelectors(ts);
101         }
102 
103         builder.setLifetimeSeconds(
104                 in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY));
105 
106         PersistableBundle configAttributeBundle = in.getPersistableBundle(CONFIG_ATTRIBUTES_KEY);
107         List<ConfigAttribute> configReqList =
108                 PersistableBundleUtils.toList(
109                         configAttributeBundle, ConfigAttribute::fromPersistableBundle);
110 
111         for (ConfigAttribute a : configReqList) {
112             builder.addConfigRequest((TunnelModeChildConfigAttribute) a);
113         }
114 
115         return builder.build();
116     }
117 
118     /**
119      * Serializes this object to a PersistableBundle
120      *
121      * @hide
122      */
123     @Override
124     @NonNull
toPersistableBundle()125     public PersistableBundle toPersistableBundle() {
126         final PersistableBundle result = super.toPersistableBundle();
127 
128         PersistableBundle configAttributeBundle =
129                 PersistableBundleUtils.fromList(
130                         Arrays.asList(mConfigRequests),
131                         TunnelModeChildConfigAttribute::toPersistableBundle);
132         result.putPersistableBundle(CONFIG_ATTRIBUTES_KEY, configAttributeBundle);
133 
134         return result;
135     }
136 
137     /** @hide */
getConfigurationAttributesInternal()138     public TunnelModeChildConfigAttribute[] getConfigurationAttributesInternal() {
139         return mConfigRequests;
140     }
141 
142     /** Retrieves the list of Configuration Requests */
143     @NonNull
getConfigurationRequests()144     public List<TunnelModeChildConfigRequest> getConfigurationRequests() {
145         return Collections.unmodifiableList(Arrays.asList(mConfigRequests));
146     }
147 
148     /** Represents a tunnel mode child session configuration request type */
149     public interface TunnelModeChildConfigRequest {}
150 
151     /** Represents an IPv4 Internal Address request */
152     public interface ConfigRequestIpv4Address extends TunnelModeChildConfigRequest {
153         /**
154          * Retrieves the requested internal IPv4 address
155          *
156          * @return The requested IPv4 address, or null if no specific internal address was requested
157          */
158         @Nullable
getAddress()159         Inet4Address getAddress();
160     }
161 
162     /** Represents an IPv4 DHCP server request */
163     public interface ConfigRequestIpv4DhcpServer extends TunnelModeChildConfigRequest {}
164 
165     /** Represents an IPv4 DNS Server request */
166     public interface ConfigRequestIpv4DnsServer extends TunnelModeChildConfigRequest {}
167 
168     /** Represents an IPv4 Netmask request */
169     public interface ConfigRequestIpv4Netmask extends TunnelModeChildConfigRequest {}
170 
171     /** Represents an IPv6 Internal Address request */
172     public interface ConfigRequestIpv6Address extends TunnelModeChildConfigRequest {
173         /**
174          * Retrieves the requested internal IPv6 address
175          *
176          * @return The requested IPv6 address, or null if no specific internal address was requested
177          */
178         @Nullable
getAddress()179         Inet6Address getAddress();
180 
181         /**
182          * Retrieves the prefix length
183          *
184          * @return The requested prefix length, or -1 if no specific IPv6 address was requested
185          */
getPrefixLength()186         int getPrefixLength();
187     }
188 
189     /** Represents an IPv6 DNS Server request */
190     public interface ConfigRequestIpv6DnsServer extends TunnelModeChildConfigRequest {}
191 
192     @Override
hashCode()193     public int hashCode() {
194         return Objects.hash(super.hashCode(), Arrays.hashCode(mConfigRequests));
195     }
196 
197     @Override
equals(Object o)198     public boolean equals(Object o) {
199         if (!super.equals(o) || !(o instanceof ChildSessionParams)) {
200             return false;
201         }
202 
203         TunnelModeChildSessionParams other = (TunnelModeChildSessionParams) o;
204 
205         return Arrays.equals(mConfigRequests, other.mConfigRequests);
206     }
207 
208     /** This class can be used to incrementally construct a {@link TunnelModeChildSessionParams}. */
209     public static final class Builder extends ChildSessionParams.Builder {
210         private static final int IPv4_DEFAULT_PREFIX_LEN = 32;
211 
212         private boolean mHasIp4AddressRequest;
213         private boolean mHasIp4NetmaskRequest;
214         private List<TunnelModeChildConfigAttribute> mConfigRequestList = new ArrayList<>();
215 
216         /** Create a Builder for negotiating a tunnel mode Child Session. */
Builder()217         public Builder() {
218             super();
219             mHasIp4AddressRequest = false;
220             mHasIp4NetmaskRequest = false;
221         }
222 
223         /**
224          * Construct Builder from the {@link TunnelModeChildSessionParams} object.
225          *
226          * @param childParams the object this Builder will be constructed with.
227          */
Builder(@onNull TunnelModeChildSessionParams childParams)228         public Builder(@NonNull TunnelModeChildSessionParams childParams) {
229             super(childParams);
230             mConfigRequestList.addAll(Arrays.asList(childParams.mConfigRequests));
231             for (TunnelModeChildConfigAttribute config : mConfigRequestList) {
232                 if (config instanceof ConfigAttributeIpv4Address) {
233                     mHasIp4AddressRequest = true;
234                 } else if (config instanceof ConfigAttributeIpv4Netmask) {
235                     mHasIp4NetmaskRequest = true;
236                 }
237             }
238         }
239 
240         /**
241          * Adds an Child SA proposal to the {@link TunnelModeChildSessionParams} being built.
242          *
243          * @param proposal Child SA proposal.
244          * @return Builder this, to facilitate chaining.
245          * @deprecated Callers should use {@link #addChildSaProposal(ChildSaProposal)}. This method
246          *     is deprecated because its name does not match the input type.
247          * @hide
248          */
249         // The matching getter is defined in the super class. Please see
250         // {@link ChildSessionParams#getSaProposals}
251         @SuppressLint("MissingGetterMatchingBuilder")
252         @Deprecated
253         @SystemApi
254         @NonNull
addSaProposal(@onNull ChildSaProposal proposal)255         public Builder addSaProposal(@NonNull ChildSaProposal proposal) {
256             return addChildSaProposal(proposal);
257         }
258 
259         /**
260          * Adds an Child SA proposal to the {@link TunnelModeChildSessionParams} being built.
261          *
262          * @param proposal Child SA proposal.
263          * @return Builder this, to facilitate chaining.
264          */
265         // The matching getter is defined in the super class. Please see
266         // {@link ChildSessionParams#getChildSaProposals}
267         @SuppressLint("MissingGetterMatchingBuilder")
268         @NonNull
addChildSaProposal(@onNull ChildSaProposal proposal)269         public Builder addChildSaProposal(@NonNull ChildSaProposal proposal) {
270             if (proposal == null) {
271                 throw new NullPointerException("Required argument not provided");
272             }
273 
274             addProposal(proposal);
275             return this;
276         }
277 
278         /**
279          * Adds an inbound {@link IkeTrafficSelector} to the {@link TunnelModeChildSessionParams}
280          * being built.
281          *
282          * <p>This method allows callers to limit the inbound traffic transmitted over the Child
283          * Session to the given range. The IKE server may further narrow the range. Callers should
284          * refer to {@link ChildSessionConfiguration} for the negotiated traffic selectors.
285          *
286          * <p>If no inbound {@link IkeTrafficSelector} is provided, a default value will be used
287          * that covers all IP addresses and ports.
288          *
289          * @param trafficSelector the inbound {@link IkeTrafficSelector}.
290          * @return Builder this, to facilitate chaining.
291          */
292         // The matching getter is defined in the super class. Please see {@link
293         // ChildSessionParams#getInboundTrafficSelectors}
294         @SuppressLint("MissingGetterMatchingBuilder")
295         @NonNull
addInboundTrafficSelectors(@onNull IkeTrafficSelector trafficSelector)296         public Builder addInboundTrafficSelectors(@NonNull IkeTrafficSelector trafficSelector) {
297             Objects.requireNonNull(trafficSelector, "Required argument not provided");
298             addInboundTs(trafficSelector);
299             return this;
300         }
301 
302         /**
303          * Adds an outbound {@link IkeTrafficSelector} to the {@link TunnelModeChildSessionParams}
304          * being built.
305          *
306          * <p>This method allows callers to limit the outbound traffic transmitted over the Child
307          * Session to the given range. The IKE server may further narrow the range. Callers should
308          * refer to {@link ChildSessionConfiguration} for the negotiated traffic selectors.
309          *
310          * <p>If no outbound {@link IkeTrafficSelector} is provided, a default value will be used
311          * that covers all IP addresses and ports.
312          *
313          * @param trafficSelector the outbound {@link IkeTrafficSelector}.
314          * @return Builder this, to facilitate chaining.
315          */
316         // The matching getter is defined in the super class. Please see {@link
317         // ChildSessionParams#getOutboundTrafficSelectors}
318         @SuppressLint("MissingGetterMatchingBuilder")
319         @NonNull
addOutboundTrafficSelectors(@onNull IkeTrafficSelector trafficSelector)320         public Builder addOutboundTrafficSelectors(@NonNull IkeTrafficSelector trafficSelector) {
321             Objects.requireNonNull(trafficSelector, "Required argument not provided");
322             addOutboundTs(trafficSelector);
323             return this;
324         }
325 
326         /**
327          * Sets hard and soft lifetimes.
328          *
329          * <p>Lifetimes will not be negotiated with the remote IKE server.
330          *
331          * @param hardLifetimeSeconds number of seconds after which Child SA will expire. Defaults
332          *     to 7200 seconds (2 hours). Considering IPsec packet lifetime, IKE library requires
333          *     hard lifetime to be a value from 300 seconds (5 minutes) to 14400 seconds (4 hours),
334          *     inclusive.
335          * @param softLifetimeSeconds number of seconds after which Child SA will request rekey.
336          *     Defaults to 3600 seconds (1 hour). MUST be at least 120 seconds (2 minutes), and at
337          *     least 60 seconds (1 minute) shorter than the hard lifetime.
338          */
339         // The matching getters are defined in the super class. Please see {@link
340         // ChildSessionParams#getHardLifetimeSeconds and {@link
341         // ChildSessionParams#getSoftLifetimeSeconds}
342         @SuppressLint("MissingGetterMatchingBuilder")
343         @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)344         public Builder setLifetimeSeconds(
345                 @IntRange(
346                                 from = CHILD_HARD_LIFETIME_SEC_MINIMUM,
347                                 to = CHILD_HARD_LIFETIME_SEC_MAXIMUM)
348                         int hardLifetimeSeconds,
349                 @IntRange(
350                                 from = CHILD_SOFT_LIFETIME_SEC_MINIMUM,
351                                 to = CHILD_HARD_LIFETIME_SEC_MAXIMUM)
352                         int softLifetimeSeconds) {
353             validateAndSetLifetime(hardLifetimeSeconds, softLifetimeSeconds);
354             mHardLifetimeSec = hardLifetimeSeconds;
355             mSoftLifetimeSec = softLifetimeSeconds;
356             return this;
357         }
358 
359         /**
360          * Adds an internal IP address request to the {@link TunnelModeChildSessionParams} being
361          * built.
362          *
363          * @param addressFamily the address family. Only {@code AF_INET} and {@code AF_INET6} are
364          *     allowed
365          * @return Builder this, to facilitate chaining.
366          */
367         // #getConfigurationRequests has been defined for callers to retrieve internal address
368         // requests
369         @SuppressLint("MissingGetterMatchingBuilder")
370         @NonNull
addInternalAddressRequest(int addressFamily)371         public Builder addInternalAddressRequest(int addressFamily) {
372             if (addressFamily == AF_INET) {
373                 mHasIp4AddressRequest = true;
374                 mConfigRequestList.add(new ConfigAttributeIpv4Address());
375                 return this;
376             } else if (addressFamily == AF_INET6) {
377                 mConfigRequestList.add(new ConfigAttributeIpv6Address());
378                 return this;
379             } else {
380                 throw new IllegalArgumentException("Invalid address family: " + addressFamily);
381             }
382         }
383 
384         /**
385          * Adds a specific internal IPv4 address request to the {@link TunnelModeChildSessionParams}
386          * being built.
387          *
388          * @param address the requested IPv4 address.
389          * @return Builder this, to facilitate chaining.
390          */
391         // #getConfigurationRequests has been defined for callers to retrieve internal address
392         // requests
393         @SuppressLint("MissingGetterMatchingBuilder")
394         @NonNull
addInternalAddressRequest(@onNull Inet4Address address)395         public Builder addInternalAddressRequest(@NonNull Inet4Address address) {
396             if (address == null) {
397                 throw new NullPointerException("Required argument not provided");
398             }
399 
400             mHasIp4AddressRequest = true;
401             mConfigRequestList.add(new ConfigAttributeIpv4Address((Inet4Address) address));
402             return this;
403         }
404 
405         /**
406          * Adds a specific internal IPv6 address request to the {@link TunnelModeChildSessionParams}
407          * being built.
408          *
409          * @param address the requested IPv6 address.
410          * @param prefixLen length of the IPv6 address prefix length.
411          * @return Builder this, to facilitate chaining.
412          */
413         // #getConfigurationRequests has been defined for callers to retrieve internal address
414         // requests
415         @SuppressLint("MissingGetterMatchingBuilder")
416         @NonNull
addInternalAddressRequest(@onNull Inet6Address address, int prefixLen)417         public Builder addInternalAddressRequest(@NonNull Inet6Address address, int prefixLen) {
418             if (address == null) {
419                 throw new NullPointerException("Required argument not provided");
420             }
421 
422             mConfigRequestList.add(
423                     new ConfigAttributeIpv6Address(new LinkAddress(address, prefixLen)));
424             return this;
425         }
426 
427         /**
428          * Adds an internal DNS server request to the {@link TunnelModeChildSessionParams} being
429          * built.
430          *
431          * @param addressFamily the address family. Only {@code AF_INET} and {@code AF_INET6} are
432          *     allowed
433          * @return Builder this, to facilitate chaining.
434          */
435         // #getConfigurationRequests has been defined for callers to retrieve internal DNS server
436         // requests
437         @SuppressLint("MissingGetterMatchingBuilder")
438         @NonNull
addInternalDnsServerRequest(int addressFamily)439         public Builder addInternalDnsServerRequest(int addressFamily) {
440             if (addressFamily == AF_INET) {
441                 mConfigRequestList.add(new ConfigAttributeIpv4Dns());
442                 return this;
443             } else if (addressFamily == AF_INET6) {
444                 mConfigRequestList.add(new ConfigAttributeIpv6Dns());
445                 return this;
446             } else {
447                 throw new IllegalArgumentException("Invalid address family: " + addressFamily);
448             }
449         }
450 
451         /**
452          * Adds a specific internal DNS server request to the {@link TunnelModeChildSessionParams}
453          * being built.
454          *
455          * @param address the requested DNS server address.
456          * @return Builder this, to facilitate chaining.
457          * @hide
458          */
459         @NonNull
addInternalDnsServerRequest(@onNull InetAddress address)460         public Builder addInternalDnsServerRequest(@NonNull InetAddress address) {
461             if (address == null) {
462                 throw new NullPointerException("Required argument not provided");
463             }
464 
465             if (address instanceof Inet4Address) {
466                 mConfigRequestList.add(new ConfigAttributeIpv4Dns((Inet4Address) address));
467                 return this;
468             } else if (address instanceof Inet6Address) {
469                 mConfigRequestList.add(new ConfigAttributeIpv6Dns((Inet6Address) address));
470                 return this;
471             } else {
472                 throw new IllegalArgumentException("Invalid address " + address);
473             }
474         }
475 
476         /**
477          * Adds an internal DHCP server request to the {@link TunnelModeChildSessionParams} being
478          * built.
479          *
480          * <p>Only DHCPv4 server requests are supported.
481          *
482          * @param addressFamily the address family. Only {@code AF_INET} is allowed
483          * @return Builder this, to facilitate chaining.
484          */
485         // #getConfigurationRequests has been defined for callers to retrieve internal DHCP server
486         // requests.
487         @SuppressLint("MissingGetterMatchingBuilder")
488         @NonNull
addInternalDhcpServerRequest(int addressFamily)489         public Builder addInternalDhcpServerRequest(int addressFamily) {
490             if (addressFamily == AF_INET) {
491                 mConfigRequestList.add(new ConfigAttributeIpv4Dhcp());
492                 return this;
493             } else {
494                 throw new IllegalArgumentException("Invalid address family: " + addressFamily);
495             }
496         }
497 
498         /**
499          * Adds a specific internal DHCP server request to the {@link TunnelModeChildSessionParams}
500          * being built.
501          *
502          * <p>Only DHCPv4 server requests are supported.
503          *
504          * @param address the requested DHCP server address.
505          * @return Builder this, to facilitate chaining.
506          * @hide
507          */
508         @NonNull
addInternalDhcpServerRequest(@onNull InetAddress address)509         public Builder addInternalDhcpServerRequest(@NonNull InetAddress address) {
510             if (address == null) {
511                 throw new NullPointerException("Required argument not provided");
512             }
513 
514             if (address instanceof Inet4Address) {
515                 mConfigRequestList.add(new ConfigAttributeIpv4Dhcp((Inet4Address) address));
516                 return this;
517             } else {
518                 throw new IllegalArgumentException("Invalid address " + address);
519             }
520         }
521 
522         /**
523          * Adds Configuration requests. Internal use only.
524          *
525          * @hide
526          */
527         @NonNull
addConfigRequest(@onNull TunnelModeChildConfigAttribute attribute)528         public Builder addConfigRequest(@NonNull TunnelModeChildConfigAttribute attribute) {
529             if (attribute instanceof ConfigAttributeIpv4Address) {
530                 mHasIp4AddressRequest = true;
531             } else if (attribute instanceof ConfigAttributeIpv4Netmask) {
532                 if (((ConfigAttributeIpv4Netmask) attribute).address != null) {
533                     throw new IllegalArgumentException(
534                             "Requesting specific a netmask is disallowed");
535                 } else {
536                     mHasIp4NetmaskRequest = true;
537                 }
538             }
539 
540             mConfigRequestList.add(attribute);
541             return this;
542         }
543 
544         /**
545          * Validates and builds the {@link TunnelModeChildSessionParams}.
546          *
547          * @return the validated {@link TunnelModeChildSessionParams}.
548          */
549         @NonNull
build()550         public TunnelModeChildSessionParams build() {
551             addDefaultTsIfNotConfigured();
552             validateOrThrow();
553 
554             if (!mHasIp4AddressRequest && mHasIp4NetmaskRequest) {
555                 throw new IllegalArgumentException(
556                         "Requesting netmask without IPv4 address is disallowed");
557             }
558             if (mHasIp4AddressRequest && !mHasIp4NetmaskRequest) {
559                 mConfigRequestList.add(new ConfigAttributeIpv4Netmask());
560             }
561 
562             return new TunnelModeChildSessionParams(
563                     mInboundTsList.toArray(new IkeTrafficSelector[0]),
564                     mOutboundTsList.toArray(new IkeTrafficSelector[0]),
565                     mSaProposalList.toArray(new ChildSaProposal[0]),
566                     mConfigRequestList.toArray(new TunnelModeChildConfigAttribute[0]),
567                     mHardLifetimeSec,
568                     mSoftLifetimeSec);
569         }
570     }
571 }
572