1package android.net.dhcp;
2
3import android.net.DhcpResults;
4import android.net.LinkAddress;
5import android.net.NetworkUtils;
6import android.os.Build;
7import android.os.SystemProperties;
8import android.system.OsConstants;
9
10import java.io.UnsupportedEncodingException;
11import java.net.Inet4Address;
12import java.net.UnknownHostException;
13import java.nio.BufferUnderflowException;
14import java.nio.ByteBuffer;
15import java.nio.ByteOrder;
16import java.nio.charset.StandardCharsets;
17import java.nio.ShortBuffer;
18
19import java.util.ArrayList;
20import java.util.Arrays;
21import 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 */
28abstract 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     */
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     */
287    abstract void finishPacket(ByteBuffer buffer);
288
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     */
305    public int getTransactionId() {
306        return mTransId;
307    }
308
309    /**
310     * Returns the client MAC.
311     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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