• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.dhcp;
18 
19 import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
20 import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
21 
22 import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE;
23 import static com.android.server.util.NetworkStackConstants.IPV4_MAX_MTU;
24 import static com.android.server.util.NetworkStackConstants.IPV4_MIN_MTU;
25 
26 import static java.lang.Integer.toUnsignedLong;
27 
28 import android.annotation.NonNull;
29 import android.annotation.Nullable;
30 import android.net.IpPrefix;
31 import android.net.LinkAddress;
32 import android.net.shared.Inet4AddressUtils;
33 import android.util.ArraySet;
34 
35 import java.net.Inet4Address;
36 import java.util.Arrays;
37 import java.util.Collections;
38 import java.util.HashSet;
39 import java.util.Set;
40 
41 /**
42  * Parameters used by the DhcpServer to serve requests.
43  *
44  * <p>Instances are immutable. Use {@link DhcpServingParams.Builder} to instantiate.
45  * @hide
46  */
47 public class DhcpServingParams {
48     public static final int MTU_UNSET = 0;
49     public static final int MIN_PREFIX_LENGTH = 16;
50     public static final int MAX_PREFIX_LENGTH = 30;
51 
52     /** Server inet address and prefix to serve */
53     @NonNull
54     public final LinkAddress serverAddr;
55 
56     /**
57      * Default routers to be advertised to DHCP clients. May be empty.
58      * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
59      */
60     @NonNull
61     public final Set<Inet4Address> defaultRouters;
62 
63     /**
64      * DNS servers to be advertised to DHCP clients. May be empty.
65      * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
66      */
67     @NonNull
68     public final Set<Inet4Address> dnsServers;
69 
70     /**
71      * Excluded addresses that the DHCP server is not allowed to assign to clients.
72      * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
73      */
74     @NonNull
75     public final Set<Inet4Address> excludedAddrs;
76 
77     // DHCP uses uint32. Use long for clearer code, and check range when building.
78     public final long dhcpLeaseTimeSecs;
79     public final int linkMtu;
80 
81     /**
82      * Indicates whether the DHCP server should send the ANDROID_METERED vendor-specific option.
83      */
84     public final boolean metered;
85 
86     /**
87      * Checked exception thrown when some parameters used to build {@link DhcpServingParams} are
88      * missing or invalid.
89      */
90     public static class InvalidParameterException extends Exception {
InvalidParameterException(String message)91         public InvalidParameterException(String message) {
92             super(message);
93         }
94     }
95 
DhcpServingParams(@onNull LinkAddress serverAddr, @NonNull Set<Inet4Address> defaultRouters, @NonNull Set<Inet4Address> dnsServers, @NonNull Set<Inet4Address> excludedAddrs, long dhcpLeaseTimeSecs, int linkMtu, boolean metered)96     private DhcpServingParams(@NonNull LinkAddress serverAddr,
97             @NonNull Set<Inet4Address> defaultRouters,
98             @NonNull Set<Inet4Address> dnsServers, @NonNull Set<Inet4Address> excludedAddrs,
99             long dhcpLeaseTimeSecs, int linkMtu, boolean metered) {
100         this.serverAddr = serverAddr;
101         this.defaultRouters = defaultRouters;
102         this.dnsServers = dnsServers;
103         this.excludedAddrs = excludedAddrs;
104         this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
105         this.linkMtu = linkMtu;
106         this.metered = metered;
107     }
108 
109     /**
110      * Create parameters from a stable AIDL-compatible parcel.
111      * @throws InvalidParameterException The parameters parcelable is null or invalid.
112      */
fromParcelableObject(@ullable DhcpServingParamsParcel parcel)113     public static DhcpServingParams fromParcelableObject(@Nullable DhcpServingParamsParcel parcel)
114             throws InvalidParameterException {
115         if (parcel == null) {
116             throw new InvalidParameterException("Null serving parameters");
117         }
118         final LinkAddress serverAddr = new LinkAddress(
119                 intToInet4AddressHTH(parcel.serverAddr),
120                 parcel.serverAddrPrefixLength);
121         return new Builder()
122                 .setServerAddr(serverAddr)
123                 .setDefaultRouters(toInet4AddressSet(parcel.defaultRouters))
124                 .setDnsServers(toInet4AddressSet(parcel.dnsServers))
125                 .setExcludedAddrs(toInet4AddressSet(parcel.excludedAddrs))
126                 .setDhcpLeaseTimeSecs(parcel.dhcpLeaseTimeSecs)
127                 .setLinkMtu(parcel.linkMtu)
128                 .setMetered(parcel.metered)
129                 .build();
130     }
131 
toInet4AddressSet(@ullable int[] addrs)132     private static Set<Inet4Address> toInet4AddressSet(@Nullable int[] addrs) {
133         if (addrs == null) {
134             return new HashSet<>(0);
135         }
136 
137         final HashSet<Inet4Address> res = new HashSet<>();
138         for (int addr : addrs) {
139             res.add(intToInet4AddressHTH(addr));
140         }
141         return res;
142     }
143 
144     @NonNull
getServerInet4Addr()145     public Inet4Address getServerInet4Addr() {
146         return (Inet4Address) serverAddr.getAddress();
147     }
148 
149     /**
150      * Get the served prefix mask as an IPv4 address.
151      *
152      * <p>For example, if the served prefix is 192.168.42.0/24, this will return 255.255.255.0.
153      */
154     @NonNull
getPrefixMaskAsAddress()155     public Inet4Address getPrefixMaskAsAddress() {
156         return getPrefixMaskAsInet4Address(serverAddr.getPrefixLength());
157     }
158 
159     /**
160      * Get the server broadcast address.
161      *
162      * <p>For example, if the server {@link LinkAddress} is 192.168.42.1/24, this will return
163      * 192.168.42.255.
164      */
165     @NonNull
getBroadcastAddress()166     public Inet4Address getBroadcastAddress() {
167         return Inet4AddressUtils.getBroadcastAddress(
168                 getServerInet4Addr(), serverAddr.getPrefixLength());
169     }
170 
171     /**
172      * Utility class to create new instances of {@link DhcpServingParams} while checking validity
173      * of the parameters.
174      */
175     public static class Builder {
176         private LinkAddress mServerAddr;
177         private Set<Inet4Address> mDefaultRouters;
178         private Set<Inet4Address> mDnsServers;
179         private Set<Inet4Address> mExcludedAddrs;
180         private long mDhcpLeaseTimeSecs;
181         private int mLinkMtu = MTU_UNSET;
182         private boolean mMetered;
183 
184         /**
185          * Set the server address and served prefix for the DHCP server.
186          *
187          * <p>This parameter is required.
188          */
setServerAddr(@onNull LinkAddress serverAddr)189         public Builder setServerAddr(@NonNull LinkAddress serverAddr) {
190             this.mServerAddr = serverAddr;
191             return this;
192         }
193 
194         /**
195          * Set the default routers to be advertised to DHCP clients.
196          *
197          * <p>Each router must be inside the served prefix. This may be an empty set, but it must
198          * always be set explicitly before building the {@link DhcpServingParams}.
199          */
setDefaultRouters(@onNull Set<Inet4Address> defaultRouters)200         public Builder setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) {
201             this.mDefaultRouters = defaultRouters;
202             return this;
203         }
204 
205         /**
206          * Set the default routers to be advertised to DHCP clients.
207          *
208          * <p>Each router must be inside the served prefix. This may be an empty list of routers,
209          * but it must always be set explicitly before building the {@link DhcpServingParams}.
210          */
setDefaultRouters(@onNull Inet4Address... defaultRouters)211         public Builder setDefaultRouters(@NonNull Inet4Address... defaultRouters) {
212             return setDefaultRouters(makeArraySet(defaultRouters));
213         }
214 
215         /**
216          * Convenience method to build the parameters with no default router.
217          *
218          * <p>Equivalent to calling {@link #setDefaultRouters(Inet4Address...)} with no address.
219          */
withNoDefaultRouter()220         public Builder withNoDefaultRouter() {
221             return setDefaultRouters();
222         }
223 
224         /**
225          * Set the DNS servers to be advertised to DHCP clients.
226          *
227          * <p>This may be an empty set, but it must always be set explicitly before building the
228          * {@link DhcpServingParams}.
229          */
setDnsServers(@onNull Set<Inet4Address> dnsServers)230         public Builder setDnsServers(@NonNull Set<Inet4Address> dnsServers) {
231             this.mDnsServers = dnsServers;
232             return this;
233         }
234 
235         /**
236          * Set the DNS servers to be advertised to DHCP clients.
237          *
238          * <p>This may be an empty list of servers, but it must always be set explicitly before
239          * building the {@link DhcpServingParams}.
240          */
setDnsServers(@onNull Inet4Address... dnsServers)241         public Builder setDnsServers(@NonNull Inet4Address... dnsServers) {
242             return setDnsServers(makeArraySet(dnsServers));
243         }
244 
245         /**
246          * Convenience method to build the parameters with no DNS server.
247          *
248          * <p>Equivalent to calling {@link #setDnsServers(Inet4Address...)} with no address.
249          */
withNoDnsServer()250         public Builder withNoDnsServer() {
251             return setDnsServers();
252         }
253 
254         /**
255          * Set excluded addresses that the DHCP server is not allowed to assign to clients.
256          *
257          * <p>This parameter is optional. DNS servers and default routers are always excluded
258          * and do not need to be set here.
259          */
setExcludedAddrs(@onNull Set<Inet4Address> excludedAddrs)260         public Builder setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) {
261             this.mExcludedAddrs = excludedAddrs;
262             return this;
263         }
264 
265         /**
266          * Set excluded addresses that the DHCP server is not allowed to assign to clients.
267          *
268          * <p>This parameter is optional. DNS servers and default routers are always excluded
269          * and do not need to be set here.
270          */
setExcludedAddrs(@onNull Inet4Address... excludedAddrs)271         public Builder setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) {
272             return setExcludedAddrs(makeArraySet(excludedAddrs));
273         }
274 
275         /**
276          * Set the lease time for leases assigned by the DHCP server.
277          *
278          * <p>This parameter is required.
279          */
setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs)280         public Builder setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) {
281             this.mDhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
282             return this;
283         }
284 
285         /**
286          * Set the link MTU to be advertised to DHCP clients.
287          *
288          * <p>If set to {@link #MTU_UNSET}, no MTU will be advertised to clients. This parameter
289          * is optional and defaults to {@link #MTU_UNSET}.
290          */
setLinkMtu(int linkMtu)291         public Builder setLinkMtu(int linkMtu) {
292             this.mLinkMtu = linkMtu;
293             return this;
294         }
295 
296         /**
297          * Set whether the DHCP server should send the ANDROID_METERED vendor-specific option.
298          *
299          * <p>If not set, the default value is false.
300          */
setMetered(boolean metered)301         public Builder setMetered(boolean metered) {
302             this.mMetered = metered;
303             return this;
304         }
305 
306         /**
307          * Create a new {@link DhcpServingParams} instance based on parameters set in the builder.
308          *
309          * <p>This method has no side-effects. If it does not throw, a valid
310          * {@link DhcpServingParams} is returned.
311          * @return The constructed parameters.
312          * @throws InvalidParameterException At least one parameter is missing or invalid.
313          */
314         @NonNull
build()315         public DhcpServingParams build() throws InvalidParameterException {
316             if (mServerAddr == null) {
317                 throw new InvalidParameterException("Missing serverAddr");
318             }
319             if (mDefaultRouters == null) {
320                 throw new InvalidParameterException("Missing defaultRouters");
321             }
322             if (mDnsServers == null) {
323                 // Empty set is OK, but enforce explicitly setting it
324                 throw new InvalidParameterException("Missing dnsServers");
325             }
326             if (mDhcpLeaseTimeSecs <= 0 || mDhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) {
327                 throw new InvalidParameterException("Invalid lease time: " + mDhcpLeaseTimeSecs);
328             }
329             if (mLinkMtu != MTU_UNSET && (mLinkMtu < IPV4_MIN_MTU || mLinkMtu > IPV4_MAX_MTU)) {
330                 throw new InvalidParameterException("Invalid link MTU: " + mLinkMtu);
331             }
332             if (!mServerAddr.isIpv4()) {
333                 throw new InvalidParameterException("serverAddr must be IPv4");
334             }
335             if (mServerAddr.getPrefixLength() < MIN_PREFIX_LENGTH
336                     || mServerAddr.getPrefixLength() > MAX_PREFIX_LENGTH) {
337                 throw new InvalidParameterException("Prefix length is not in supported range");
338             }
339 
340             final IpPrefix prefix = makeIpPrefix(mServerAddr);
341             for (Inet4Address addr : mDefaultRouters) {
342                 if (!prefix.contains(addr)) {
343                     throw new InvalidParameterException(String.format(
344                             "Default router %s is not in server prefix %s", addr, mServerAddr));
345                 }
346             }
347 
348             final Set<Inet4Address> excl = new HashSet<>();
349             if (mExcludedAddrs != null) {
350                 excl.addAll(mExcludedAddrs);
351             }
352             excl.add((Inet4Address) mServerAddr.getAddress());
353             excl.addAll(mDefaultRouters);
354             excl.addAll(mDnsServers);
355 
356             return new DhcpServingParams(mServerAddr,
357                     Collections.unmodifiableSet(new HashSet<>(mDefaultRouters)),
358                     Collections.unmodifiableSet(new HashSet<>(mDnsServers)),
359                     Collections.unmodifiableSet(excl),
360                     mDhcpLeaseTimeSecs, mLinkMtu, mMetered);
361         }
362     }
363 
364     /**
365      * Utility method to create an IpPrefix with the address and prefix length of a LinkAddress.
366      */
367     @NonNull
makeIpPrefix(@onNull LinkAddress addr)368     static IpPrefix makeIpPrefix(@NonNull LinkAddress addr) {
369         return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
370     }
371 
makeArraySet(T[] elements)372     private static <T> ArraySet<T> makeArraySet(T[] elements) {
373         final ArraySet<T> set = new ArraySet<>(elements.length);
374         set.addAll(Arrays.asList(elements));
375         return set;
376     }
377 }
378