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