1 package android.net.dhcp; 2 3 import java.net.InetAddress; 4 import java.net.UnknownHostException; 5 import java.nio.ByteBuffer; 6 import java.nio.ByteOrder; 7 import java.nio.charset.StandardCharsets; 8 import java.nio.ShortBuffer; 9 10 import java.util.ArrayList; 11 import java.util.List; 12 13 /** 14 * Defines basic data and operations needed to build and use packets for the 15 * DHCP protocol. Subclasses create the specific packets used at each 16 * stage of the negotiation. 17 */ 18 abstract class DhcpPacket { 19 protected static final String TAG = "DhcpPacket"; 20 21 /** 22 * Packet encapsulations. 23 */ 24 public static final int ENCAP_L2 = 0; // EthernetII header included 25 public static final int ENCAP_L3 = 1; // IP/UDP header included 26 public static final int ENCAP_BOOTP = 2; // BOOTP contents only 27 28 /** 29 * IP layer definitions. 30 */ 31 private static final byte IP_TYPE_UDP = (byte) 0x11; 32 33 /** 34 * IP: Version 4, Header Length 20 bytes 35 */ 36 private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45; 37 38 /** 39 * IP: Flags 0, Fragment Offset 0, Don't Fragment 40 */ 41 private static final short IP_FLAGS_OFFSET = (short) 0x4000; 42 43 /** 44 * IP: TOS 45 */ 46 private static final byte IP_TOS_LOWDELAY = (byte) 0x10; 47 48 /** 49 * IP: TTL -- use default 64 from RFC1340 50 */ 51 private static final byte IP_TTL = (byte) 0x40; 52 53 /** 54 * The client DHCP port. 55 */ 56 static final short DHCP_CLIENT = (short) 68; 57 58 /** 59 * The server DHCP port. 60 */ 61 static final short DHCP_SERVER = (short) 67; 62 63 /** 64 * The message op code indicating a request from a client. 65 */ 66 protected static final byte DHCP_BOOTREQUEST = (byte) 1; 67 68 /** 69 * The message op code indicating a response from the server. 70 */ 71 protected static final byte DHCP_BOOTREPLY = (byte) 2; 72 73 /** 74 * The code type used to identify an Ethernet MAC address in the 75 * Client-ID field. 76 */ 77 protected static final byte CLIENT_ID_ETHER = (byte) 1; 78 79 /** 80 * The maximum length of a packet that can be constructed. 81 */ 82 protected static final int MAX_LENGTH = 1500; 83 84 /** 85 * DHCP Optional Type: DHCP Subnet Mask 86 */ 87 protected static final byte DHCP_SUBNET_MASK = 1; 88 protected InetAddress mSubnetMask; 89 90 /** 91 * DHCP Optional Type: DHCP Router 92 */ 93 protected static final byte DHCP_ROUTER = 3; 94 protected InetAddress mGateway; 95 96 /** 97 * DHCP Optional Type: DHCP DNS Server 98 */ 99 protected static final byte DHCP_DNS_SERVER = 6; 100 protected List<InetAddress> mDnsServers; 101 102 /** 103 * DHCP Optional Type: DHCP Host Name 104 */ 105 protected static final byte DHCP_HOST_NAME = 12; 106 protected String mHostName; 107 108 /** 109 * DHCP Optional Type: DHCP DOMAIN NAME 110 */ 111 protected static final byte DHCP_DOMAIN_NAME = 15; 112 protected String mDomainName; 113 114 /** 115 * DHCP Optional Type: DHCP BROADCAST ADDRESS 116 */ 117 protected static final byte DHCP_BROADCAST_ADDRESS = 28; 118 protected InetAddress mBroadcastAddress; 119 120 /** 121 * DHCP Optional Type: DHCP Requested IP Address 122 */ 123 protected static final byte DHCP_REQUESTED_IP = 50; 124 protected InetAddress mRequestedIp; 125 126 /** 127 * DHCP Optional Type: DHCP Lease Time 128 */ 129 protected static final byte DHCP_LEASE_TIME = 51; 130 protected Integer mLeaseTime; 131 132 /** 133 * DHCP Optional Type: DHCP Message Type 134 */ 135 protected static final byte DHCP_MESSAGE_TYPE = 53; 136 // the actual type values 137 protected static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1; 138 protected static final byte DHCP_MESSAGE_TYPE_OFFER = 2; 139 protected static final byte DHCP_MESSAGE_TYPE_REQUEST = 3; 140 protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4; 141 protected static final byte DHCP_MESSAGE_TYPE_ACK = 5; 142 protected static final byte DHCP_MESSAGE_TYPE_NAK = 6; 143 protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8; 144 145 /** 146 * DHCP Optional Type: DHCP Server Identifier 147 */ 148 protected static final byte DHCP_SERVER_IDENTIFIER = 54; 149 protected InetAddress mServerIdentifier; 150 151 /** 152 * DHCP Optional Type: DHCP Parameter List 153 */ 154 protected static final byte DHCP_PARAMETER_LIST = 55; 155 protected byte[] mRequestedParams; 156 157 /** 158 * DHCP Optional Type: DHCP MESSAGE 159 */ 160 protected static final byte DHCP_MESSAGE = 56; 161 protected String mMessage; 162 163 /** 164 * DHCP Optional Type: DHCP Renewal Time Value 165 */ 166 protected static final byte DHCP_RENEWAL_TIME = 58; 167 168 /** 169 * DHCP Optional Type: Vendor Class Identifier 170 */ 171 protected static final byte DHCP_VENDOR_CLASS_ID = 60; 172 173 /** 174 * DHCP Optional Type: DHCP Client Identifier 175 */ 176 protected static final byte DHCP_CLIENT_IDENTIFIER = 61; 177 178 /** 179 * The transaction identifier used in this particular DHCP negotiation 180 */ 181 protected final int mTransId; 182 183 /** 184 * The IP address of the client host. This address is typically 185 * proposed by the client (from an earlier DHCP negotiation) or 186 * supplied by the server. 187 */ 188 protected final InetAddress mClientIp; 189 protected final InetAddress mYourIp; 190 private final InetAddress mNextIp; 191 private final InetAddress mRelayIp; 192 193 /** 194 * Does the client request a broadcast response? 195 */ 196 protected boolean mBroadcast; 197 198 /** 199 * The six-octet MAC of the client. 200 */ 201 protected final byte[] mClientMac; 202 203 /** 204 * Asks the packet object to signal the next operation in the DHCP 205 * protocol. The available actions are methods defined in the 206 * DhcpStateMachine interface. 207 */ doNextOp(DhcpStateMachine stateMachine)208 public abstract void doNextOp(DhcpStateMachine stateMachine); 209 210 /** 211 * Asks the packet object to create a ByteBuffer serialization of 212 * the packet for transmission. 213 */ buildPacket(int encap, short destUdp, short srcUdp)214 public abstract ByteBuffer buildPacket(int encap, short destUdp, 215 short srcUdp); 216 217 /** 218 * Allows the concrete class to fill in packet-type-specific details, 219 * typically optional parameters at the end of the packet. 220 */ finishPacket(ByteBuffer buffer)221 abstract void finishPacket(ByteBuffer buffer); 222 DhcpPacket(int transId, InetAddress clientIp, InetAddress yourIp, InetAddress nextIp, InetAddress relayIp, byte[] clientMac, boolean broadcast)223 protected DhcpPacket(int transId, InetAddress clientIp, InetAddress yourIp, 224 InetAddress nextIp, InetAddress relayIp, 225 byte[] clientMac, boolean broadcast) { 226 mTransId = transId; 227 mClientIp = clientIp; 228 mYourIp = yourIp; 229 mNextIp = nextIp; 230 mRelayIp = relayIp; 231 mClientMac = clientMac; 232 mBroadcast = broadcast; 233 } 234 235 /** 236 * Returns the transaction ID. 237 */ getTransactionId()238 public int getTransactionId() { 239 return mTransId; 240 } 241 242 /** 243 * Creates a new L3 packet (including IP header) containing the 244 * DHCP udp packet. This method relies upon the delegated method 245 * finishPacket() to insert the per-packet contents. 246 */ fillInPacket(int encap, InetAddress destIp, InetAddress srcIp, short destUdp, short srcUdp, ByteBuffer buf, byte requestCode, boolean broadcast)247 protected void fillInPacket(int encap, InetAddress destIp, 248 InetAddress srcIp, short destUdp, short srcUdp, ByteBuffer buf, 249 byte requestCode, boolean broadcast) { 250 byte[] destIpArray = destIp.getAddress(); 251 byte[] srcIpArray = srcIp.getAddress(); 252 int ipLengthOffset = 0; 253 int ipChecksumOffset = 0; 254 int endIpHeader = 0; 255 int udpHeaderOffset = 0; 256 int udpLengthOffset = 0; 257 int udpChecksumOffset = 0; 258 259 buf.clear(); 260 buf.order(ByteOrder.BIG_ENDIAN); 261 262 // if a full IP packet needs to be generated, put the IP & UDP 263 // headers in place, and pre-populate with artificial values 264 // needed to seed the IP checksum. 265 if (encap == ENCAP_L3) { 266 // fake IP header, used in the IP-header checksum 267 buf.put(IP_VERSION_HEADER_LEN); 268 buf.put(IP_TOS_LOWDELAY); // tos: IPTOS_LOWDELAY 269 ipLengthOffset = buf.position(); 270 buf.putShort((short)0); // length 271 buf.putShort((short)0); // id 272 buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment 273 buf.put(IP_TTL); // TTL: use default 64 from RFC1340 274 buf.put(IP_TYPE_UDP); 275 ipChecksumOffset = buf.position(); 276 buf.putShort((short) 0); // checksum 277 278 buf.put(srcIpArray); 279 buf.put(destIpArray); 280 endIpHeader = buf.position(); 281 282 // UDP header 283 udpHeaderOffset = buf.position(); 284 buf.putShort(srcUdp); 285 buf.putShort(destUdp); 286 udpLengthOffset = buf.position(); 287 buf.putShort((short) 0); // length 288 udpChecksumOffset = buf.position(); 289 buf.putShort((short) 0); // UDP checksum -- initially zero 290 } 291 292 // DHCP payload 293 buf.put(requestCode); 294 buf.put((byte) 1); // Hardware Type: Ethernet 295 buf.put((byte) mClientMac.length); // Hardware Address Length 296 buf.put((byte) 0); // Hop Count 297 buf.putInt(mTransId); // Transaction ID 298 buf.putShort((short) 0); // Elapsed Seconds 299 300 if (broadcast) { 301 buf.putShort((short) 0x8000); // Flags 302 } else { 303 buf.putShort((short) 0x0000); // Flags 304 } 305 306 buf.put(mClientIp.getAddress()); 307 buf.put(mYourIp.getAddress()); 308 buf.put(mNextIp.getAddress()); 309 buf.put(mRelayIp.getAddress()); 310 buf.put(mClientMac); 311 buf.position(buf.position() + 312 (16 - mClientMac.length) // pad addr to 16 bytes 313 + 64 // empty server host name (64 bytes) 314 + 128); // empty boot file name (128 bytes) 315 buf.putInt(0x63825363); // magic number 316 finishPacket(buf); 317 318 // round up to an even number of octets 319 if ((buf.position() & 1) == 1) { 320 buf.put((byte) 0); 321 } 322 323 // If an IP packet is being built, the IP & UDP checksums must be 324 // computed. 325 if (encap == ENCAP_L3) { 326 // fix UDP header: insert length 327 short udpLen = (short)(buf.position() - udpHeaderOffset); 328 buf.putShort(udpLengthOffset, udpLen); 329 // fix UDP header: checksum 330 // checksum for UDP at udpChecksumOffset 331 int udpSeed = 0; 332 333 // apply IPv4 pseudo-header. Read IP address src and destination 334 // values from the IP header and accumulate checksum. 335 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2)); 336 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4)); 337 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6)); 338 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8)); 339 340 // accumulate extra data for the pseudo-header 341 udpSeed += IP_TYPE_UDP; 342 udpSeed += udpLen; 343 // and compute UDP checksum 344 buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed, 345 udpHeaderOffset, 346 buf.position())); 347 // fix IP header: insert length 348 buf.putShort(ipLengthOffset, (short)buf.position()); 349 // fixup IP-header checksum 350 buf.putShort(ipChecksumOffset, 351 (short) checksum(buf, 0, 0, endIpHeader)); 352 } 353 } 354 355 /** 356 * Converts a signed short value to an unsigned int value. Needed 357 * because Java does not have unsigned types. 358 */ intAbs(short v)359 private int intAbs(short v) { 360 if (v < 0) { 361 int r = v + 65536; 362 return r; 363 } else { 364 return(v); 365 } 366 } 367 368 /** 369 * Performs an IP checksum (used in IP header and across UDP 370 * payload) on the specified portion of a ByteBuffer. The seed 371 * allows the checksum to commence with a specified value. 372 */ checksum(ByteBuffer buf, int seed, int start, int end)373 private int checksum(ByteBuffer buf, int seed, int start, int end) { 374 int sum = seed; 375 int bufPosition = buf.position(); 376 377 // set position of original ByteBuffer, so that the ShortBuffer 378 // will be correctly initialized 379 buf.position(start); 380 ShortBuffer shortBuf = buf.asShortBuffer(); 381 382 // re-set ByteBuffer position 383 buf.position(bufPosition); 384 385 short[] shortArray = new short[(end - start) / 2]; 386 shortBuf.get(shortArray); 387 388 for (short s : shortArray) { 389 sum += intAbs(s); 390 } 391 392 start += shortArray.length * 2; 393 394 // see if a singleton byte remains 395 if (end != start) { 396 short b = buf.get(start); 397 398 // make it unsigned 399 if (b < 0) { 400 b += 256; 401 } 402 403 sum += b * 256; 404 } 405 406 sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); 407 sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF); 408 int negated = ~sum; 409 return intAbs((short) negated); 410 } 411 412 /** 413 * Adds an optional parameter containing a single byte value. 414 */ addTlv(ByteBuffer buf, byte type, byte value)415 protected void addTlv(ByteBuffer buf, byte type, byte value) { 416 buf.put(type); 417 buf.put((byte) 1); 418 buf.put(value); 419 } 420 421 /** 422 * Adds an optional parameter containing an array of bytes. 423 */ addTlv(ByteBuffer buf, byte type, byte[] payload)424 protected void addTlv(ByteBuffer buf, byte type, byte[] payload) { 425 if (payload != null) { 426 buf.put(type); 427 buf.put((byte) payload.length); 428 buf.put(payload); 429 } 430 } 431 432 /** 433 * Adds an optional parameter containing an IP address. 434 */ addTlv(ByteBuffer buf, byte type, InetAddress addr)435 protected void addTlv(ByteBuffer buf, byte type, InetAddress addr) { 436 if (addr != null) { 437 addTlv(buf, type, addr.getAddress()); 438 } 439 } 440 441 /** 442 * Adds an optional parameter containing a list of IP addresses. 443 */ addTlv(ByteBuffer buf, byte type, List<InetAddress> addrs)444 protected void addTlv(ByteBuffer buf, byte type, List<InetAddress> addrs) { 445 if (addrs != null && addrs.size() > 0) { 446 buf.put(type); 447 buf.put((byte)(4 * addrs.size())); 448 449 for (InetAddress addr : addrs) { 450 buf.put(addr.getAddress()); 451 } 452 } 453 } 454 455 /** 456 * Adds an optional parameter containing a simple integer 457 */ addTlv(ByteBuffer buf, byte type, Integer value)458 protected void addTlv(ByteBuffer buf, byte type, Integer value) { 459 if (value != null) { 460 buf.put(type); 461 buf.put((byte) 4); 462 buf.putInt(value.intValue()); 463 } 464 } 465 466 /** 467 * Adds an optional parameter containing and ASCII string. 468 */ addTlv(ByteBuffer buf, byte type, String str)469 protected void addTlv(ByteBuffer buf, byte type, String str) { 470 if (str != null) { 471 buf.put(type); 472 buf.put((byte) str.length()); 473 474 for (int i = 0; i < str.length(); i++) { 475 buf.put((byte) str.charAt(i)); 476 } 477 } 478 } 479 480 /** 481 * Adds the special end-of-optional-parameters indicator. 482 */ addTlvEnd(ByteBuffer buf)483 protected void addTlvEnd(ByteBuffer buf) { 484 buf.put((byte) 0xFF); 485 } 486 487 /** 488 * Converts a MAC from an array of octets to an ASCII string. 489 */ macToString(byte[] mac)490 public static String macToString(byte[] mac) { 491 String macAddr = ""; 492 493 for (int i = 0; i < mac.length; i++) { 494 String hexString = "0" + Integer.toHexString(mac[i]); 495 496 // substring operation grabs the last 2 digits: this 497 // allows signed bytes to be converted correctly. 498 macAddr += hexString.substring(hexString.length() - 2); 499 500 if (i != (mac.length - 1)) { 501 macAddr += ":"; 502 } 503 } 504 505 return macAddr; 506 } 507 toString()508 public String toString() { 509 String macAddr = macToString(mClientMac); 510 511 return macAddr; 512 } 513 514 /** 515 * Reads a four-octet value from a ByteBuffer and construct 516 * an IPv4 address from that value. 517 */ readIpAddress(ByteBuffer packet)518 private static InetAddress readIpAddress(ByteBuffer packet) { 519 InetAddress result = null; 520 byte[] ipAddr = new byte[4]; 521 packet.get(ipAddr); 522 523 try { 524 result = InetAddress.getByAddress(ipAddr); 525 } catch (UnknownHostException ex) { 526 // ipAddr is numeric, so this should not be 527 // triggered. However, if it is, just nullify 528 result = null; 529 } 530 531 return result; 532 } 533 534 /** 535 * Reads a string of specified length from the buffer. 536 */ readAsciiString(ByteBuffer buf, int byteCount)537 private static String readAsciiString(ByteBuffer buf, int byteCount) { 538 byte[] bytes = new byte[byteCount]; 539 buf.get(bytes); 540 return new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII); 541 } 542 543 /** 544 * Creates a concrete DhcpPacket from the supplied ByteBuffer. The 545 * buffer may have an L2 encapsulation (which is the full EthernetII 546 * format starting with the source-address MAC) or an L3 encapsulation 547 * (which starts with the IP header). 548 * <br> 549 * A subset of the optional parameters are parsed and are stored 550 * in object fields. 551 */ decodeFullPacket(ByteBuffer packet, int pktType)552 public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) 553 { 554 // bootp parameters 555 int transactionId; 556 InetAddress clientIp; 557 InetAddress yourIp; 558 InetAddress nextIp; 559 InetAddress relayIp; 560 byte[] clientMac; 561 List<InetAddress> dnsServers = new ArrayList<InetAddress>(); 562 InetAddress gateway = null; // aka router 563 Integer leaseTime = null; 564 InetAddress serverIdentifier = null; 565 InetAddress netMask = null; 566 String message = null; 567 String vendorId = null; 568 byte[] expectedParams = null; 569 String hostName = null; 570 String domainName = null; 571 InetAddress ipSrc = null; 572 InetAddress ipDst = null; 573 InetAddress bcAddr = null; 574 InetAddress requestedIp = null; 575 576 // dhcp options 577 byte dhcpType = (byte) 0xFF; 578 579 packet.order(ByteOrder.BIG_ENDIAN); 580 581 // check to see if we need to parse L2, IP, and UDP encaps 582 if (pktType == ENCAP_L2) { 583 // System.out.println("buffer len " + packet.limit()); 584 byte[] l2dst = new byte[6]; 585 byte[] l2src = new byte[6]; 586 587 packet.get(l2dst); 588 packet.get(l2src); 589 590 short l2type = packet.getShort(); 591 592 if (l2type != 0x0800) 593 return null; 594 } 595 596 if ((pktType == ENCAP_L2) || (pktType == ENCAP_L3)) { 597 // assume l2type is 0x0800, i.e. IP 598 byte ipType = packet.get(); 599 // System.out.println("ipType is " + ipType); 600 byte ipDiffServicesField = packet.get(); 601 short ipTotalLength = packet.getShort(); 602 short ipIdentification = packet.getShort(); 603 byte ipFlags = packet.get(); 604 byte ipFragOffset = packet.get(); 605 byte ipTTL = packet.get(); 606 byte ipProto = packet.get(); 607 short ipChksm = packet.getShort(); 608 609 ipSrc = readIpAddress(packet); 610 ipDst = readIpAddress(packet); 611 612 if (ipProto != IP_TYPE_UDP) // UDP 613 return null; 614 615 // assume UDP 616 short udpSrcPort = packet.getShort(); 617 short udpDstPort = packet.getShort(); 618 short udpLen = packet.getShort(); 619 short udpChkSum = packet.getShort(); 620 621 if ((udpSrcPort != DHCP_SERVER) && (udpSrcPort != DHCP_CLIENT)) 622 return null; 623 } 624 625 // assume bootp 626 byte type = packet.get(); 627 byte hwType = packet.get(); 628 byte addrLen = packet.get(); 629 byte hops = packet.get(); 630 transactionId = packet.getInt(); 631 short elapsed = packet.getShort(); 632 short bootpFlags = packet.getShort(); 633 boolean broadcast = (bootpFlags & 0x8000) != 0; 634 byte[] ipv4addr = new byte[4]; 635 636 try { 637 packet.get(ipv4addr); 638 clientIp = InetAddress.getByAddress(ipv4addr); 639 packet.get(ipv4addr); 640 yourIp = InetAddress.getByAddress(ipv4addr); 641 packet.get(ipv4addr); 642 nextIp = InetAddress.getByAddress(ipv4addr); 643 packet.get(ipv4addr); 644 relayIp = InetAddress.getByAddress(ipv4addr); 645 } catch (UnknownHostException ex) { 646 return null; 647 } 648 649 clientMac = new byte[addrLen]; 650 packet.get(clientMac); 651 652 // skip over address padding (16 octets allocated) 653 packet.position(packet.position() + (16 - addrLen) 654 + 64 // skip server host name (64 chars) 655 + 128); // skip boot file name (128 chars) 656 657 int dhcpMagicCookie = packet.getInt(); 658 659 if (dhcpMagicCookie != 0x63825363) 660 return null; 661 662 // parse options 663 boolean notFinishedOptions = true; 664 665 while ((packet.position() < packet.limit()) && notFinishedOptions) { 666 byte optionType = packet.get(); 667 668 if (optionType == (byte) 0xFF) { 669 notFinishedOptions = false; 670 } else { 671 byte optionLen = packet.get(); 672 int expectedLen = 0; 673 674 switch(optionType) { 675 case DHCP_SUBNET_MASK: 676 netMask = readIpAddress(packet); 677 expectedLen = 4; 678 break; 679 case DHCP_ROUTER: 680 gateway = readIpAddress(packet); 681 expectedLen = 4; 682 break; 683 case DHCP_DNS_SERVER: 684 expectedLen = 0; 685 686 for (expectedLen = 0; expectedLen < optionLen; 687 expectedLen += 4) { 688 dnsServers.add(readIpAddress(packet)); 689 } 690 break; 691 case DHCP_HOST_NAME: 692 expectedLen = optionLen; 693 hostName = readAsciiString(packet, optionLen); 694 break; 695 case DHCP_DOMAIN_NAME: 696 expectedLen = optionLen; 697 domainName = readAsciiString(packet, optionLen); 698 break; 699 case DHCP_BROADCAST_ADDRESS: 700 bcAddr = readIpAddress(packet); 701 expectedLen = 4; 702 break; 703 case DHCP_REQUESTED_IP: 704 requestedIp = readIpAddress(packet); 705 expectedLen = 4; 706 break; 707 case DHCP_LEASE_TIME: 708 leaseTime = Integer.valueOf(packet.getInt()); 709 expectedLen = 4; 710 break; 711 case DHCP_MESSAGE_TYPE: 712 dhcpType = packet.get(); 713 expectedLen = 1; 714 break; 715 case DHCP_SERVER_IDENTIFIER: 716 serverIdentifier = readIpAddress(packet); 717 expectedLen = 4; 718 break; 719 case DHCP_PARAMETER_LIST: 720 expectedParams = new byte[optionLen]; 721 packet.get(expectedParams); 722 expectedLen = optionLen; 723 break; 724 case DHCP_MESSAGE: 725 expectedLen = optionLen; 726 message = readAsciiString(packet, optionLen); 727 break; 728 case DHCP_VENDOR_CLASS_ID: 729 expectedLen = optionLen; 730 vendorId = readAsciiString(packet, optionLen); 731 break; 732 case DHCP_CLIENT_IDENTIFIER: { // Client identifier 733 byte[] id = new byte[optionLen]; 734 packet.get(id); 735 expectedLen = optionLen; 736 } break; 737 default: 738 // ignore any other parameters 739 for (int i = 0; i < optionLen; i++) { 740 expectedLen++; 741 byte throwaway = packet.get(); 742 } 743 } 744 745 if (expectedLen != optionLen) { 746 return null; 747 } 748 } 749 } 750 751 DhcpPacket newPacket; 752 753 switch(dhcpType) { 754 case -1: return null; 755 case DHCP_MESSAGE_TYPE_DISCOVER: 756 newPacket = new DhcpDiscoverPacket( 757 transactionId, clientMac, broadcast); 758 break; 759 case DHCP_MESSAGE_TYPE_OFFER: 760 newPacket = new DhcpOfferPacket( 761 transactionId, broadcast, ipSrc, yourIp, clientMac); 762 break; 763 case DHCP_MESSAGE_TYPE_REQUEST: 764 newPacket = new DhcpRequestPacket( 765 transactionId, clientIp, clientMac, broadcast); 766 break; 767 case DHCP_MESSAGE_TYPE_DECLINE: 768 newPacket = new DhcpDeclinePacket( 769 transactionId, clientIp, yourIp, nextIp, relayIp, 770 clientMac); 771 break; 772 case DHCP_MESSAGE_TYPE_ACK: 773 newPacket = new DhcpAckPacket( 774 transactionId, broadcast, ipSrc, yourIp, clientMac); 775 break; 776 case DHCP_MESSAGE_TYPE_NAK: 777 newPacket = new DhcpNakPacket( 778 transactionId, clientIp, yourIp, nextIp, relayIp, 779 clientMac); 780 break; 781 case DHCP_MESSAGE_TYPE_INFORM: 782 newPacket = new DhcpInformPacket( 783 transactionId, clientIp, yourIp, nextIp, relayIp, 784 clientMac); 785 break; 786 default: 787 System.out.println("Unimplemented type: " + dhcpType); 788 return null; 789 } 790 791 newPacket.mBroadcastAddress = bcAddr; 792 newPacket.mDnsServers = dnsServers; 793 newPacket.mDomainName = domainName; 794 newPacket.mGateway = gateway; 795 newPacket.mHostName = hostName; 796 newPacket.mLeaseTime = leaseTime; 797 newPacket.mMessage = message; 798 newPacket.mRequestedIp = requestedIp; 799 newPacket.mRequestedParams = expectedParams; 800 newPacket.mServerIdentifier = serverIdentifier; 801 newPacket.mSubnetMask = netMask; 802 return newPacket; 803 } 804 805 /** 806 * Parse a packet from an array of bytes. 807 */ decodeFullPacket(byte[] packet, int pktType)808 public static DhcpPacket decodeFullPacket(byte[] packet, int pktType) 809 { 810 ByteBuffer buffer = ByteBuffer.wrap(packet).order(ByteOrder.BIG_ENDIAN); 811 return decodeFullPacket(buffer, pktType); 812 } 813 814 /** 815 * Builds a DHCP-DISCOVER packet from the required specified 816 * parameters. 817 */ buildDiscoverPacket(int encap, int transactionId, byte[] clientMac, boolean broadcast, byte[] expectedParams)818 public static ByteBuffer buildDiscoverPacket(int encap, int transactionId, 819 byte[] clientMac, boolean broadcast, byte[] expectedParams) { 820 DhcpPacket pkt = new DhcpDiscoverPacket( 821 transactionId, clientMac, broadcast); 822 pkt.mRequestedParams = expectedParams; 823 return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 824 } 825 826 /** 827 * Builds a DHCP-OFFER packet from the required specified 828 * parameters. 829 */ buildOfferPacket(int encap, int transactionId, boolean broadcast, InetAddress serverIpAddr, InetAddress clientIpAddr, byte[] mac, Integer timeout, InetAddress netMask, InetAddress bcAddr, InetAddress gateway, List<InetAddress> dnsServers, InetAddress dhcpServerIdentifier, String domainName)830 public static ByteBuffer buildOfferPacket(int encap, int transactionId, 831 boolean broadcast, InetAddress serverIpAddr, InetAddress clientIpAddr, 832 byte[] mac, Integer timeout, InetAddress netMask, InetAddress bcAddr, 833 InetAddress gateway, List<InetAddress> dnsServers, 834 InetAddress dhcpServerIdentifier, String domainName) { 835 DhcpPacket pkt = new DhcpOfferPacket( 836 transactionId, broadcast, serverIpAddr, clientIpAddr, mac); 837 pkt.mGateway = gateway; 838 pkt.mDnsServers = dnsServers; 839 pkt.mLeaseTime = timeout; 840 pkt.mDomainName = domainName; 841 pkt.mServerIdentifier = dhcpServerIdentifier; 842 pkt.mSubnetMask = netMask; 843 pkt.mBroadcastAddress = bcAddr; 844 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 845 } 846 847 /** 848 * Builds a DHCP-ACK packet from the required specified parameters. 849 */ buildAckPacket(int encap, int transactionId, boolean broadcast, InetAddress serverIpAddr, InetAddress clientIpAddr, byte[] mac, Integer timeout, InetAddress netMask, InetAddress bcAddr, InetAddress gateway, List<InetAddress> dnsServers, InetAddress dhcpServerIdentifier, String domainName)850 public static ByteBuffer buildAckPacket(int encap, int transactionId, 851 boolean broadcast, InetAddress serverIpAddr, InetAddress clientIpAddr, 852 byte[] mac, Integer timeout, InetAddress netMask, InetAddress bcAddr, 853 InetAddress gateway, List<InetAddress> dnsServers, 854 InetAddress dhcpServerIdentifier, String domainName) { 855 DhcpPacket pkt = new DhcpAckPacket( 856 transactionId, broadcast, serverIpAddr, clientIpAddr, mac); 857 pkt.mGateway = gateway; 858 pkt.mDnsServers = dnsServers; 859 pkt.mLeaseTime = timeout; 860 pkt.mDomainName = domainName; 861 pkt.mSubnetMask = netMask; 862 pkt.mServerIdentifier = dhcpServerIdentifier; 863 pkt.mBroadcastAddress = bcAddr; 864 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 865 } 866 867 /** 868 * Builds a DHCP-NAK packet from the required specified parameters. 869 */ buildNakPacket(int encap, int transactionId, InetAddress serverIpAddr, InetAddress clientIpAddr, byte[] mac)870 public static ByteBuffer buildNakPacket(int encap, int transactionId, 871 InetAddress serverIpAddr, InetAddress clientIpAddr, byte[] mac) { 872 DhcpPacket pkt = new DhcpNakPacket(transactionId, clientIpAddr, 873 serverIpAddr, serverIpAddr, serverIpAddr, mac); 874 pkt.mMessage = "requested address not available"; 875 pkt.mRequestedIp = clientIpAddr; 876 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 877 } 878 879 /** 880 * Builds a DHCP-REQUEST packet from the required specified parameters. 881 */ buildRequestPacket(int encap, int transactionId, InetAddress clientIp, boolean broadcast, byte[] clientMac, InetAddress requestedIpAddress, InetAddress serverIdentifier, byte[] requestedParams, String hostName)882 public static ByteBuffer buildRequestPacket(int encap, 883 int transactionId, InetAddress clientIp, boolean broadcast, 884 byte[] clientMac, InetAddress requestedIpAddress, 885 InetAddress serverIdentifier, byte[] requestedParams, String hostName) { 886 DhcpPacket pkt = new DhcpRequestPacket(transactionId, clientIp, 887 clientMac, broadcast); 888 pkt.mRequestedIp = requestedIpAddress; 889 pkt.mServerIdentifier = serverIdentifier; 890 pkt.mHostName = hostName; 891 pkt.mRequestedParams = requestedParams; 892 ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 893 return result; 894 } 895 } 896