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