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