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