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