aboutsummaryrefslogtreecommitdiff
path: root/src/java/android/net/ipsec/ike/TunnelModeChildSessionParams.java
blob: c8d31f6bccdc338d4d0905aaa5dca727fa949157 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
/*
 * 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.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.LinkAddress;

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.ConfigAttributeIpv6Address;
import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Dns;
import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.TunnelModeChildConfigAttribute;

import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * TunnelModeChildSessionParams represents proposed configurations for negotiating a tunnel mode
 * Child Session.
 *
 * @hide
 */
@SystemApi
public final class TunnelModeChildSessionParams extends ChildSessionParams {
    @NonNull private final TunnelModeChildConfigAttribute[] mConfigRequests;

    private TunnelModeChildSessionParams(
            @NonNull IkeTrafficSelector[] inboundTs,
            @NonNull IkeTrafficSelector[] outboundTs,
            @NonNull ChildSaProposal[] proposals,
            @NonNull TunnelModeChildConfigAttribute[] configRequests,
            int hardLifetimeSec,
            int softLifetimeSec) {
        super(
                inboundTs,
                outboundTs,
                proposals,
                hardLifetimeSec,
                softLifetimeSec,
                false /*isTransport*/);
        mConfigRequests = configRequests;
    }

    /** @hide */
    public TunnelModeChildConfigAttribute[] getConfigurationAttributesInternal() {
        return mConfigRequests;
    }

    /** Retrieves the list of Configuration Requests */
    @NonNull
    public List<TunnelModeChildConfigRequest> getConfigurationRequests() {
        return Collections.unmodifiableList(Arrays.asList(mConfigRequests));
    }

    /** Represents a tunnel mode child session configuration request type */
    public interface TunnelModeChildConfigRequest {}

    /** Represents an IPv4 Internal Address request */
    public interface ConfigRequestIpv4Address extends TunnelModeChildConfigRequest {
        /**
         * Retrieves the requested internal IPv4 address
         *
         * @return The requested IPv4 address, or null if no specific internal address was requested
         */
        @Nullable
        Inet4Address getAddress();
    }

    /** Represents an IPv4 DHCP server request */
    public interface ConfigRequestIpv4DhcpServer extends TunnelModeChildConfigRequest {}

    /** Represents an IPv4 DNS Server request */
    public interface ConfigRequestIpv4DnsServer extends TunnelModeChildConfigRequest {}

    /** Represents an IPv4 Netmask request */
    public interface ConfigRequestIpv4Netmask extends TunnelModeChildConfigRequest {}

    /** Represents an IPv6 Internal Address request */
    public interface ConfigRequestIpv6Address extends TunnelModeChildConfigRequest {
        /**
         * Retrieves the requested internal IPv6 address
         *
         * @return The requested IPv6 address, or null if no specific internal address was requested
         */
        @Nullable
        Inet6Address getAddress();

        /**
         * Retrieves the prefix length
         *
         * @return The requested prefix length, or -1 if no specific IPv6 address was requested
         */
        int getPrefixLength();
    }

    /** Represents an IPv6 DNS Server request */
    public interface ConfigRequestIpv6DnsServer extends TunnelModeChildConfigRequest {}

    /** This class can be used to incrementally construct a {@link TunnelModeChildSessionParams}. */
    public static final class Builder extends ChildSessionParams.Builder {
        private static final int IPv4_DEFAULT_PREFIX_LEN = 32;

        private boolean mHasIp4AddressRequest;
        private List<TunnelModeChildConfigAttribute> 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 the {@link TunnelModeChildSessionParams} being built.
         *
         * @param proposal Child SA proposal.
         * @return Builder this, to facilitate chaining.
         */
        @NonNull
        public Builder addSaProposal(@NonNull ChildSaProposal proposal) {
            if (proposal == null) {
                throw new NullPointerException("Required argument not provided");
            }

            addProposal(proposal);
            return this;
        }

