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