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