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