        /**
         * Adds an inbound {@link IkeTrafficSelector} to the {@link TunnelModeChildSessionParams}
         * being built.
         *
         * <p>This method allows callers to limit the inbound traffic transmitted over the Child
         * Session to the given range. The IKE server may further narrow the range. Callers should
         * refer to {@link ChildSessionConfiguration} for the negotiated traffic selectors.
         *
         * <p>If no inbound {@link IkeTrafficSelector} is provided, a default value will be used
         * that covers all IP addresses and ports.
         *
         * @param trafficSelector the inbound {@link IkeTrafficSelector}.
         * @return Builder this, to facilitate chaining.
         */
        @NonNull
        public Builder addInboundTrafficSelectors(@NonNull IkeTrafficSelector trafficSelector) {
            Objects.requireNonNull(trafficSelector, "Required argument not provided");
            addInboundTs(trafficSelector);
            return this;
        }

        /**
         * Adds an outbound {@link IkeTrafficSelector} to the {@link TunnelModeChildSessionParams}
         * being built.
         *
         * <p>This method allows callers to limit the outbound traffic transmitted over the Child
         * Session to the given range. The IKE server may further narrow the range. Callers should
         * refer to {@link ChildSessionConfiguration} for the negotiated traffic selectors.
         *
         * <p>If no outbound {@link IkeTrafficSelector} is provided, a default value will be used
         * that covers all IP addresses and ports.
         *
         * @param trafficSelector the outbound {@link IkeTrafficSelector}.
         * @return Builder this, to facilitate chaining.
         */
        @NonNull
        public Builder addOutboundTrafficSelectors(@NonNull IkeTrafficSelector trafficSelector) {
            Objects.requireNonNull(trafficSelector, "Required argument not provided");
            addOutboundTs(trafficSelector);
            return this;
        }

