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