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