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.modules.utils.build.SdkLevel.isAtLeastR; 20 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ALL; 21 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY; 22 23 import android.net.DhcpResults; 24 import android.net.LinkAddress; 25 import android.net.metrics.DhcpErrorEvent; 26 import android.net.networkstack.aidl.dhcp.DhcpOption; 27 import android.os.Build; 28 import android.os.SystemProperties; 29 import android.system.OsConstants; 30 import android.text.TextUtils; 31 32 import androidx.annotation.NonNull; 33 import androidx.annotation.Nullable; 34 import androidx.annotation.VisibleForTesting; 35 36 import com.android.net.module.util.Inet4AddressUtils; 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 && !isAtLeastR()) { 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 default: 1349 throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE, 1350 "Unimplemented DHCP type %d", dhcpType); 1351 } 1352 1353 newPacket.mBroadcastAddress = bcAddr; 1354 newPacket.mClientId = clientId; 1355 newPacket.mDnsServers = dnsServers; 1356 newPacket.mDomainName = domainName; 1357 newPacket.mGateways = gateways; 1358 newPacket.mHostName = hostName; 1359 newPacket.mLeaseTime = leaseTime; 1360 newPacket.mMessage = message; 1361 newPacket.mMtu = mtu; 1362 newPacket.mRequestedIp = requestedIp; 1363 newPacket.mRequestedParams = expectedParams; 1364 newPacket.mServerIdentifier = serverIdentifier; 1365 newPacket.mSubnetMask = netMask; 1366 newPacket.mMaxMessageSize = maxMessageSize; 1367 newPacket.mT1 = T1; 1368 newPacket.mT2 = T2; 1369 newPacket.mVendorId = vendorId; 1370 newPacket.mVendorInfo = vendorInfo; 1371 newPacket.mCaptivePortalUrl = captivePortalUrl; 1372 newPacket.mIpv6OnlyWaitTime = ipv6OnlyWaitTime; 1373 newPacket.mUserClass = userClass; 1374 if ((optionOverload & OPTION_OVERLOAD_SNAME) == 0) { 1375 newPacket.mServerHostName = serverHostName; 1376 } else { 1377 newPacket.mServerHostName = ""; 1378 } 1379 return newPacket; 1380 } 1381 1382 /** 1383 * Parse a packet from an array of bytes, stopping at the given length. 1384 */ decodeFullPacket(byte[] packet, int length, int pktType, byte[] optionsToSkip)1385 public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType, 1386 byte[] optionsToSkip) throws ParseException { 1387 ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN); 1388 try { 1389 return decodeFullPacket(buffer, pktType, optionsToSkip); 1390 } catch (ParseException e) { 1391 throw e; 1392 } catch (Exception e) { 1393 throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage()); 1394 } 1395 } 1396 1397 /** 1398 * Parse a packet from an array of bytes, stopping at the given length. 1399 */ decodeFullPacket(byte[] packet, int length, int pktType)1400 public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType) 1401 throws ParseException { 1402 return decodeFullPacket(packet, length, pktType, new byte[0]); 1403 } 1404 1405 /** 1406 * Construct a DhcpResults object from a DHCP reply packet. 1407 */ toDhcpResults()1408 public DhcpResults toDhcpResults() { 1409 Inet4Address ipAddress = mYourIp; 1410 if (ipAddress.equals(IPV4_ADDR_ANY)) { 1411 ipAddress = mClientIp; 1412 if (ipAddress.equals(IPV4_ADDR_ANY)) { 1413 return null; 1414 } 1415 } 1416 1417 int prefixLength; 1418 if (mSubnetMask != null) { 1419 try { 1420 prefixLength = Inet4AddressUtils.netmaskToPrefixLength(mSubnetMask); 1421 } catch (IllegalArgumentException e) { 1422 // Non-contiguous netmask. 1423 return null; 1424 } 1425 } else { 1426 prefixLength = Inet4AddressUtils.getImplicitNetmask(ipAddress); 1427 } 1428 1429 DhcpResults results = new DhcpResults(); 1430 try { 1431 results.ipAddress = new LinkAddress(ipAddress, prefixLength); 1432 } catch (IllegalArgumentException e) { 1433 return null; 1434 } 1435 1436 if (mGateways.size() > 0) { 1437 results.gateway = mGateways.get(0); 1438 } 1439 1440 results.dnsServers.addAll(mDnsServers); 1441 results.domains = mDomainName; 1442 results.serverAddress = mServerIdentifier; 1443 results.vendorInfo = mVendorInfo; 1444 results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE; 1445 results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0; 1446 results.serverHostName = mServerHostName; 1447 results.captivePortalApiUrl = mCaptivePortalUrl; 1448 1449 return results; 1450 } 1451 1452 /** 1453 * Returns the parsed lease time, in milliseconds, or 0 for infinite. 1454 */ getLeaseTimeMillis()1455 public long getLeaseTimeMillis() { 1456 // dhcpcd treats the lack of a lease time option as an infinite lease. 1457 if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) { 1458 return 0; 1459 } else if (0 <= mLeaseTime && mLeaseTime < MINIMUM_LEASE) { 1460 return MINIMUM_LEASE * 1000; 1461 } else { 1462 return (mLeaseTime & 0xffffffffL) * 1000; 1463 } 1464 } 1465 1466 /** 1467 * Returns the IPv6-only wait time, in milliseconds, or -1 if the option is not present. 1468 */ getIpv6OnlyWaitTimeMillis()1469 public long getIpv6OnlyWaitTimeMillis() { 1470 if (mIpv6OnlyWaitTime == null) return V6ONLY_PREFERRED_ABSENCE; 1471 return Math.max(MIN_V6ONLY_WAIT_MS, Integer.toUnsignedLong(mIpv6OnlyWaitTime) * 1000); 1472 } 1473 1474 /** 1475 * Builds a DHCP-DISCOVER packet from the required specified parameters. 1476 */ buildDiscoverPacket(int encap, int transactionId, short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, boolean rapidCommit, String hostname, List<DhcpOption> options)1477 public static ByteBuffer buildDiscoverPacket(int encap, int transactionId, 1478 short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, 1479 boolean rapidCommit, String hostname, List<DhcpOption> options) { 1480 DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */, 1481 clientMac, broadcast, INADDR_ANY /* srcIp */, rapidCommit); 1482 pkt.mRequestedParams = expectedParams; 1483 pkt.mHostName = hostname; 1484 pkt.mCustomizedClientOptions = options; 1485 pkt.mVendorId = getVendorId(options); 1486 return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 1487 } 1488 1489 /** 1490 * Builds a DHCP-DISCOVER packet from the required specified parameters. 1491 * 1492 * TODO: remove this method when automerger to mainline-prod is running. 1493 */ buildDiscoverPacket(int encap, int transactionId, short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, boolean rapidCommit, String hostname)1494 public static ByteBuffer buildDiscoverPacket(int encap, int transactionId, 1495 short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, 1496 boolean rapidCommit, String hostname) { 1497 return buildDiscoverPacket(encap, transactionId, secs, clientMac, broadcast, 1498 expectedParams, rapidCommit, hostname, new ArrayList<DhcpOption>()); 1499 } 1500 1501 /** 1502 * Builds a DHCP-OFFER packet from the required specified parameters. 1503 */ 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)1504 public static ByteBuffer buildOfferPacket(int encap, int transactionId, 1505 boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, 1506 Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, 1507 Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1508 Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, 1509 short mtu, String captivePortalUrl, Integer ipv6OnlyWaitTime) { 1510 DhcpPacket pkt = new DhcpOfferPacket( 1511 transactionId, (short) 0, broadcast, serverIpAddr, relayIp, 1512 INADDR_ANY /* clientIp */, yourIp, mac); 1513 pkt.mGateways = gateways; 1514 pkt.mDnsServers = dnsServers; 1515 pkt.mLeaseTime = timeout; 1516 pkt.mDomainName = domainName; 1517 pkt.mHostName = hostname; 1518 pkt.mServerIdentifier = dhcpServerIdentifier; 1519 pkt.mSubnetMask = netMask; 1520 pkt.mBroadcastAddress = bcAddr; 1521 pkt.mMtu = mtu; 1522 pkt.mCaptivePortalUrl = captivePortalUrl; 1523 if (metered) { 1524 pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED; 1525 } 1526 if (ipv6OnlyWaitTime != null) { 1527 pkt.mIpv6OnlyWaitTime = ipv6OnlyWaitTime; 1528 } 1529 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 1530 } 1531 1532 /** 1533 * Builds a DHCP-OFFER packet from the required specified parameters. 1534 */ 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)1535 public static ByteBuffer buildOfferPacket(int encap, int transactionId, 1536 boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, 1537 Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, 1538 Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1539 Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, 1540 short mtu, String captivePortalUrl) { 1541 return buildOfferPacket(encap, transactionId, broadcast, serverIpAddr, relayIp, yourIp, 1542 mac, timeout, netMask, bcAddr, gateways, dnsServers, dhcpServerIdentifier, 1543 domainName, hostname, metered, mtu, captivePortalUrl, null /* V6ONLY_WAIT */); 1544 } 1545 1546 /** 1547 * Builds a DHCP-ACK packet from the required specified parameters. 1548 */ 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)1549 public static ByteBuffer buildAckPacket(int encap, int transactionId, 1550 boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, 1551 Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, 1552 Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1553 Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, 1554 short mtu, boolean rapidCommit, String captivePortalUrl, Integer ipv6OnlyWaitTime) { 1555 DhcpPacket pkt = new DhcpAckPacket( 1556 transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp, 1557 mac, rapidCommit); 1558 pkt.mGateways = gateways; 1559 pkt.mDnsServers = dnsServers; 1560 pkt.mLeaseTime = timeout; 1561 pkt.mDomainName = domainName; 1562 pkt.mHostName = hostname; 1563 pkt.mSubnetMask = netMask; 1564 pkt.mServerIdentifier = dhcpServerIdentifier; 1565 pkt.mBroadcastAddress = bcAddr; 1566 pkt.mMtu = mtu; 1567 pkt.mCaptivePortalUrl = captivePortalUrl; 1568 if (metered) { 1569 pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED; 1570 } 1571 if (ipv6OnlyWaitTime != null) { 1572 pkt.mIpv6OnlyWaitTime = ipv6OnlyWaitTime; 1573 } 1574 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 1575 } 1576 1577 /** 1578 * Builds a DHCP-ACK packet from the required specified parameters. 1579 */ 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)1580 public static ByteBuffer buildAckPacket(int encap, int transactionId, 1581 boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, 1582 Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, 1583 Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1584 Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, 1585 short mtu, boolean rapidCommit, String captivePortalUrl) { 1586 return buildAckPacket(encap, transactionId, broadcast, serverIpAddr, relayIp, yourIp, 1587 requestClientIp, mac, timeout, netMask, bcAddr, gateways, dnsServers, 1588 dhcpServerIdentifier, domainName, hostname, metered, mtu, rapidCommit, 1589 captivePortalUrl, null /* V6ONLY_WAIT */); 1590 } 1591 1592 /** 1593 * Builds a DHCP-NAK packet from the required specified parameters. 1594 */ buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr, Inet4Address relayIp, byte[] mac, boolean broadcast, String message)1595 public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr, 1596 Inet4Address relayIp, byte[] mac, boolean broadcast, String message) { 1597 DhcpPacket pkt = new DhcpNakPacket( 1598 transactionId, (short) 0, relayIp, mac, broadcast); 1599 pkt.mMessage = message; 1600 pkt.mServerIdentifier = serverIpAddr; 1601 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 1602 } 1603 1604 /** 1605 * Builds a DHCP-REQUEST packet from the required specified parameters. 1606 */ buildRequestPacket(int encap, int transactionId, short secs, Inet4Address clientIp, boolean broadcast, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier, byte[] requestedParams, String hostName, List<DhcpOption> options)1607 public static ByteBuffer buildRequestPacket(int encap, 1608 int transactionId, short secs, Inet4Address clientIp, boolean broadcast, 1609 byte[] clientMac, Inet4Address requestedIpAddress, 1610 Inet4Address serverIdentifier, byte[] requestedParams, String hostName, 1611 List<DhcpOption> options) { 1612 DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp, 1613 INADDR_ANY /* relayIp */, clientMac, broadcast); 1614 pkt.mRequestedIp = requestedIpAddress; 1615 pkt.mServerIdentifier = serverIdentifier; 1616 pkt.mHostName = hostName; 1617 pkt.mRequestedParams = requestedParams; 1618 pkt.mCustomizedClientOptions = options; 1619 pkt.mVendorId = getVendorId(options); 1620 ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 1621 return result; 1622 } 1623 1624 /** 1625 * Builds a DHCP-REQUEST packet from the required specified parameters. 1626 * 1627 * TODO: remove this method when automerger to mainline-prod is running. 1628 */ buildRequestPacket(int encap, int transactionId, short secs, Inet4Address clientIp, boolean broadcast, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier, byte[] requestedParams, String hostName)1629 public static ByteBuffer buildRequestPacket(int encap, 1630 int transactionId, short secs, Inet4Address clientIp, boolean broadcast, 1631 byte[] clientMac, Inet4Address requestedIpAddress, 1632 Inet4Address serverIdentifier, byte[] requestedParams, String hostName) { 1633 return buildRequestPacket(encap, transactionId, secs, clientIp, broadcast, clientMac, 1634 requestedIpAddress, serverIdentifier, requestedParams, hostName, 1635 new ArrayList<DhcpOption>()); 1636 } 1637 1638 /** 1639 * Builds a DHCP-DECLINE packet from the required specified parameters. 1640 */ buildDeclinePacket(int encap, int transactionId, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier)1641 public static ByteBuffer buildDeclinePacket(int encap, int transactionId, byte[] clientMac, 1642 Inet4Address requestedIpAddress, Inet4Address serverIdentifier) { 1643 DhcpPacket pkt = new DhcpDeclinePacket(transactionId, (short) 0 /* secs */, 1644 INADDR_ANY /* clientIp */, INADDR_ANY /* yourIp */, INADDR_ANY /* nextIp */, 1645 INADDR_ANY /* relayIp */, clientMac, requestedIpAddress, serverIdentifier); 1646 ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 1647 return result; 1648 } 1649 } 1650