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