blob: c7c25f0e9ffb46657b3271035beae3965df434a8 [file] [log] [blame]
Stan Chesnutt7da02ad2010-12-14 09:49:26 -08001package android.net.dhcp;
2
Stan Chesnutt7da02ad2010-12-14 09:49:26 -08003import java.net.InetAddress;
4import java.net.UnknownHostException;
5import java.nio.ByteBuffer;
6import java.nio.ByteOrder;
Elliott Hughesd396a442013-06-28 16:24:48 -07007import java.nio.charset.StandardCharsets;
Stan Chesnutt7da02ad2010-12-14 09:49:26 -08008import java.nio.ShortBuffer;
9
10import java.util.ArrayList;
11import 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 */
18abstract 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);
Elliott Hughesd396a442013-06-28 16:24:48 -0700540 return new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII);
Stan Chesnutt7da02ad2010-12-14 09:49:26 -0800541 }
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;
Stan Chesnutt045b1662011-02-02 12:10:21 -0800561 List<InetAddress> dnsServers = new ArrayList<InetAddress>();
Stan Chesnutt7da02ad2010-12-14 09:49:26 -0800562 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:
Stan Chesnutt7da02ad2010-12-14 09:49:26 -0800684 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}