        /**
         * Sets hard and soft lifetimes.
         *
         * <p>Lifetimes will not be negotiated with the remote IKE server.
         *
         * @param hardLifetimeSeconds number of seconds after which Child SA will expire. Defaults
         *     to 7200 seconds (2 hours). Considering IPsec packet lifetime, IKE library requires
         *     hard lifetime to be a value from 300 seconds (5 minutes) to 14400 seconds (4 hours),
         *     inclusive.
         * @param softLifetimeSeconds number of seconds after which Child SA will request rekey.
         *     Defaults to 3600 seconds (1 hour). MUST be at least 120 seconds (2 minutes), and at
         *     least 60 seconds (1 minute) shorter than the hard lifetime.
         */
        @NonNull
        public Builder setLifetimeSeconds(
                @IntRange(
                                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) {
            validateAndSetLifetime(hardLifetimeSeconds, softLifetimeSeconds);
            mHardLifetimeSec = hardLifetimeSeconds;
            mSoftLifetimeSec = softLifetimeSeconds;
            return this;
        }

        /**
         * Adds an internal IP address request to the {@link TunnelModeChildSessionParams} being
         * built.
         *
         * @param addressFamily the address family. Only {@link OsConstants.AF_INET} and {@link
         *     OsConstants.AF_INET6} are allowed.
         * @return Builder this, to facilitate chaining.
         */
        @NonNull
        public Builder addInternalAddressRequest(int addressFamily) {
            if (addressFamily == AF_INET) {
                mHasIp4AddressRequest = true;
                mConfigRequestList.add(new ConfigAttributeIpv4Address());
                return this;
            } else if (addressFamily == AF_INET6) {
                mConfigRequestList.add(new ConfigAttributeIpv6Address());
                return this;
            } else {
                throw new IllegalArgumentException("Invalid address family: " + addressFamily);
            }
        }

        /**
         * Adds a specific internal IPv4 address request to the {@link TunnelModeChildSessionParams}
         * being built.
         *
         * @param address the requested IPv4 address.
         * @return Builder this, to facilitate chaining.
         */
        @NonNull
        public Builder addInternalAddressRequest(@NonNull Inet4Address address) {
            if (address == null) {
                throw new NullPointerException("Required argument not provided");
            }

            mHasIp4AddressRequest = true;
            mConfigRequestList.add(new ConfigAttributeIpv4Address((Inet4Address) address));
            return this;
        }

        /**
         * Adds a specific internal IPv6 address request to the {@link TunnelModeChildSessionParams}
         * being built.
         *
         * @param address the requested IPv6 address.
         * @param prefixLen length of the IPv6 address prefix length.
         * @return Builder this, to facilitate chaining.
         */
        @NonNull
        public Builder addInternalAddressRequest(@NonNull Inet6Address address, int prefixLen) {
            if (address == null) {
                throw new NullPointerException("Required argument not provided");
            }

            mConfigRequestList.add(
                    new ConfigAttributeIpv6Address(new LinkAddress(address, prefixLen)));
            return this;
        }

        /**
         * Adds an internal DNS server request to the {@link TunnelModeChildSessionParams} being
         * built.
         *
         * @param addressFamily the address family. Only {@link OsConstants.AF_INET} and {@link
         *     OsConstants.AF_INET6} are allowed.
         * @return Builder this, to facilitate chaining.
         */
        @NonNull
        public Builder addInternalDnsServerRequest(int addressFamily) {
            if (addressFamily == AF_INET) {
                mConfigRequestList.add(new ConfigAttributeIpv4Dns());
                return this;
            } else if (addressFamily == AF_INET6) {
                mConfigRequestList.add(new ConfigAttributeIpv6Dns());
                return this;
            } else {
                throw new IllegalArgumentException("Invalid address family: " + addressFamily);
            }
        }

        /**
         * Adds a specific internal DNS server request to the {@link TunnelModeChildSessionParams}
         * being built.
         *
         * @param address the requested DNS server address.
         * @return Builder this, to facilitate chaining.
         * @hide
         */
        @NonNull
        public Builder addInternalDnsServerRequest(@NonNull InetAddress address) {
            if (address == null) {
                throw new NullPointerException("Required argument not provided");
            }

            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 DHCP server requests to the {@link TunnelModeChildSessionParams} being
         * built.
         *
         * <p>Only DHCPv4 server requests are supported.
         *
         * @param addressFamily the address family. Only {@link OsConstants.AF_INET} is allowed.
         * @return Builder this, to facilitate chaining.
         */
        @NonNull
        public Builder addInternalDhcpServerRequest(int addressFamily) {
            if (addressFamily == AF_INET) {
                mConfigRequestList.add(new ConfigAttributeIpv4Dhcp());
                return this;
            } else {
                throw new IllegalArgumentException("Invalid address family: " + addressFamily);
            }
        }

        /**
         * Adds a specific internal DHCP server request to the {@link TunnelModeChildSessionParams}
         * being built.
         *
         * <p>Only DHCPv4 server requests are supported.
         *
         * @param address the requested DHCP server address.
         * @return Builder this, to facilitate chaining.
         * @hide
         */
        @NonNull
        public Builder addInternalDhcpServerRequest(@NonNull InetAddress address) {
            if (address == null) {
                throw new NullPointerException("Required argument not provided");
            }

            if (address instanceof Inet4Address) {
                mConfigRequestList.add(new ConfigAttributeIpv4Dhcp((Inet4Address) address));
                return this;
            } else {
                throw new IllegalArgumentException("Invalid address " + address);
            }
        }

        /**
         * Validates and builds the {@link TunnelModeChildSessionParams}.
         *
         * @return the validated {@link TunnelModeChildSessionParams}.
         */
        @NonNull
        public TunnelModeChildSessionParams build() {
            addDefaultTsIfNotConfigured();
            validateOrThrow();

            if (mHasIp4AddressRequest) {
                mConfigRequestList.add(new ConfigAttributeIpv4Netmask());
            }

            return new TunnelModeChildSessionParams(
                    mInboundTsList.toArray(new IkeTrafficSelector[0]),
                    mOutboundTsList.toArray(new IkeTrafficSelector[0]),
                    mSaProposalList.toArray(new ChildSaProposal[0]),
                    mConfigRequestList.toArray(new TunnelModeChildConfigAttribute[0]),
                    mHardLifetimeSec,
                    mSoftLifetimeSec);
        }
    }
}