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.dhcp; 18 19 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ALL; 20 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY; 21 22 import android.net.DhcpResults; 23 import android.net.LinkAddress; 24 import android.net.metrics.DhcpErrorEvent; 25 import android.net.networkstack.aidl.dhcp.DhcpOption; 26 import android.os.Build; 27 import android.os.SystemProperties; 28 import android.system.OsConstants; 29 import android.text.TextUtils; 30 31 import androidx.annotation.NonNull; 32 import androidx.annotation.Nullable; 33 import androidx.annotation.VisibleForTesting; 34 35 import com.android.net.module.util.Inet4AddressUtils; 36 import com.android.networkstack.apishim.common.ShimUtils; 37 38 import java.io.UnsupportedEncodingException; 39 import java.net.Inet4Address; 40 import java.net.UnknownHostException; 41 import java.nio.BufferUnderflowException; 42 import java.nio.ByteBuffer; 43 import java.nio.ByteOrder; 44 import java.nio.ShortBuffer; 45 import java.nio.charset.StandardCharsets; 46 import java.util.ArrayList; 47 import java.util.Arrays; 48 import java.util.List; 49 50 /** 51 * Defines basic data and operations needed to build and use packets for the 52 * DHCP protocol. Subclasses create the specific packets used at each 53 * stage of the negotiation. 54 * 55 * @hide 56 */ 57 public abstract class DhcpPacket { 58 protected static final String TAG = "DhcpPacket"; 59 60 // TODO: use NetworkStackConstants.IPV4_MIN_MTU once this class is moved to the network stack. 61 private static final int IPV4_MIN_MTU = 68; 62 63 // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the 64 // CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the 65 // DHCP client timeout. 66 public static final int MINIMUM_LEASE = 60; 67 public static final int INFINITE_LEASE = (int) 0xffffffff; 68 69 public static final Inet4Address INADDR_ANY = IPV4_ADDR_ANY; 70 public static final Inet4Address INADDR_BROADCAST = IPV4_ADDR_ALL; 71 public static final byte[] ETHER_BROADCAST = new byte[] { 72 (byte) 0xff, (byte) 0xff, (byte) 0xff, 73 (byte) 0xff, (byte) 0xff, (byte) 0xff, 74 }; 75 76 /** 77 * Packet encapsulations. 78 */ 79 public static final int ENCAP_L2 = 0; // EthernetII header included 80 public static final int ENCAP_L3 = 1; // IP/UDP header included 81 public static final int ENCAP_BOOTP = 2; // BOOTP contents only 82 83 /** 84 * Minimum length of a DHCP packet, excluding options, in the above encapsulations. 85 */ 86 public static final int MIN_PACKET_LENGTH_BOOTP = 236; // See diagram in RFC 2131, section 2. 87 public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8; 88 public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14; 89 90 public static final int HWADDR_LEN = 16; 91 public static final int MAX_OPTION_LEN = 255; 92 93 // The lower boundary for V6ONLY_WAIT. 94 public static final long MIN_V6ONLY_WAIT_MS = 300_000; 95 public static final long V6ONLY_PREFERRED_ABSENCE = -1L; 96 97 /** 98 * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum 99 * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280, 100 * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500 101 * because in general it is risky to assume that the hardware is able to send/receive packets 102 * larger than 1500 bytes even if the network supports it. 103 */ 104 private static final int MIN_MTU = 1280; 105 private static final int MAX_MTU = 1500; 106 107 /** 108 * IP layer definitions. 109 */ 110 private static final byte IP_TYPE_UDP = (byte) 0x11; 111 112 /** 113 * IP: Version 4, Header Length 20 bytes 114 */ 115 private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45; 116 117 /** 118 * IP: Flags 0, Fragment Offset 0, Don't Fragment 119 */ 120 private static final short IP_FLAGS_OFFSET = (short) 0x4000; 121 122 /** 123 * IP: TOS 124 */ 125 private static final byte IP_TOS_LOWDELAY = (byte) 0x10; 126 127 /** 128 * IP: TTL -- use default 64 from RFC1340 129 */ 130 private static final byte IP_TTL = (byte) 0x40; 131 132 /** 133 * The client DHCP port. 134 */ 135 public static final short DHCP_CLIENT = (short) 68; 136 137 /** 138 * The server DHCP port. 139 */ 140 public static final short DHCP_SERVER = (short) 67; 141 142 /** 143 * The message op code indicating a request from a client. 144 */ 145 public static final byte DHCP_BOOTREQUEST = (byte) 1; 146 147 /** 148 * The message op code indicating a response from the server. 149 */ 150 public static final byte DHCP_BOOTREPLY = (byte) 2; 151 152 /** 153 * The code type used to identify an Ethernet MAC address in the 154 * Client-ID field. 155 */ 156 protected static final byte CLIENT_ID_ETHER = (byte) 1; 157 158 /** 159 * The maximum length of a packet that can be constructed. 160 */ 161 protected static final int MAX_LENGTH = 1500; 162 163 /** 164 * The magic cookie that identifies this as a DHCP packet instead of BOOTP. 165 */ 166 public static final int DHCP_MAGIC_COOKIE = 0x63825363; 167 168 /** 169 * DHCP Optional Type: DHCP Subnet Mask 170 */ 171 public static final byte DHCP_SUBNET_MASK = 1; 172 protected Inet4Address mSubnetMask; 173 174 /** 175 * DHCP Optional Type: DHCP Router 176 */ 177 public static final byte DHCP_ROUTER = 3; 178 protected List <Inet4Address> mGateways; 179 180 /** 181 * DHCP Optional Type: DHCP DNS Server 182 */ 183 public static final byte DHCP_DNS_SERVER = 6; 184 protected List<Inet4Address> mDnsServers; 185 186 /** 187 * DHCP Optional Type: DHCP Host Name 188 */ 189 public static final byte DHCP_HOST_NAME = 12; 190 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 191 public String mHostName; 192 193 /** 194 * DHCP Optional Type: DHCP DOMAIN NAME 195 */ 196 public static final byte DHCP_DOMAIN_NAME = 15; 197 protected String mDomainName; 198 199 /** 200 * DHCP Optional Type: DHCP Interface MTU 201 */ 202 public static final byte DHCP_MTU = 26; 203 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 204 public Short mMtu; 205 206 /** 207 * DHCP Optional Type: DHCP BROADCAST ADDRESS 208 */ 209 public static final byte DHCP_BROADCAST_ADDRESS = 28; 210 protected Inet4Address mBroadcastAddress; 211 212 /** 213 * DHCP Optional Type: Vendor specific information 214 */ 215 public static final byte DHCP_VENDOR_INFO = 43; 216 protected String mVendorInfo; 217 218 /** 219 * Value of the vendor specific option used to indicate that the network is metered 220 */ 221 public static final String VENDOR_INFO_ANDROID_METERED = "ANDROID_METERED"; 222 223 /** 224 * DHCP Optional Type: Option overload option 225 */ 226 public static final byte DHCP_OPTION_OVERLOAD = 52; 227 228 /** 229 * Possible values of the option overload option. 230 */ 231 private static final byte OPTION_OVERLOAD_FILE = 1; 232 private static final byte OPTION_OVERLOAD_SNAME = 2; 233 private static final byte OPTION_OVERLOAD_BOTH = 3; 234 235 /** 236 * DHCP Optional Type: DHCP Requested IP Address 237 */ 238 public static final byte DHCP_REQUESTED_IP = 50; 239 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 240 public Inet4Address mRequestedIp; 241 242 /** 243 * DHCP Optional Type: DHCP Lease Time 244 */ 245 public static final byte DHCP_LEASE_TIME = 51; 246 protected Integer mLeaseTime; 247 248 /** 249 * DHCP Optional Type: DHCP Message Type 250 */ 251 public static final byte DHCP_MESSAGE_TYPE = 53; 252 // the actual type values 253 public static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1; 254 public static final byte DHCP_MESSAGE_TYPE_OFFER = 2; 255 public static final byte DHCP_MESSAGE_TYPE_REQUEST = 3; 256 public static final byte DHCP_MESSAGE_TYPE_DECLINE = 4; 257 public static final byte DHCP_MESSAGE_TYPE_ACK = 5; 258 public static final byte DHCP_MESSAGE_TYPE_NAK = 6; 259 public static final byte DHCP_MESSAGE_TYPE_RELEASE = 7; 260 public static final byte DHCP_MESSAGE_TYPE_INFORM = 8; 261 262 /** 263 * DHCP Optional Type: DHCP Server Identifier 264 */ 265 public static final byte DHCP_SERVER_IDENTIFIER = 54; 266 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 267 public Inet4Address mServerIdentifier; 268 269 /** 270 * DHCP Optional Type: DHCP Parameter List 271 */ 272 public static final byte DHCP_PARAMETER_LIST = 55; 273 protected byte[] mRequestedParams; 274 275 /** 276 * DHCP Optional Type: DHCP MESSAGE 277 */ 278 public static final byte DHCP_MESSAGE = 56; 279 protected String mMessage; 280 281 /** 282 * DHCP Optional Type: Maximum DHCP Message Size 283 */ 284 public static final byte DHCP_MAX_MESSAGE_SIZE = 57; 285 protected Short mMaxMessageSize; 286 287 /** 288 * DHCP Optional Type: DHCP Renewal Time Value 289 */ 290 public static final byte DHCP_RENEWAL_TIME = 58; 291 protected Integer mT1; 292 293 /** 294 * DHCP Optional Type: Rebinding Time Value 295 */ 296 public static final byte DHCP_REBINDING_TIME = 59; 297 protected Integer mT2; 298 299 /** 300 * DHCP Optional Type: Vendor Class Identifier 301 */ 302 public static final byte DHCP_VENDOR_CLASS_ID = 60; 303 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 304 public String mVendorId; 305 306 /** 307 * DHCP Optional Type: DHCP Client Identifier 308 */ 309 public static final byte DHCP_CLIENT_IDENTIFIER = 61; 310 protected byte[] mClientId; 311 312 /** 313 * DHCP Optional Type: DHCP User Class option 314 */ 315 public static final byte DHCP_USER_CLASS = 77; 316 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 317 public byte[] mUserClass; 318 319 /** 320 * DHCP zero-length Optional Type: Rapid Commit. Per RFC4039, both DHCPDISCOVER and DHCPACK 321 * packet may include this option. 322 */ 323 public static final byte DHCP_RAPID_COMMIT = 80; 324 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 325 public boolean mRapidCommit; 326 327 /** 328 * DHCP IPv6-Only Preferred Option(RFC 8925). 329 * Indicate that a host supports an IPv6-only mode and willing to forgo obtaining an IPv4 330 * address for V6ONLY_WAIT period if the network provides IPv6 connectivity. V6ONLY_WAIT 331 * is 32-bit unsigned integer, so the Integer value cannot be used as-is. 332 */ 333 public static final byte DHCP_IPV6_ONLY_PREFERRED = (byte) 108; 334 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 335 public Integer mIpv6OnlyWaitTime; 336 337 public static final byte DHCP_CAPTIVE_PORTAL = (byte) 114; 338 protected String mCaptivePortalUrl; 339 340 /** 341 * DHCP zero-length option code: pad 342 */ 343 public static final byte DHCP_OPTION_PAD = 0x00; 344 345 /** 346 * DHCP zero-length option code: end of options 347 */ 348 public static final byte DHCP_OPTION_END = (byte) 0xff; 349 350 /** 351 * The transaction identifier used in this particular DHCP negotiation 352 */ 353 protected final int mTransId; 354 355 /** 356 * The seconds field in the BOOTP header. Per RFC, should be nonzero in client requests only. 357 */ 358 protected final short mSecs; 359 360 /** 361 * The IP address of the client host. This address is typically 362 * proposed by the client (from an earlier DHCP negotiation) or 363 * supplied by the server. 364 */ 365 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 366 public final Inet4Address mClientIp; 367 protected final Inet4Address mYourIp; 368 private final Inet4Address mNextIp; 369 protected final Inet4Address mRelayIp; 370 371 /** 372 * Does the client request a broadcast response? 373 */ 374 protected boolean mBroadcast; 375 376 /** 377 * The six-octet MAC of the client. 378 */ 379 protected final byte[] mClientMac; 380 381 /** 382 * The server host name from server. 383 */ 384 protected String mServerHostName; 385 386 /** 387 * The customized DHCP client options to be sent. 388 */ 389 @Nullable 390 protected List<DhcpOption> mCustomizedClientOptions; 391 392 /** 393 * Asks the packet object to create a ByteBuffer serialization of 394 * the packet for transmission. 395 */ buildPacket(int encap, short destUdp, short srcUdp)396 public abstract ByteBuffer buildPacket(int encap, short destUdp, 397 short srcUdp); 398 399 /** 400 * Allows the concrete class to fill in packet-type-specific details, 401 * typically optional parameters at the end of the packet. 402 */ finishPacket(ByteBuffer buffer)403 abstract void finishPacket(ByteBuffer buffer); 404 405 // Set in unit tests, to ensure that the test does not break when run on different devices and 406 // on different releases. 407 static String sTestOverrideVendorId = null; 408 DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp, Inet4Address nextIp, Inet4Address relayIp, byte[] clientMac, boolean broadcast)409 protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp, 410 Inet4Address nextIp, Inet4Address relayIp, 411 byte[] clientMac, boolean broadcast) { 412 mTransId = transId; 413 mSecs = secs; 414 mClientIp = clientIp; 415 mYourIp = yourIp; 416 mNextIp = nextIp; 417 mRelayIp = relayIp; 418 mClientMac = clientMac; 419 mBroadcast = broadcast; 420 } 421 422 /** 423 * Returns the transaction ID. 424 */ getTransactionId()425 public int getTransactionId() { 426 return mTransId; 427 } 428 429 /** 430 * Returns the client MAC. 431 */ getClientMac()432 public byte[] getClientMac() { 433 return mClientMac; 434 } 435 436 // TODO: refactor DhcpClient to set clientId when constructing packets and remove 437 // hasExplicitClientId logic 438 /** 439 * Returns whether a client ID was set in the options for this packet. 440 */ hasExplicitClientId()441 public boolean hasExplicitClientId() { 442 return mClientId != null; 443 } 444 445 /** 446 * Convenience method to return the client ID if it was set explicitly, or null otherwise. 447 */ 448 @Nullable getExplicitClientIdOrNull()449 public byte[] getExplicitClientIdOrNull() { 450 return hasExplicitClientId() ? getClientId() : null; 451 } 452 453 /** 454 * Returns the client ID. If not set explicitly, this follows RFC 2132 and creates a client ID 455 * based on the hardware address. 456 */ getClientId()457 public byte[] getClientId() { 458 final byte[] clientId; 459 if (hasExplicitClientId()) { 460 clientId = Arrays.copyOf(mClientId, mClientId.length); 461 } else { 462 clientId = new byte[mClientMac.length + 1]; 463 clientId[0] = CLIENT_ID_ETHER; 464 System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length); 465 } 466 return clientId; 467 } 468 469 /** 470 * Returns whether a parameter is included in the parameter request list option of this packet. 471 * 472 * <p>If there is no parameter request list option in the packet, false is returned. 473 * 474 * @param paramId ID of the parameter, such as {@link #DHCP_MTU} or {@link #DHCP_HOST_NAME}. 475 */ hasRequestedParam(byte paramId)476 public boolean hasRequestedParam(byte paramId) { 477 if (mRequestedParams == null) { 478 return false; 479 } 480 481 for (byte reqParam : mRequestedParams) { 482 if (reqParam == paramId) { 483 return true; 484 } 485 } 486 return false; 487 } 488 489 /** 490 * Creates a new L3 packet (including IP header) containing the 491 * DHCP udp packet. This method relies upon the delegated method 492 * finishPacket() to insert the per-packet contents. 493 */ fillInPacket(int encap, Inet4Address destIp, Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf, byte requestCode, boolean broadcast)494 protected void fillInPacket(int encap, Inet4Address destIp, 495 Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf, 496 byte requestCode, boolean broadcast) { 497 byte[] destIpArray = destIp.getAddress(); 498 byte[] srcIpArray = srcIp.getAddress(); 499 int ipHeaderOffset = 0; 500 int ipLengthOffset = 0; 501 int ipChecksumOffset = 0; 502 int endIpHeader = 0; 503 int udpHeaderOffset = 0; 504 int udpLengthOffset = 0; 505 int udpChecksumOffset = 0; 506 507 buf.clear(); 508 buf.order(ByteOrder.BIG_ENDIAN); 509 510 if (encap == ENCAP_L2) { 511 buf.put(ETHER_BROADCAST); 512 buf.put(mClientMac); 513 buf.putShort((short) OsConstants.ETH_P_IP); 514 } 515 516 // if a full IP packet needs to be generated, put the IP & UDP 517 // headers in place, and pre-populate with artificial values 518 // needed to seed the IP checksum. 519 if (encap <= ENCAP_L3) { 520 ipHeaderOffset = buf.position(); 521 buf.put(IP_VERSION_HEADER_LEN); 522 buf.put(IP_TOS_LOWDELAY); // tos: IPTOS_LOWDELAY 523 ipLengthOffset = buf.position(); 524 buf.putShort((short)0); // length 525 buf.putShort((short)0); // id 526 buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment 527 buf.put(IP_TTL); // TTL: use default 64 from RFC1340 528 buf.put(IP_TYPE_UDP); 529 ipChecksumOffset = buf.position(); 530 buf.putShort((short) 0); // checksum 531 532 buf.put(srcIpArray); 533 buf.put(destIpArray); 534 endIpHeader = buf.position(); 535 536 // UDP header 537 udpHeaderOffset = buf.position(); 538 buf.putShort(srcUdp); 539 buf.putShort(destUdp); 540 udpLengthOffset = buf.position(); 541 buf.putShort((short) 0); // length 542 udpChecksumOffset = buf.position(); 543 buf.putShort((short) 0); // UDP checksum -- initially zero 544 } 545 546 // DHCP payload 547 buf.put(requestCode); 548 buf.put((byte) 1); // Hardware Type: Ethernet 549 buf.put((byte) mClientMac.length); // Hardware Address Length 550 buf.put((byte) 0); // Hop Count 551 buf.putInt(mTransId); // Transaction ID 552 buf.putShort(mSecs); // Elapsed Seconds 553 554 if (broadcast) { 555 buf.putShort((short) 0x8000); // Flags 556 } else { 557 buf.putShort((short) 0x0000); // Flags 558 } 559 560 buf.put(mClientIp.getAddress()); 561 buf.put(mYourIp.getAddress()); 562 buf.put(mNextIp.getAddress()); 563 buf.put(mRelayIp.getAddress()); 564 buf.put(mClientMac); 565 buf.position(buf.position() + 566 (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes 567 + 64 // empty server host name (64 bytes) 568 + 128); // empty boot file name (128 bytes) 569 buf.putInt(DHCP_MAGIC_COOKIE); // magic number 570 finishPacket(buf); 571 572 // round up to an even number of octets 573 if ((buf.position() & 1) == 1) { 574 buf.put((byte) 0); 575 } 576 577 // If an IP packet is being built, the IP & UDP checksums must be 578 // computed. 579 if (encap <= ENCAP_L3) { 580 // fix UDP header: insert length 581 short udpLen = (short)(buf.position() - udpHeaderOffset); 582 buf.putShort(udpLengthOffset, udpLen); 583 // fix UDP header: checksum 584 // checksum for UDP at udpChecksumOffset 585 int udpSeed = 0; 586 587 // apply IPv4 pseudo-header. Read IP address src and destination 588 // values from the IP header and accumulate checksum. 589 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2)); 590 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4)); 591 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6)); 592 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8)); 593 594 // accumulate extra data for the pseudo-header 595 udpSeed += IP_TYPE_UDP; 596 udpSeed += udpLen; 597 // and compute UDP checksum 598 buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed, 599 udpHeaderOffset, 600 buf.position())); 601 // fix IP header: insert length 602 buf.putShort(ipLengthOffset, (short)(buf.position() - ipHeaderOffset)); 603 // fixup IP-header checksum 604 buf.putShort(ipChecksumOffset, 605 (short) checksum(buf, 0, ipHeaderOffset, endIpHeader)); 606 } 607 } 608 609 /** 610 * Converts a signed short value to an unsigned int value. Needed 611 * because Java does not have unsigned types. 612 */ intAbs(short v)613 private static int intAbs(short v) { 614 return v & 0xFFFF; 615 } 616 617 /** 618 * Performs an IP checksum (used in IP header and across UDP 619 * payload) on the specified portion of a ByteBuffer. The seed 620 * allows the checksum to commence with a specified value. 621 */ checksum(ByteBuffer buf, int seed, int start, int end)622 private int checksum(ByteBuffer buf, int seed, int start, int end) { 623 int sum = seed; 624 int bufPosition = buf.position(); 625 626 // set position of original ByteBuffer, so that the ShortBuffer 627 // will be correctly initialized 628 buf.position(start); 629 ShortBuffer shortBuf = buf.asShortBuffer(); 630 631 // re-set ByteBuffer position 632 buf.position(bufPosition); 633 634 short[] shortArray = new short[(end - start) / 2]; 635 shortBuf.get(shortArray); 636 637 for (short s : shortArray) { 638 sum += intAbs(s); 639 } 640 641 start += shortArray.length * 2; 642 643 // see if a singleton byte remains 644 if (end != start) { 645 short b = buf.get(start); 646 647 // make it unsigned 648 if (b < 0) { 649 b += 256; 650 } 651 652 sum += b * 256; 653 } 654 655 sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); 656 sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF); 657 int negated = ~sum; 658 return intAbs((short) negated); 659 } 660 661 /** 662 * Adds an optional parameter containing a single byte value. 663 */ addTlv(ByteBuffer buf, byte type, byte value)664 protected static void addTlv(ByteBuffer buf, byte type, byte value) { 665 buf.put(type); 666 buf.put((byte) 1); 667 buf.put(value); 668 } 669 670 /** 671 * Adds an optional parameter containing zero-length value. 672 */ addTlv(ByteBuffer buf, byte type)673 protected static void addTlv(ByteBuffer buf, byte type) { 674 buf.put(type); 675 buf.put((byte) 0); 676 } 677 678 /** 679 * Adds an optional parameter containing an array of bytes. 680 * 681 * <p>This method is a no-op if the payload argument is null. 682 */ addTlv(ByteBuffer buf, byte type, @Nullable byte[] payload)683 protected static void addTlv(ByteBuffer buf, byte type, @Nullable byte[] payload) { 684 if (payload != null) { 685 if (payload.length > MAX_OPTION_LEN) { 686 throw new IllegalArgumentException("DHCP option too long: " 687 + payload.length + " vs. " + MAX_OPTION_LEN); 688 } 689 buf.put(type); 690 buf.put((byte) payload.length); 691 buf.put(payload); 692 } 693 } 694 695 /** 696 * Adds an optional parameter containing an IP address. 697 * 698 * <p>This method is a no-op if the address argument is null. 699 */ addTlv(ByteBuffer buf, byte type, @Nullable Inet4Address addr)700 protected static void addTlv(ByteBuffer buf, byte type, @Nullable Inet4Address addr) { 701 if (addr != null) { 702 addTlv(buf, type, addr.getAddress()); 703 } 704 } 705 706 /** 707 * Adds an optional parameter containing a list of IP addresses. 708 * 709 * <p>This method is a no-op if the addresses argument is null or empty. 710 */ addTlv(ByteBuffer buf, byte type, @Nullable List<Inet4Address> addrs)711 protected static void addTlv(ByteBuffer buf, byte type, @Nullable List<Inet4Address> addrs) { 712 if (addrs == null || addrs.size() == 0) return; 713 714 int optionLen = 4 * addrs.size(); 715 if (optionLen > MAX_OPTION_LEN) { 716 throw new IllegalArgumentException("DHCP option too long: " 717 + optionLen + " vs. " + MAX_OPTION_LEN); 718 } 719 720 buf.put(type); 721 buf.put((byte)(optionLen)); 722 723 for (Inet4Address addr : addrs) { 724 buf.put(addr.getAddress()); 725 } 726 } 727 728 /** 729 * Adds an optional parameter containing a short integer. 730 * 731 * <p>This method is a no-op if the value argument is null. 732 */ addTlv(ByteBuffer buf, byte type, @Nullable Short value)733 protected static void addTlv(ByteBuffer buf, byte type, @Nullable Short value) { 734 if (value != null) { 735 buf.put(type); 736 buf.put((byte) 2); 737 buf.putShort(value.shortValue()); 738 } 739 } 740 741 /** 742 * Adds an optional parameter containing a simple integer. 743 * 744 * <p>This method is a no-op if the value argument is null. 745 */ addTlv(ByteBuffer buf, byte type, @Nullable Integer value)746 protected static void addTlv(ByteBuffer buf, byte type, @Nullable Integer value) { 747 if (value != null) { 748 buf.put(type); 749 buf.put((byte) 4); 750 buf.putInt(value.intValue()); 751 } 752 } 753 754 /** 755 * Adds an optional parameter containing an ASCII string. 756 * 757 * <p>This method is a no-op if the string argument is null. 758 */ addTlv(ByteBuffer buf, byte type, @Nullable String str)759 protected static void addTlv(ByteBuffer buf, byte type, @Nullable String str) { 760 if (str != null) { 761 try { 762 addTlv(buf, type, str.getBytes("US-ASCII")); 763 } catch (UnsupportedEncodingException e) { 764 throw new IllegalArgumentException("String is not US-ASCII: " + str); 765 } 766 } 767 } 768 769 /** 770 * Adds the special end-of-optional-parameters indicator. 771 */ addTlvEnd(ByteBuffer buf)772 protected static void addTlvEnd(ByteBuffer buf) { 773 buf.put((byte) 0xFF); 774 } 775 776 /** 777 * Get the DHCP Vendor Class Identifier. 778 * 779 * By default the vendor Id is "android-dhcp-<version>". The default value will be overwritten 780 * with the customized option value if any. 781 */ getVendorId(@ullable List<DhcpOption> customizedClientOptions)782 private static String getVendorId(@Nullable List<DhcpOption> customizedClientOptions) { 783 if (sTestOverrideVendorId != null) return sTestOverrideVendorId; 784 785 String vendorId = "android-dhcp-" + Build.VERSION.RELEASE; 786 if (customizedClientOptions != null) { 787 for (DhcpOption option : customizedClientOptions) { 788 if (option.type == DHCP_VENDOR_CLASS_ID) { 789 vendorId = readAsciiString(option.value, false); 790 break; 791 } 792 } 793 } 794 return vendorId; 795 } 796 797 /** 798 * Get the DHCP client hostname after transliteration. 799 */ 800 @VisibleForTesting getHostname()801 public String getHostname() { 802 if (mHostName == null 803 && !ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q)) { 804 return SystemProperties.get("net.hostname"); 805 } 806 return mHostName; 807 } 808 809 /** 810 * Adds common client TLVs. 811 * 812 * TODO: Does this belong here? The alternative would be to modify all the buildXyzPacket 813 * methods to take them. 814 */ addCommonClientTlvs(ByteBuffer buf)815 protected void addCommonClientTlvs(ByteBuffer buf) { 816 addTlv(buf, DHCP_MAX_MESSAGE_SIZE, (short) MAX_LENGTH); 817 addTlv(buf, DHCP_VENDOR_CLASS_ID, mVendorId); 818 final String hn = getHostname(); 819 if (!TextUtils.isEmpty(hn)) addTlv(buf, DHCP_HOST_NAME, hn); 820 } 821 822 /** 823 * Adds OEM's customized client TLVs, which will be appended before the End Tlv. 824 */ addCustomizedClientTlvs(ByteBuffer buf)825 protected void addCustomizedClientTlvs(ByteBuffer buf) { 826 if (mCustomizedClientOptions == null) return; 827 for (DhcpOption option : mCustomizedClientOptions) { 828 // A null value means the option should only be put into the PRL. 829 if (option.value == null) continue; 830 // The vendor class ID was already added by addCommonClientTlvs. 831 if (option.type == DHCP_VENDOR_CLASS_ID) continue; 832 addTlv(buf, option.type, option.value); 833 } 834 } 835 addCommonServerTlvs(ByteBuffer buf)836 protected void addCommonServerTlvs(ByteBuffer buf) { 837 addTlv(buf, DHCP_LEASE_TIME, mLeaseTime); 838 if (mLeaseTime != null && mLeaseTime != INFINITE_LEASE) { 839 // The client should renew at 1/2 the lease-expiry interval 840 addTlv(buf, DHCP_RENEWAL_TIME, (int) (Integer.toUnsignedLong(mLeaseTime) / 2)); 841 // Default rebinding time is set as below by RFC2131 842 addTlv(buf, DHCP_REBINDING_TIME, 843 (int) (Integer.toUnsignedLong(mLeaseTime) * 875L / 1000L)); 844 } 845 addTlv(buf, DHCP_SUBNET_MASK, mSubnetMask); 846 addTlv(buf, DHCP_BROADCAST_ADDRESS, mBroadcastAddress); 847 addTlv(buf, DHCP_ROUTER, mGateways); 848 addTlv(buf, DHCP_DNS_SERVER, mDnsServers); 849 addTlv(buf, DHCP_DOMAIN_NAME, mDomainName); 850 addTlv(buf, DHCP_HOST_NAME, mHostName); 851 addTlv(buf, DHCP_VENDOR_INFO, mVendorInfo); 852 if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) { 853 addTlv(buf, DHCP_MTU, mMtu); 854 } 855 if (mIpv6OnlyWaitTime != null) { 856 addTlv(buf, DHCP_IPV6_ONLY_PREFERRED, (int) Integer.toUnsignedLong(mIpv6OnlyWaitTime)); 857 } 858 addTlv(buf, DHCP_CAPTIVE_PORTAL, mCaptivePortalUrl); 859 } 860 861 /** 862 * Converts a MAC from an array of octets to an ASCII string. 863 */ macToString(byte[] mac)864 public static String macToString(byte[] mac) { 865 String macAddr = ""; 866 867 for (int i = 0; i < mac.length; i++) { 868 String hexString = "0" + Integer.toHexString(mac[i]); 869 870 // substring operation grabs the last 2 digits: this 871 // allows signed bytes to be converted correctly. 872 macAddr += hexString.substring(hexString.length() - 2); 873 874 if (i != (mac.length - 1)) { 875 macAddr += ":"; 876 } 877 } 878 879 return macAddr; 880 } 881 toString()882 public String toString() { 883 String macAddr = macToString(mClientMac); 884 885 return macAddr; 886 } 887 888 /** 889 * Reads a four-octet value from a ByteBuffer and construct 890 * an IPv4 address from that value. 891 */ readIpAddress(ByteBuffer packet)892 private static Inet4Address readIpAddress(ByteBuffer packet) { 893 Inet4Address result = null; 894 byte[] ipAddr = new byte[4]; 895 packet.get(ipAddr); 896 897 try { 898 result = (Inet4Address) Inet4Address.getByAddress(ipAddr); 899 } catch (UnknownHostException ex) { 900 // ipAddr is numeric, so this should not be 901 // triggered. However, if it is, just nullify 902 result = null; 903 } 904 905 return result; 906 } 907 908 /** 909 * Reads a string of specified length from the buffer. 910 */ readAsciiString(@onNull final ByteBuffer buf, int byteCount, boolean nullOk)911 private static String readAsciiString(@NonNull final ByteBuffer buf, int byteCount, 912 boolean nullOk) { 913 final byte[] bytes = new byte[byteCount]; 914 buf.get(bytes); 915 return readAsciiString(bytes, nullOk); 916 } 917 readAsciiString(@onNull final byte[] payload, boolean nullOk)918 private static String readAsciiString(@NonNull final byte[] payload, boolean nullOk) { 919 final byte[] bytes = payload; 920 int length = bytes.length; 921 if (!nullOk) { 922 // Stop at the first null byte. This is because some DHCP options (e.g., the domain 923 // name) are passed to netd via FrameworkListener, which refuses arguments containing 924 // null bytes. We don't do this by default because vendorInfo is an opaque string which 925 // could in theory contain null bytes. 926 for (length = 0; length < bytes.length; length++) { 927 if (bytes[length] == 0) { 928 break; 929 } 930 } 931 } 932 return new String(bytes, 0, length, StandardCharsets.US_ASCII); 933 } 934 isPacketToOrFromClient(short udpSrcPort, short udpDstPort)935 private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) { 936 return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT); 937 } 938 isPacketServerToServer(short udpSrcPort, short udpDstPort)939 private static boolean isPacketServerToServer(short udpSrcPort, short udpDstPort) { 940 return (udpSrcPort == DHCP_SERVER) && (udpDstPort == DHCP_SERVER); 941 } 942 943 public static class ParseException extends Exception { 944 public final int errorCode; ParseException(int errorCode, String msg, Object... args)945 public ParseException(int errorCode, String msg, Object... args) { 946 super(String.format(msg, args)); 947 this.errorCode = errorCode; 948 } 949 } 950 skipOption(ByteBuffer packet, int optionLen)951 private static int skipOption(ByteBuffer packet, int optionLen) 952 throws BufferUnderflowException { 953 int expectedLen = 0; 954 for (int i = 0; i < optionLen; i++) { 955 expectedLen++; 956 packet.get(); 957 } 958 return expectedLen; 959 } 960 shouldSkipOption(byte optionType, byte[] optionsToSkip)961 private static boolean shouldSkipOption(byte optionType, byte[] optionsToSkip) { 962 for (byte option : optionsToSkip) { 963 if (option == optionType) return true; 964 } 965 return false; 966 } 967 968 /** 969 * Creates a concrete DhcpPacket from the supplied ByteBuffer. The 970 * buffer may have an L2 encapsulation (which is the full EthernetII 971 * format starting with the source-address MAC) or an L3 encapsulation 972 * (which starts with the IP header). 973 * <br> 974 * A subset of the optional parameters are parsed and are stored 975 * in object fields. 976 */ 977 @VisibleForTesting decodeFullPacket(ByteBuffer packet, int pktType, byte[] optionsToSkip)978 static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType, byte[] optionsToSkip) 979 throws ParseException { 980 // bootp parameters 981 int transactionId; 982 short secs; 983 Inet4Address clientIp; 984 Inet4Address yourIp; 985 Inet4Address nextIp; 986 Inet4Address relayIp; 987 byte[] clientMac; 988 byte[] clientId = null; 989 List<Inet4Address> dnsServers = new ArrayList<>(); 990 List<Inet4Address> gateways = new ArrayList<>(); // aka router 991 Inet4Address serverIdentifier = null; 992 Inet4Address netMask = null; 993 String message = null; 994 String vendorId = null; 995 String vendorInfo = null; 996 boolean rapidCommit = false; 997 String captivePortalUrl = null; 998 byte[] expectedParams = null; 999 String hostName = null; 1000 String domainName = null; 1001 Inet4Address ipSrc = null; 1002 Inet4Address ipDst = null; 1003 Inet4Address bcAddr = null; 1004 Inet4Address requestedIp = null; 1005 String serverHostName; 1006 byte optionOverload = 0; 1007 byte[] userClass = null; 1008 1009 // The following are all unsigned integers. Internally we store them as signed integers of 1010 // the same length because that way we're guaranteed that they can't be out of the range of 1011 // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need 1012 // to cast it. 1013 Short mtu = null; 1014 Short maxMessageSize = null; 1015 Integer leaseTime = null; 1016 Integer T1 = null; 1017 Integer T2 = null; 1018 Integer ipv6OnlyWaitTime = null; 1019 1020 // dhcp options 1021 byte dhcpType = (byte) 0xFF; 1022 1023 packet.order(ByteOrder.BIG_ENDIAN); 1024 1025 // check to see if we need to parse L2, IP, and UDP encaps 1026 if (pktType == ENCAP_L2) { 1027 if (packet.remaining() < MIN_PACKET_LENGTH_L2) { 1028 throw new ParseException(DhcpErrorEvent.L2_TOO_SHORT, 1029 "L2 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L2); 1030 } 1031 1032 byte[] l2dst = new byte[6]; 1033 byte[] l2src = new byte[6]; 1034 1035 packet.get(l2dst); 1036 packet.get(l2src); 1037 1038 short l2type = packet.getShort(); 1039 1040 if (l2type != OsConstants.ETH_P_IP) { 1041 throw new ParseException(DhcpErrorEvent.L2_WRONG_ETH_TYPE, 1042 "Unexpected L2 type 0x%04x, expected 0x%04x", l2type, OsConstants.ETH_P_IP); 1043 } 1044 } 1045 1046 if (pktType <= ENCAP_L3) { 1047 if (packet.remaining() < MIN_PACKET_LENGTH_L3) { 1048 throw new ParseException(DhcpErrorEvent.L3_TOO_SHORT, 1049 "L3 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L3); 1050 } 1051 1052 byte ipTypeAndLength = packet.get(); 1053 int ipVersion = (ipTypeAndLength & 0xf0) >> 4; 1054 if (ipVersion != 4) { 1055 throw new ParseException( 1056 DhcpErrorEvent.L3_NOT_IPV4, "Invalid IP version %d", ipVersion); 1057 } 1058 1059 // System.out.println("ipType is " + ipType); 1060 byte ipDiffServicesField = packet.get(); 1061 short ipTotalLength = packet.getShort(); 1062 short ipIdentification = packet.getShort(); 1063 byte ipFlags = packet.get(); 1064 byte ipFragOffset = packet.get(); 1065 byte ipTTL = packet.get(); 1066 byte ipProto = packet.get(); 1067 short ipChksm = packet.getShort(); 1068 1069 ipSrc = readIpAddress(packet); 1070 ipDst = readIpAddress(packet); 1071 1072 if (ipProto != IP_TYPE_UDP) { 1073 throw new ParseException( 1074 DhcpErrorEvent.L4_NOT_UDP, "Protocol not UDP: %d", ipProto); 1075 } 1076 1077 // Skip options. This cannot cause us to read beyond the end of the buffer because the 1078 // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than 1079 // MIN_PACKET_LENGTH_L3. 1080 int optionWords = ((ipTypeAndLength & 0x0f) - 5); 1081 for (int i = 0; i < optionWords; i++) { 1082 packet.getInt(); 1083 } 1084 1085 // assume UDP 1086 short udpSrcPort = packet.getShort(); 1087 short udpDstPort = packet.getShort(); 1088 short udpLen = packet.getShort(); 1089 short udpChkSum = packet.getShort(); 1090 1091 // Only accept packets to or from the well-known client port (expressly permitting 1092 // packets from ports other than the well-known server port; http://b/24687559), and 1093 // server-to-server packets, e.g. for relays. 1094 if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) && 1095 !isPacketServerToServer(udpSrcPort, udpDstPort)) { 1096 // This should almost never happen because we use SO_ATTACH_FILTER on the packet 1097 // socket to drop packets that don't have the right source ports. However, it's 1098 // possible that a packet arrives between when the socket is bound and when the 1099 // filter is set. http://b/26696823 . 1100 throw new ParseException(DhcpErrorEvent.L4_WRONG_PORT, 1101 "Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort); 1102 } 1103 } 1104 1105 // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length. 1106 if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) { 1107 throw new ParseException(DhcpErrorEvent.BOOTP_TOO_SHORT, 1108 "Invalid type or BOOTP packet too short, %d < %d", 1109 packet.remaining(), MIN_PACKET_LENGTH_BOOTP); 1110 } 1111 1112 byte type = packet.get(); 1113 byte hwType = packet.get(); 1114 int addrLen = packet.get() & 0xff; 1115 byte hops = packet.get(); 1116 transactionId = packet.getInt(); 1117 secs = packet.getShort(); 1118 short bootpFlags = packet.getShort(); 1119 boolean broadcast = (bootpFlags & 0x8000) != 0; 1120 byte[] ipv4addr = new byte[4]; 1121 1122 try { 1123 packet.get(ipv4addr); 1124 clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr); 1125 packet.get(ipv4addr); 1126 yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr); 1127 packet.get(ipv4addr); 1128 nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr); 1129 packet.get(ipv4addr); 1130 relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr); 1131 } catch (UnknownHostException ex) { 1132 throw new ParseException(DhcpErrorEvent.L3_INVALID_IP, 1133 "Invalid IPv4 address: %s", Arrays.toString(ipv4addr)); 1134 } 1135 1136 // Some DHCP servers have been known to announce invalid client hardware address values such 1137 // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at 1138 // all but only checks that the interface MAC address matches the first bytes of the address 1139 // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger 1140 // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795 1141 // TODO: evaluate whether to make this test more liberal. 1142 if (addrLen > HWADDR_LEN) { 1143 addrLen = ETHER_BROADCAST.length; 1144 } 1145 1146 clientMac = new byte[addrLen]; 1147 packet.get(clientMac); 1148 1149 // skip over address padding (16 octets allocated) 1150 packet.position(packet.position() + (16 - addrLen)); 1151 serverHostName = readAsciiString(packet, 64, false); 1152 packet.position(packet.position() + 128); 1153 1154 // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211 1155 if (packet.remaining() < 4) { 1156 throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message"); 1157 } 1158 1159 int dhcpMagicCookie = packet.getInt(); 1160 if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) { 1161 throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE, 1162 "Bad magic cookie 0x%08x, should be 0x%08x", 1163 dhcpMagicCookie, DHCP_MAGIC_COOKIE); 1164 } 1165 1166 // parse options 1167 boolean notFinishedOptions = true; 1168 1169 while ((packet.position() < packet.limit()) && notFinishedOptions) { 1170 final byte optionType = packet.get(); // cannot underflow because position < limit 1171 try { 1172 if (optionType == DHCP_OPTION_END) { 1173 notFinishedOptions = false; 1174 } else if (optionType == DHCP_OPTION_PAD) { 1175 // The pad option doesn't have a length field. Nothing to do. 1176 } else { 1177 int optionLen = packet.get() & 0xFF; 1178 int expectedLen = 0; 1179 1180 if (shouldSkipOption(optionType, optionsToSkip)) { 1181 skipOption(packet, optionLen); 1182 continue; 1183 } 1184 1185 switch(optionType) { 1186 case DHCP_SUBNET_MASK: 1187 netMask = readIpAddress(packet); 1188 expectedLen = 4; 1189 break; 1190 case DHCP_ROUTER: 1191 for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) { 1192 gateways.add(readIpAddress(packet)); 1193 } 1194 break; 1195 case DHCP_DNS_SERVER: 1196 for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) { 1197 dnsServers.add(readIpAddress(packet)); 1198 } 1199 break; 1200 case DHCP_HOST_NAME: 1201 expectedLen = optionLen; 1202 hostName = readAsciiString(packet, optionLen, false); 1203 break; 1204 case DHCP_MTU: 1205 expectedLen = 2; 1206 mtu = packet.getShort(); 1207 break; 1208 case DHCP_DOMAIN_NAME: 1209 expectedLen = optionLen; 1210 domainName = readAsciiString(packet, optionLen, false); 1211 break; 1212 case DHCP_BROADCAST_ADDRESS: 1213 bcAddr = readIpAddress(packet); 1214 expectedLen = 4; 1215 break; 1216 case DHCP_REQUESTED_IP: 1217 requestedIp = readIpAddress(packet); 1218 expectedLen = 4; 1219 break; 1220 case DHCP_LEASE_TIME: 1221 leaseTime = Integer.valueOf(packet.getInt()); 1222 expectedLen = 4; 1223 break; 1224 case DHCP_MESSAGE_TYPE: 1225 dhcpType = packet.get(); 1226 expectedLen = 1; 1227 break; 1228 case DHCP_SERVER_IDENTIFIER: 1229 serverIdentifier = readIpAddress(packet); 1230 expectedLen = 4; 1231 break; 1232 case DHCP_PARAMETER_LIST: 1233 expectedParams = new byte[optionLen]; 1234 packet.get(expectedParams); 1235 expectedLen = optionLen; 1236 break; 1237 case DHCP_MESSAGE: 1238 expectedLen = optionLen; 1239 message = readAsciiString(packet, optionLen, false); 1240 break; 1241 case DHCP_MAX_MESSAGE_SIZE: 1242 expectedLen = 2; 1243 maxMessageSize = Short.valueOf(packet.getShort()); 1244 break; 1245 case DHCP_RENEWAL_TIME: 1246 expectedLen = 4; 1247 T1 = Integer.valueOf(packet.getInt()); 1248 break; 1249 case DHCP_REBINDING_TIME: 1250 expectedLen = 4; 1251 T2 = Integer.valueOf(packet.getInt()); 1252 break; 1253 case DHCP_VENDOR_CLASS_ID: 1254 expectedLen = optionLen; 1255 // Embedded nulls are safe as this does not get passed to netd. 1256 vendorId = readAsciiString(packet, optionLen, true); 1257 break; 1258 case DHCP_CLIENT_IDENTIFIER: { // Client identifier 1259 clientId = new byte[optionLen]; 1260 packet.get(clientId); 1261 expectedLen = optionLen; 1262 } break; 1263 case DHCP_VENDOR_INFO: 1264 expectedLen = optionLen; 1265 // Embedded nulls are safe as this does not get passed to netd. 1266 vendorInfo = readAsciiString(packet, optionLen, true); 1267 break; 1268 case DHCP_OPTION_OVERLOAD: 1269 expectedLen = 1; 1270 optionOverload = packet.get(); 1271 optionOverload &= OPTION_OVERLOAD_BOTH; 1272 break; 1273 case DHCP_USER_CLASS: 1274 userClass = new byte[optionLen]; 1275 packet.get(userClass); 1276 expectedLen = optionLen; 1277 break; 1278 case DHCP_RAPID_COMMIT: 1279 expectedLen = 0; 1280 rapidCommit = true; 1281 break; 1282 case DHCP_CAPTIVE_PORTAL: 1283 expectedLen = optionLen; 1284 captivePortalUrl = readAsciiString(packet, optionLen, true); 1285 break; 1286 case DHCP_IPV6_ONLY_PREFERRED: 1287 expectedLen = 4; 1288 ipv6OnlyWaitTime = Integer.valueOf(packet.getInt()); 1289 break; 1290 default: 1291 expectedLen = skipOption(packet, optionLen); 1292 } 1293 1294 if (expectedLen != optionLen) { 1295 final int errorCode = DhcpErrorEvent.errorCodeWithOption( 1296 DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType); 1297 throw new ParseException(errorCode, 1298 "Invalid length %d for option %d, expected %d", 1299 optionLen, optionType, expectedLen); 1300 } 1301 } 1302 } catch (BufferUnderflowException e) { 1303 final int errorCode = DhcpErrorEvent.errorCodeWithOption( 1304 DhcpErrorEvent.BUFFER_UNDERFLOW, optionType); 1305 throw new ParseException(errorCode, "BufferUnderflowException"); 1306 } 1307 } 1308 1309 DhcpPacket newPacket; 1310 1311 switch(dhcpType) { 1312 case (byte) 0xFF: 1313 throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE, 1314 "No DHCP message type option"); 1315 case DHCP_MESSAGE_TYPE_DISCOVER: 1316 newPacket = new DhcpDiscoverPacket(transactionId, secs, relayIp, clientMac, 1317 broadcast, ipSrc, rapidCommit); 1318 break; 1319 case DHCP_MESSAGE_TYPE_OFFER: 1320 newPacket = new DhcpOfferPacket( 1321 transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac); 1322 break; 1323 case DHCP_MESSAGE_TYPE_REQUEST: 1324 newPacket = new DhcpRequestPacket( 1325 transactionId, secs, clientIp, relayIp, clientMac, broadcast); 1326 break; 1327 case DHCP_MESSAGE_TYPE_DECLINE: 1328 newPacket = new DhcpDeclinePacket( 1329 transactionId, secs, clientIp, yourIp, nextIp, relayIp, clientMac, requestedIp, 1330 serverIdentifier); 1331 break; 1332 case DHCP_MESSAGE_TYPE_ACK: 1333 newPacket = new DhcpAckPacket( 1334 transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac, 1335 rapidCommit); 1336 break; 1337 case DHCP_MESSAGE_TYPE_NAK: 1338 newPacket = new DhcpNakPacket( 1339 transactionId, secs, relayIp, clientMac, broadcast); 1340 break; 1341 case DHCP_MESSAGE_TYPE_RELEASE: 1342 if (serverIdentifier == null) { 1343 throw new ParseException(DhcpErrorEvent.MISC_ERROR, 1344 "DHCPRELEASE without server identifier"); 1345 } 1346 newPacket = new DhcpReleasePacket( 1347 transactionId, serverIdentifier, clientIp, relayIp, clientMac); 1348 break; 1349 case DHCP_MESSAGE_TYPE_INFORM: 1350 newPacket = new DhcpInformPacket( 1351 transactionId, secs, clientIp, yourIp, nextIp, relayIp, 1352 clientMac); 1353 break; 1354 default: 1355 throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE, 1356 "Unimplemented DHCP type %d", dhcpType); 1357 } 1358 1359 newPacket.mBroadcastAddress = bcAddr; 1360 newPacket.mClientId = clientId; 1361 newPacket.mDnsServers = dnsServers; 1362 newPacket.mDomainName = domainName; 1363 newPacket.mGateways = gateways; 1364 newPacket.mHostName = hostName; 1365 newPacket.mLeaseTime = leaseTime; 1366 newPacket.mMessage = message; 1367 newPacket.mMtu = mtu; 1368 newPacket.mRequestedIp = requestedIp; 1369 newPacket.mRequestedParams = expectedParams; 1370 newPacket.mServerIdentifier = serverIdentifier; 1371 newPacket.mSubnetMask = netMask; 1372 newPacket.mMaxMessageSize = maxMessageSize; 1373 newPacket.mT1 = T1; 1374 newPacket.mT2 = T2; 1375 newPacket.mVendorId = vendorId; 1376 newPacket.mVendorInfo = vendorInfo; 1377 newPacket.mCaptivePortalUrl = captivePortalUrl; 1378 newPacket.mIpv6OnlyWaitTime = ipv6OnlyWaitTime; 1379 newPacket.mUserClass = userClass; 1380 if ((optionOverload & OPTION_OVERLOAD_SNAME) == 0) { 1381 newPacket.mServerHostName = serverHostName; 1382 } else { 1383 newPacket.mServerHostName = ""; 1384 } 1385 return newPacket; 1386 } 1387 1388 /** 1389 * Parse a packet from an array of bytes, stopping at the given length. 1390 */ decodeFullPacket(byte[] packet, int length, int pktType, byte[] optionsToSkip)1391 public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType, 1392 byte[] optionsToSkip) throws ParseException { 1393 ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN); 1394 try { 1395 return decodeFullPacket(buffer, pktType, optionsToSkip); 1396 } catch (ParseException e) { 1397 throw e; 1398 } catch (Exception e) { 1399 throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage()); 1400 } 1401 } 1402 1403 /** 1404 * Parse a packet from an array of bytes, stopping at the given length. 1405 */ decodeFullPacket(byte[] packet, int length, int pktType)1406 public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType) 1407 throws ParseException { 1408 return decodeFullPacket(packet, length, pktType, new byte[0]); 1409 } 1410 1411 /** 1412 * Construct a DhcpResults object from a DHCP reply packet. 1413 */ toDhcpResults()1414 public DhcpResults toDhcpResults() { 1415 Inet4Address ipAddress = mYourIp; 1416 if (ipAddress.equals(IPV4_ADDR_ANY)) { 1417 ipAddress = mClientIp; 1418 if (ipAddress.equals(IPV4_ADDR_ANY)) { 1419 return null; 1420 } 1421 } 1422 1423 int prefixLength; 1424 if (mSubnetMask != null) { 1425 try { 1426 prefixLength = Inet4AddressUtils.netmaskToPrefixLength(mSubnetMask); 1427 } catch (IllegalArgumentException e) { 1428 // Non-contiguous netmask. 1429 return null; 1430 } 1431 } else { 1432 prefixLength = Inet4AddressUtils.getImplicitNetmask(ipAddress); 1433 } 1434 1435 DhcpResults results = new DhcpResults(); 1436 try { 1437 results.ipAddress = new LinkAddress(ipAddress, prefixLength); 1438 } catch (IllegalArgumentException e) { 1439 return null; 1440 } 1441 1442 if (mGateways.size() > 0) { 1443 results.gateway = mGateways.get(0); 1444 } 1445 1446 results.dnsServers.addAll(mDnsServers); 1447 results.domains = mDomainName; 1448 results.serverAddress = mServerIdentifier; 1449 results.vendorInfo = mVendorInfo; 1450 results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE; 1451 results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0; 1452 results.serverHostName = mServerHostName; 1453 results.captivePortalApiUrl = mCaptivePortalUrl; 1454 1455 return results; 1456 } 1457 1458 /** 1459 * Returns the parsed lease time, in milliseconds, or 0 for infinite. 1460 */ getLeaseTimeMillis()1461 public long getLeaseTimeMillis() { 1462 // dhcpcd treats the lack of a lease time option as an infinite lease. 1463 if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) { 1464 return 0; 1465 } else if (0 <= mLeaseTime && mLeaseTime < MINIMUM_LEASE) { 1466 return MINIMUM_LEASE * 1000; 1467 } else { 1468 return (mLeaseTime & 0xffffffffL) * 1000; 1469 } 1470 } 1471 1472 /** 1473 * Returns the IPv6-only wait time, in milliseconds, or -1 if the option is not present. 1474 */ getIpv6OnlyWaitTimeMillis()1475 public long getIpv6OnlyWaitTimeMillis() { 1476 if (mIpv6OnlyWaitTime == null) return V6ONLY_PREFERRED_ABSENCE; 1477 return Math.max(MIN_V6ONLY_WAIT_MS, Integer.toUnsignedLong(mIpv6OnlyWaitTime) * 1000); 1478 } 1479 1480 /** 1481 * Builds a DHCP-DISCOVER packet from the required specified parameters. 1482 */ buildDiscoverPacket(int encap, int transactionId, short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, boolean rapidCommit, String hostname, List<DhcpOption> options)1483 public static ByteBuffer buildDiscoverPacket(int encap, int transactionId, 1484 short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, 1485 boolean rapidCommit, String hostname, List<DhcpOption> options) { 1486 DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */, 1487 clientMac, broadcast, INADDR_ANY /* srcIp */, rapidCommit); 1488 pkt.mRequestedParams = expectedParams; 1489 pkt.mHostName = hostname; 1490 pkt.mCustomizedClientOptions = options; 1491 pkt.mVendorId = getVendorId(options); 1492 return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 1493 } 1494 1495 /** 1496 * Builds a DHCP-DISCOVER packet from the required specified parameters. 1497 * 1498 * TODO: remove this method when automerger to mainline-prod is running. 1499 */ buildDiscoverPacket(int encap, int transactionId, short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, boolean rapidCommit, String hostname)1500 public static ByteBuffer buildDiscoverPacket(int encap, int transactionId, 1501 short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, 1502 boolean rapidCommit, String hostname) { 1503 return buildDiscoverPacket(encap, transactionId, secs, clientMac, broadcast, 1504 expectedParams, rapidCommit, hostname, new ArrayList<DhcpOption>()); 1505 } 1506 1507 /** 1508 * Builds a DHCP-OFFER packet from the required specified parameters. 1509 */ buildOfferPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, short mtu, String captivePortalUrl, Integer ipv6OnlyWaitTime)1510 public static ByteBuffer buildOfferPacket(int encap, int transactionId, 1511 boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, 1512 Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, 1513 Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1514 Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, 1515 short mtu, String captivePortalUrl, Integer ipv6OnlyWaitTime) { 1516 DhcpPacket pkt = new DhcpOfferPacket( 1517 transactionId, (short) 0, broadcast, serverIpAddr, relayIp, 1518 INADDR_ANY /* clientIp */, yourIp, mac); 1519 pkt.mGateways = gateways; 1520 pkt.mDnsServers = dnsServers; 1521 pkt.mLeaseTime = timeout; 1522 pkt.mDomainName = domainName; 1523 pkt.mHostName = hostname; 1524 pkt.mServerIdentifier = dhcpServerIdentifier; 1525 pkt.mSubnetMask = netMask; 1526 pkt.mBroadcastAddress = bcAddr; 1527 pkt.mMtu = mtu; 1528 pkt.mCaptivePortalUrl = captivePortalUrl; 1529 if (metered) { 1530 pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED; 1531 } 1532 if (ipv6OnlyWaitTime != null) { 1533 pkt.mIpv6OnlyWaitTime = ipv6OnlyWaitTime; 1534 } 1535 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 1536 } 1537 1538 /** 1539 * Builds a DHCP-OFFER packet from the required specified parameters. 1540 */ buildOfferPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, short mtu, String captivePortalUrl)1541 public static ByteBuffer buildOfferPacket(int encap, int transactionId, 1542 boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, 1543 Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, 1544 Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1545 Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, 1546 short mtu, String captivePortalUrl) { 1547 return buildOfferPacket(encap, transactionId, broadcast, serverIpAddr, relayIp, yourIp, 1548 mac, timeout, netMask, bcAddr, gateways, dnsServers, dhcpServerIdentifier, 1549 domainName, hostname, metered, mtu, captivePortalUrl, null /* V6ONLY_WAIT */); 1550 } 1551 1552 /** 1553 * Builds a DHCP-ACK packet from the required specified parameters. 1554 */ buildAckPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, short mtu, boolean rapidCommit, String captivePortalUrl, Integer ipv6OnlyWaitTime)1555 public static ByteBuffer buildAckPacket(int encap, int transactionId, 1556 boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, 1557 Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, 1558 Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1559 Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, 1560 short mtu, boolean rapidCommit, String captivePortalUrl, Integer ipv6OnlyWaitTime) { 1561 DhcpPacket pkt = new DhcpAckPacket( 1562 transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp, 1563 mac, rapidCommit); 1564 pkt.mGateways = gateways; 1565 pkt.mDnsServers = dnsServers; 1566 pkt.mLeaseTime = timeout; 1567 pkt.mDomainName = domainName; 1568 pkt.mHostName = hostname; 1569 pkt.mSubnetMask = netMask; 1570 pkt.mServerIdentifier = dhcpServerIdentifier; 1571 pkt.mBroadcastAddress = bcAddr; 1572 pkt.mMtu = mtu; 1573 pkt.mCaptivePortalUrl = captivePortalUrl; 1574 if (metered) { 1575 pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED; 1576 } 1577 if (ipv6OnlyWaitTime != null) { 1578 pkt.mIpv6OnlyWaitTime = ipv6OnlyWaitTime; 1579 } 1580 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 1581 } 1582 1583 /** 1584 * Builds a DHCP-ACK packet from the required specified parameters. 1585 */ buildAckPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, short mtu, boolean rapidCommit, String captivePortalUrl)1586 public static ByteBuffer buildAckPacket(int encap, int transactionId, 1587 boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, 1588 Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, 1589 Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1590 Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, 1591 short mtu, boolean rapidCommit, String captivePortalUrl) { 1592 return buildAckPacket(encap, transactionId, broadcast, serverIpAddr, relayIp, yourIp, 1593 requestClientIp, mac, timeout, netMask, bcAddr, gateways, dnsServers, 1594 dhcpServerIdentifier, domainName, hostname, metered, mtu, rapidCommit, 1595 captivePortalUrl, null /* V6ONLY_WAIT */); 1596 } 1597 1598 /** 1599 * Builds a DHCP-NAK packet from the required specified parameters. 1600 */ buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr, Inet4Address relayIp, byte[] mac, boolean broadcast, String message)1601 public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr, 1602 Inet4Address relayIp, byte[] mac, boolean broadcast, String message) { 1603 DhcpPacket pkt = new DhcpNakPacket( 1604 transactionId, (short) 0, relayIp, mac, broadcast); 1605 pkt.mMessage = message; 1606 pkt.mServerIdentifier = serverIpAddr; 1607 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 1608 } 1609 1610 /** 1611 * Builds a DHCP-REQUEST packet from the required specified parameters. 1612 */ buildRequestPacket(int encap, int transactionId, short secs, Inet4Address clientIp, boolean broadcast, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier, byte[] requestedParams, String hostName, List<DhcpOption> options)1613 public static ByteBuffer buildRequestPacket(int encap, 1614 int transactionId, short secs, Inet4Address clientIp, boolean broadcast, 1615 byte[] clientMac, Inet4Address requestedIpAddress, 1616 Inet4Address serverIdentifier, byte[] requestedParams, String hostName, 1617 List<DhcpOption> options) { 1618 DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp, 1619 INADDR_ANY /* relayIp */, clientMac, broadcast); 1620 pkt.mRequestedIp = requestedIpAddress; 1621 pkt.mServerIdentifier = serverIdentifier; 1622 pkt.mHostName = hostName; 1623 pkt.mRequestedParams = requestedParams; 1624 pkt.mCustomizedClientOptions = options; 1625 pkt.mVendorId = getVendorId(options); 1626 ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 1627 return result; 1628 } 1629 1630 /** 1631 * Builds a DHCP-REQUEST packet from the required specified parameters. 1632 * 1633 * TODO: remove this method when automerger to mainline-prod is running. 1634 */ buildRequestPacket(int encap, int transactionId, short secs, Inet4Address clientIp, boolean broadcast, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier, byte[] requestedParams, String hostName)1635 public static ByteBuffer buildRequestPacket(int encap, 1636 int transactionId, short secs, Inet4Address clientIp, boolean broadcast, 1637 byte[] clientMac, Inet4Address requestedIpAddress, 1638 Inet4Address serverIdentifier, byte[] requestedParams, String hostName) { 1639 return buildRequestPacket(encap, transactionId, secs, clientIp, broadcast, clientMac, 1640 requestedIpAddress, serverIdentifier, requestedParams, hostName, 1641 new ArrayList<DhcpOption>()); 1642 } 1643 1644 /** 1645 * Builds a DHCP-DECLINE packet from the required specified parameters. 1646 */ buildDeclinePacket(int encap, int transactionId, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier)1647 public static ByteBuffer buildDeclinePacket(int encap, int transactionId, byte[] clientMac, 1648 Inet4Address requestedIpAddress, Inet4Address serverIdentifier) { 1649 DhcpPacket pkt = new DhcpDeclinePacket(transactionId, (short) 0 /* secs */, 1650 INADDR_ANY /* clientIp */, INADDR_ANY /* yourIp */, INADDR_ANY /* nextIp */, 1651 INADDR_ANY /* relayIp */, clientMac, requestedIpAddress, serverIdentifier); 1652 ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 1653 return result; 1654 } 1655 } 1656