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