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 */ 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 */ 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 */ 221 abstract void finishPacket(ByteBuffer buffer); 222 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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