blob: bc8baa12a45b47426801b53c187fca1e7d65288b [file] [log] [blame]
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +09001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net.dhcp;
18
Lorenzo Colittid9735372015-06-02 13:15:50 +090019import android.net.DhcpResults;
Lorenzo Colittif68edb12015-06-02 17:46:24 +090020import android.net.LinkAddress;
Hugo Benichie0ea7fe2016-10-05 18:33:21 +090021import android.net.NetworkUtils;
22import android.net.metrics.DhcpErrorEvent;
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +090023import android.system.OsConstants;
24import android.test.suitebuilder.annotation.SmallTest;
Lorenzo Colittif28e62b2015-07-27 16:35:22 +090025import com.android.internal.util.HexDump;
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +090026import java.net.Inet4Address;
27import java.nio.ByteBuffer;
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +090028import java.util.ArrayList;
Lorenzo Colitti6c7acb62015-06-29 17:10:45 +090029import java.util.Arrays;
Hugo Benichi006e0612016-10-05 21:07:19 +090030import java.util.Random;
Hugo Benichie0ea7fe2016-10-05 18:33:21 +090031import junit.framework.TestCase;
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +090032
33import static android.net.dhcp.DhcpPacket.*;
34
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +090035public class DhcpPacketTest extends TestCase {
36
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +090037 private static Inet4Address SERVER_ADDR = v4Address("192.0.2.1");
38 private static Inet4Address CLIENT_ADDR = v4Address("192.0.2.234");
Lorenzo Colittif68edb12015-06-02 17:46:24 +090039 // Use our own empty address instead of Inet4Address.ANY or INADDR_ANY to ensure that the code
40 // doesn't use == instead of equals when comparing addresses.
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +090041 private static Inet4Address ANY = (Inet4Address) v4Address("0.0.0.0");
Lorenzo Colittif68edb12015-06-02 17:46:24 +090042
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +090043 private static byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
44
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +090045 private static final Inet4Address v4Address(String addrString) throws IllegalArgumentException {
46 return (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
47 }
48
Lorenzo Colitti6c7acb62015-06-29 17:10:45 +090049 public void setUp() {
50 DhcpPacket.testOverrideVendorId = "android-dhcp-???";
51 DhcpPacket.testOverrideHostname = "android-01234567890abcde";
52 }
53
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +090054 class TestDhcpPacket extends DhcpPacket {
55 private byte mType;
56 // TODO: Make this a map of option numbers to bytes instead.
Lorenzo Colittif68edb12015-06-02 17:46:24 +090057 private byte[] mDomainBytes, mVendorInfoBytes, mLeaseTimeBytes, mNetmaskBytes;
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +090058
Lorenzo Colittif68edb12015-06-02 17:46:24 +090059 public TestDhcpPacket(byte type, Inet4Address clientIp, Inet4Address yourIp) {
60 super(0xdeadbeef, (short) 0, clientIp, yourIp, INADDR_ANY, INADDR_ANY,
Lorenzo Colitti3e979322015-04-21 15:22:17 +090061 CLIENT_MAC, true);
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +090062 mType = type;
Lorenzo Colittid9735372015-06-02 13:15:50 +090063 }
64
Lorenzo Colittif68edb12015-06-02 17:46:24 +090065 public TestDhcpPacket(byte type) {
66 this(type, INADDR_ANY, CLIENT_ADDR);
67 }
68
Lorenzo Colittid9735372015-06-02 13:15:50 +090069 public TestDhcpPacket setDomainBytes(byte[] domainBytes) {
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +090070 mDomainBytes = domainBytes;
Lorenzo Colittid9735372015-06-02 13:15:50 +090071 return this;
72 }
73
74 public TestDhcpPacket setVendorInfoBytes(byte[] vendorInfoBytes) {
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +090075 mVendorInfoBytes = vendorInfoBytes;
Lorenzo Colittid9735372015-06-02 13:15:50 +090076 return this;
77 }
78
79 public TestDhcpPacket setLeaseTimeBytes(byte[] leaseTimeBytes) {
80 mLeaseTimeBytes = leaseTimeBytes;
81 return this;
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +090082 }
83
Lorenzo Colittif68edb12015-06-02 17:46:24 +090084 public TestDhcpPacket setNetmaskBytes(byte[] netmaskBytes) {
85 mNetmaskBytes = netmaskBytes;
86 return this;
87 }
88
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +090089 public ByteBuffer buildPacket(int encap, short unusedDestUdp, short unusedSrcUdp) {
90 ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
91 fillInPacket(encap, CLIENT_ADDR, SERVER_ADDR,
92 DHCP_CLIENT, DHCP_SERVER, result, DHCP_BOOTREPLY, false);
93 return result;
94 }
95
96 public void finishPacket(ByteBuffer buffer) {
97 addTlv(buffer, DHCP_MESSAGE_TYPE, mType);
98 if (mDomainBytes != null) {
99 addTlv(buffer, DHCP_DOMAIN_NAME, mDomainBytes);
100 }
101 if (mVendorInfoBytes != null) {
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900102 addTlv(buffer, DHCP_VENDOR_INFO, mVendorInfoBytes);
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +0900103 }
Lorenzo Colittid9735372015-06-02 13:15:50 +0900104 if (mLeaseTimeBytes != null) {
105 addTlv(buffer, DHCP_LEASE_TIME, mLeaseTimeBytes);
106 }
Lorenzo Colittif68edb12015-06-02 17:46:24 +0900107 if (mNetmaskBytes != null) {
108 addTlv(buffer, DHCP_SUBNET_MASK, mNetmaskBytes);
109 }
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +0900110 addTlvEnd(buffer);
111 }
112
113 // Convenience method.
114 public ByteBuffer build() {
115 // ENCAP_BOOTP packets don't contain ports, so just pass in 0.
116 ByteBuffer pkt = buildPacket(ENCAP_BOOTP, (short) 0, (short) 0);
117 pkt.flip();
118 return pkt;
119 }
120 }
121
122 private void assertDomainAndVendorInfoParses(
123 String expectedDomain, byte[] domainBytes,
Erik Kline496906e2015-09-16 15:44:54 +0900124 String expectedVendorInfo, byte[] vendorInfoBytes) throws Exception {
Lorenzo Colittid9735372015-06-02 13:15:50 +0900125 ByteBuffer packet = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER)
126 .setDomainBytes(domainBytes)
127 .setVendorInfoBytes(vendorInfoBytes)
128 .build();
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +0900129 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
130 assertEquals(expectedDomain, offerPacket.mDomainName);
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900131 assertEquals(expectedVendorInfo, offerPacket.mVendorInfo);
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +0900132 }
133
134 @SmallTest
135 public void testDomainName() throws Exception {
136 byte[] nullByte = new byte[] { 0x00 };
137 byte[] twoNullBytes = new byte[] { 0x00, 0x00 };
138 byte[] nonNullDomain = new byte[] {
139 (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l'
140 };
141 byte[] trailingNullDomain = new byte[] {
142 (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l', 0x00
143 };
144 byte[] embeddedNullsDomain = new byte[] {
145 (byte) 'g', (byte) 'o', (byte) 'o', 0x00, 0x00, (byte) 'g', (byte) 'l'
146 };
147 byte[] metered = "ANDROID_METERED".getBytes("US-ASCII");
148
149 byte[] meteredEmbeddedNull = metered.clone();
150 meteredEmbeddedNull[7] = (char) 0;
151
152 byte[] meteredTrailingNull = metered.clone();
153 meteredTrailingNull[meteredTrailingNull.length - 1] = (char) 0;
154
155 assertDomainAndVendorInfoParses("", nullByte, "\u0000", nullByte);
156 assertDomainAndVendorInfoParses("", twoNullBytes, "\u0000\u0000", twoNullBytes);
157 assertDomainAndVendorInfoParses("goo.gl", nonNullDomain, "ANDROID_METERED", metered);
158 assertDomainAndVendorInfoParses("goo", embeddedNullsDomain,
159 "ANDROID\u0000METERED", meteredEmbeddedNull);
160 assertDomainAndVendorInfoParses("goo.gl", trailingNullDomain,
161 "ANDROID_METERE\u0000", meteredTrailingNull);
162 }
Lorenzo Colittid9735372015-06-02 13:15:50 +0900163
164 private void assertLeaseTimeParses(boolean expectValid, Integer rawLeaseTime,
Erik Kline496906e2015-09-16 15:44:54 +0900165 long leaseTimeMillis, byte[] leaseTimeBytes) throws Exception {
Lorenzo Colittid9735372015-06-02 13:15:50 +0900166 TestDhcpPacket testPacket = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER);
167 if (leaseTimeBytes != null) {
168 testPacket.setLeaseTimeBytes(leaseTimeBytes);
169 }
170 ByteBuffer packet = testPacket.build();
Erik Kline496906e2015-09-16 15:44:54 +0900171 DhcpPacket offerPacket = null;
172
Lorenzo Colittid9735372015-06-02 13:15:50 +0900173 if (!expectValid) {
Erik Kline496906e2015-09-16 15:44:54 +0900174 try {
175 offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
176 fail("Invalid packet parsed successfully: " + offerPacket);
177 } catch (ParseException expected) {
178 }
Lorenzo Colittid9735372015-06-02 13:15:50 +0900179 return;
180 }
Erik Kline496906e2015-09-16 15:44:54 +0900181
182 offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
183 assertNotNull(offerPacket);
Lorenzo Colittid9735372015-06-02 13:15:50 +0900184 assertEquals(rawLeaseTime, offerPacket.mLeaseTime);
185 DhcpResults dhcpResults = offerPacket.toDhcpResults(); // Just check this doesn't crash.
186 assertEquals(leaseTimeMillis, offerPacket.getLeaseTimeMillis());
187 }
188
189 @SmallTest
190 public void testLeaseTime() throws Exception {
191 byte[] noLease = null;
192 byte[] tooShortLease = new byte[] { 0x00, 0x00 };
193 byte[] tooLongLease = new byte[] { 0x00, 0x00, 0x00, 60, 0x01 };
194 byte[] zeroLease = new byte[] { 0x00, 0x00, 0x00, 0x00 };
195 byte[] tenSecondLease = new byte[] { 0x00, 0x00, 0x00, 10 };
196 byte[] oneMinuteLease = new byte[] { 0x00, 0x00, 0x00, 60 };
197 byte[] fiveMinuteLease = new byte[] { 0x00, 0x00, 0x01, 0x2c };
198 byte[] oneDayLease = new byte[] { 0x00, 0x01, 0x51, (byte) 0x80 };
199 byte[] maxIntPlusOneLease = new byte[] { (byte) 0x80, 0x00, 0x00, 0x01 };
200 byte[] infiniteLease = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
201
202 assertLeaseTimeParses(true, null, 0, noLease);
203 assertLeaseTimeParses(false, null, 0, tooShortLease);
204 assertLeaseTimeParses(false, null, 0, tooLongLease);
205 assertLeaseTimeParses(true, 0, 60 * 1000, zeroLease);
206 assertLeaseTimeParses(true, 10, 60 * 1000, tenSecondLease);
207 assertLeaseTimeParses(true, 60, 60 * 1000, oneMinuteLease);
208 assertLeaseTimeParses(true, 300, 300 * 1000, fiveMinuteLease);
209 assertLeaseTimeParses(true, 86400, 86400 * 1000, oneDayLease);
210 assertLeaseTimeParses(true, -2147483647, 2147483649L * 1000, maxIntPlusOneLease);
211 assertLeaseTimeParses(true, DhcpPacket.INFINITE_LEASE, 0, infiniteLease);
212 }
Lorenzo Colittif68edb12015-06-02 17:46:24 +0900213
214 private void checkIpAddress(String expected, Inet4Address clientIp, Inet4Address yourIp,
Erik Kline496906e2015-09-16 15:44:54 +0900215 byte[] netmaskBytes) throws Exception {
Lorenzo Colittif68edb12015-06-02 17:46:24 +0900216 checkIpAddress(expected, DHCP_MESSAGE_TYPE_OFFER, clientIp, yourIp, netmaskBytes);
217 checkIpAddress(expected, DHCP_MESSAGE_TYPE_ACK, clientIp, yourIp, netmaskBytes);
218 }
219
220 private void checkIpAddress(String expected, byte type,
221 Inet4Address clientIp, Inet4Address yourIp,
Erik Kline496906e2015-09-16 15:44:54 +0900222 byte[] netmaskBytes) throws Exception {
Lorenzo Colittif68edb12015-06-02 17:46:24 +0900223 ByteBuffer packet = new TestDhcpPacket(type, clientIp, yourIp)
224 .setNetmaskBytes(netmaskBytes)
225 .build();
226 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
227 DhcpResults results = offerPacket.toDhcpResults();
228
229 if (expected != null) {
230 LinkAddress expectedAddress = new LinkAddress(expected);
231 assertEquals(expectedAddress, results.ipAddress);
232 } else {
233 assertNull(results);
234 }
235 }
236
237 @SmallTest
238 public void testIpAddress() throws Exception {
239 byte[] slash11Netmask = new byte[] { (byte) 0xff, (byte) 0xe0, 0x00, 0x00 };
240 byte[] slash24Netmask = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00 };
241 byte[] invalidNetmask = new byte[] { (byte) 0xff, (byte) 0xfb, (byte) 0xff, 0x00 };
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900242 Inet4Address example1 = v4Address("192.0.2.1");
243 Inet4Address example2 = v4Address("192.0.2.43");
Lorenzo Colittif68edb12015-06-02 17:46:24 +0900244
245 // A packet without any addresses is not valid.
246 checkIpAddress(null, ANY, ANY, slash24Netmask);
247
248 // ClientIP is used iff YourIP is not present.
249 checkIpAddress("192.0.2.1/24", example2, example1, slash24Netmask);
250 checkIpAddress("192.0.2.43/11", example2, ANY, slash11Netmask);
251 checkIpAddress("192.0.2.43/11", ANY, example2, slash11Netmask);
252
253 // Invalid netmasks are ignored.
254 checkIpAddress(null, example2, ANY, invalidNetmask);
255
256 // If there is no netmask, implicit netmasks are used.
257 checkIpAddress("192.0.2.43/24", ANY, example2, null);
258 }
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900259
260 private void assertDhcpResults(String ipAddress, String gateway, String dnsServersString,
261 String domains, String serverAddress, String vendorInfo, int leaseDuration,
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900262 boolean hasMeteredHint, int mtu, DhcpResults dhcpResults) throws Exception {
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900263 assertEquals(new LinkAddress(ipAddress), dhcpResults.ipAddress);
264 assertEquals(v4Address(gateway), dhcpResults.gateway);
265
266 String[] dnsServerStrings = dnsServersString.split(",");
267 ArrayList dnsServers = new ArrayList();
268 for (String dnsServerString : dnsServerStrings) {
269 dnsServers.add(v4Address(dnsServerString));
270 }
271 assertEquals(dnsServers, dhcpResults.dnsServers);
272
273 assertEquals(domains, dhcpResults.domains);
274 assertEquals(v4Address(serverAddress), dhcpResults.serverAddress);
275 assertEquals(vendorInfo, dhcpResults.vendorInfo);
276 assertEquals(leaseDuration, dhcpResults.leaseDuration);
277 assertEquals(hasMeteredHint, dhcpResults.hasMeteredHint());
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900278 assertEquals(mtu, dhcpResults.mtu);
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900279 }
280
281 @SmallTest
282 public void testOffer1() throws Exception {
283 // TODO: Turn all of these into golden files. This will probably require modifying
284 // Android.mk appropriately, making this into an AndroidTestCase, and adding code to read
285 // the golden files from the test APK's assets via mContext.getAssets().
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900286 final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900287 // IP header.
288 "451001480000000080118849c0a89003c0a89ff7" +
289 // UDP header.
290 "004300440134dcfa" +
291 // BOOTP header.
292 "02010600c997a63b0000000000000000c0a89ff70000000000000000" +
293 // MAC address.
294 "30766ff2a90c00000000000000000000" +
295 // Server name.
296 "0000000000000000000000000000000000000000000000000000000000000000" +
297 "0000000000000000000000000000000000000000000000000000000000000000" +
298 // File.
299 "0000000000000000000000000000000000000000000000000000000000000000" +
300 "0000000000000000000000000000000000000000000000000000000000000000" +
301 "0000000000000000000000000000000000000000000000000000000000000000" +
302 "0000000000000000000000000000000000000000000000000000000000000000" +
303 // Options
304 "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900305 "3a0400000e103b040000189cff00000000000000000000"));
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900306
307 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
308 assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
309 DhcpResults dhcpResults = offerPacket.toDhcpResults();
310 assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900311 null, "192.168.144.3", null, 7200, false, 0, dhcpResults);
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900312 }
313
314 @SmallTest
315 public void testOffer2() throws Exception {
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900316 final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900317 // IP header.
318 "450001518d0600004011144dc0a82b01c0a82bf7" +
319 // UDP header.
320 "00430044013d9ac7" +
321 // BOOTP header.
322 "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
323 // MAC address.
324 "30766ff2a90c00000000000000000000" +
325 // Server name.
326 "0000000000000000000000000000000000000000000000000000000000000000" +
327 "0000000000000000000000000000000000000000000000000000000000000000" +
328 // File.
329 "0000000000000000000000000000000000000000000000000000000000000000" +
330 "0000000000000000000000000000000000000000000000000000000000000000" +
331 "0000000000000000000000000000000000000000000000000000000000000000" +
332 "0000000000000000000000000000000000000000000000000000000000000000" +
333 // Options
334 "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900335 "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900336
337 assertEquals(337, packet.limit());
338 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
339 assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
340 DhcpResults dhcpResults = offerPacket.toDhcpResults();
341 assertDhcpResults("192.168.43.247/24", "192.168.43.1", "192.168.43.1",
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900342 null, "192.168.43.1", "ANDROID_METERED", 3600, true, 0, dhcpResults);
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900343 assertTrue(dhcpResults.hasMeteredHint());
344 }
345
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900346 @SmallTest
347 public void testBadIpPacket() throws Exception {
348 final byte[] packet = HexDump.hexStringToByteArray(
349 // IP header.
350 "450001518d0600004011144dc0a82b01c0a82bf7");
351
352 try {
353 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
354 } catch (DhcpPacket.ParseException expected) {
355 assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
356 return;
357 }
358 fail("Dhcp packet parsing should have failed");
359 }
360
361 @SmallTest
362 public void testBadDhcpPacket() throws Exception {
363 final byte[] packet = HexDump.hexStringToByteArray(
364 // IP header.
365 "450001518d0600004011144dc0a82b01c0a82bf7" +
366 // UDP header.
367 "00430044013d9ac7" +
368 // BOOTP header.
369 "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000");
370
371 try {
372 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
373 } catch (DhcpPacket.ParseException expected) {
374 assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
375 return;
376 }
377 fail("Dhcp packet parsing should have failed");
378 }
379
380 @SmallTest
381 public void testBadTruncatedOffer() throws Exception {
382 final byte[] packet = HexDump.hexStringToByteArray(
383 // IP header.
384 "450001518d0600004011144dc0a82b01c0a82bf7" +
385 // UDP header.
386 "00430044013d9ac7" +
387 // BOOTP header.
388 "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
389 // MAC address.
390 "30766ff2a90c00000000000000000000" +
391 // Server name.
392 "0000000000000000000000000000000000000000000000000000000000000000" +
393 "0000000000000000000000000000000000000000000000000000000000000000" +
394 // File, missing one byte
395 "0000000000000000000000000000000000000000000000000000000000000000" +
396 "0000000000000000000000000000000000000000000000000000000000000000" +
397 "0000000000000000000000000000000000000000000000000000000000000000" +
398 "00000000000000000000000000000000000000000000000000000000000000");
399
400 try {
401 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
402 } catch (DhcpPacket.ParseException expected) {
403 assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
404 return;
405 }
406 fail("Dhcp packet parsing should have failed");
407 }
408
409 @SmallTest
410 public void testBadOfferWithoutACookie() throws Exception {
411 final byte[] packet = HexDump.hexStringToByteArray(
412 // IP header.
413 "450001518d0600004011144dc0a82b01c0a82bf7" +
414 // UDP header.
415 "00430044013d9ac7" +
416 // BOOTP header.
417 "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
418 // MAC address.
419 "30766ff2a90c00000000000000000000" +
420 // Server name.
421 "0000000000000000000000000000000000000000000000000000000000000000" +
422 "0000000000000000000000000000000000000000000000000000000000000000" +
423 // File.
424 "0000000000000000000000000000000000000000000000000000000000000000" +
425 "0000000000000000000000000000000000000000000000000000000000000000" +
426 "0000000000000000000000000000000000000000000000000000000000000000" +
427 "0000000000000000000000000000000000000000000000000000000000000000"
428 // No options
429 );
430
431 try {
432 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
433 } catch (DhcpPacket.ParseException expected) {
Hugo Benichi006e0612016-10-05 21:07:19 +0900434 assertDhcpErrorCodes(DhcpErrorEvent.DHCP_NO_COOKIE, expected.errorCode);
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900435 return;
436 }
437 fail("Dhcp packet parsing should have failed");
438 }
439
440 @SmallTest
441 public void testOfferWithBadCookie() throws Exception {
442 final byte[] packet = HexDump.hexStringToByteArray(
443 // IP header.
444 "450001518d0600004011144dc0a82b01c0a82bf7" +
445 // UDP header.
446 "00430044013d9ac7" +
447 // BOOTP header.
448 "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
449 // MAC address.
450 "30766ff2a90c00000000000000000000" +
451 // Server name.
452 "0000000000000000000000000000000000000000000000000000000000000000" +
453 "0000000000000000000000000000000000000000000000000000000000000000" +
454 // File.
455 "0000000000000000000000000000000000000000000000000000000000000000" +
456 "0000000000000000000000000000000000000000000000000000000000000000" +
457 "0000000000000000000000000000000000000000000000000000000000000000" +
458 "0000000000000000000000000000000000000000000000000000000000000000" +
459 // Bad cookie
460 "DEADBEEF3501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
461 "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
462
463 try {
464 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
465 } catch (DhcpPacket.ParseException expected) {
466 assertDhcpErrorCodes(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE, expected.errorCode);
467 return;
468 }
469 fail("Dhcp packet parsing should have failed");
470 }
471
472 private void assertDhcpErrorCodes(int expected, int got) {
473 assertEquals(Integer.toHexString(expected), Integer.toHexString(got));
474 }
475
Hugo Benichi006e0612016-10-05 21:07:19 +0900476 public void testTruncatedOfferPackets() throws Exception {
477 final byte[] packet = HexDump.hexStringToByteArray(
478 // IP header.
479 "450001518d0600004011144dc0a82b01c0a82bf7" +
480 // UDP header.
481 "00430044013d9ac7" +
482 // BOOTP header.
483 "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
484 // MAC address.
485 "30766ff2a90c00000000000000000000" +
486 // Server name.
487 "0000000000000000000000000000000000000000000000000000000000000000" +
488 "0000000000000000000000000000000000000000000000000000000000000000" +
489 // File.
490 "0000000000000000000000000000000000000000000000000000000000000000" +
491 "0000000000000000000000000000000000000000000000000000000000000000" +
492 "0000000000000000000000000000000000000000000000000000000000000000" +
493 "0000000000000000000000000000000000000000000000000000000000000000" +
494 // Options
495 "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
496 "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
497
498 for (int len = 0; len < packet.length; len++) {
499 try {
500 DhcpPacket.decodeFullPacket(packet, len, ENCAP_L3);
501 } catch (ParseException e) {
502 if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
503 fail(String.format("bad truncated packet of length %d", len));
504 }
505 }
506 }
507 }
508
509 public void testRandomPackets() throws Exception {
510 final int maxRandomPacketSize = 512;
511 final Random r = new Random();
512 for (int i = 0; i < 10000; i++) {
513 byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
514 r.nextBytes(packet);
515 try {
516 DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
517 } catch (ParseException e) {
518 if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
519 fail("bad packet: " + HexDump.toHexString(packet));
520 }
521 }
522 }
523 }
524
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900525 private byte[] mtuBytes(int mtu) {
526 // 0x1a02: option 26, length 2. 0xff: no more options.
527 if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
528 throw new IllegalArgumentException(
529 String.format("Invalid MTU %d, must be 16-bit unsigned", mtu));
530 }
531 String hexString = String.format("1a02%04xff", mtu);
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900532 return HexDump.hexStringToByteArray(hexString);
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900533 }
534
535 private void checkMtu(ByteBuffer packet, int expectedMtu, byte[] mtuBytes) throws Exception {
536 if (mtuBytes != null) {
537 packet.position(packet.capacity() - mtuBytes.length);
538 packet.put(mtuBytes);
539 packet.clear();
540 }
541 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
542 assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
543 DhcpResults dhcpResults = offerPacket.toDhcpResults();
544 assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
545 null, "192.168.144.3", null, 7200, false, expectedMtu, dhcpResults);
546 }
547
548 @SmallTest
549 public void testMtu() throws Exception {
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900550 final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900551 // IP header.
552 "451001480000000080118849c0a89003c0a89ff7" +
553 // UDP header.
554 "004300440134dcfa" +
555 // BOOTP header.
556 "02010600c997a63b0000000000000000c0a89ff70000000000000000" +
557 // MAC address.
558 "30766ff2a90c00000000000000000000" +
559 // Server name.
560 "0000000000000000000000000000000000000000000000000000000000000000" +
561 "0000000000000000000000000000000000000000000000000000000000000000" +
562 // File.
563 "0000000000000000000000000000000000000000000000000000000000000000" +
564 "0000000000000000000000000000000000000000000000000000000000000000" +
565 "0000000000000000000000000000000000000000000000000000000000000000" +
566 "0000000000000000000000000000000000000000000000000000000000000000" +
567 // Options
568 "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900569 "3a0400000e103b040000189cff00000000"));
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900570
571 checkMtu(packet, 0, null);
572 checkMtu(packet, 0, mtuBytes(1501));
573 checkMtu(packet, 1500, mtuBytes(1500));
574 checkMtu(packet, 1499, mtuBytes(1499));
575 checkMtu(packet, 1280, mtuBytes(1280));
576 checkMtu(packet, 0, mtuBytes(1279));
577 checkMtu(packet, 0, mtuBytes(576));
578 checkMtu(packet, 0, mtuBytes(68));
579 checkMtu(packet, 0, mtuBytes(Short.MIN_VALUE));
580 checkMtu(packet, 0, mtuBytes(Short.MAX_VALUE + 3));
581 checkMtu(packet, 0, mtuBytes(-1));
582 }
583
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900584 @SmallTest
Lorenzo Colittid64144a2015-09-03 17:36:20 +0900585 public void testBadHwaddrLength() throws Exception {
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900586 final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
Lorenzo Colittid64144a2015-09-03 17:36:20 +0900587 // IP header.
588 "450001518d0600004011144dc0a82b01c0a82bf7" +
589 // UDP header.
590 "00430044013d9ac7" +
591 // BOOTP header.
592 "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
593 // MAC address.
594 "30766ff2a90c00000000000000000000" +
595 // Server name.
596 "0000000000000000000000000000000000000000000000000000000000000000" +
597 "0000000000000000000000000000000000000000000000000000000000000000" +
598 // File.
599 "0000000000000000000000000000000000000000000000000000000000000000" +
600 "0000000000000000000000000000000000000000000000000000000000000000" +
601 "0000000000000000000000000000000000000000000000000000000000000000" +
602 "0000000000000000000000000000000000000000000000000000000000000000" +
603 // Options
604 "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900605 "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
Lorenzo Colittid64144a2015-09-03 17:36:20 +0900606 String expectedClientMac = "30766FF2A90C";
607
608 final int hwAddrLenOffset = 20 + 8 + 2;
609 assertEquals(6, packet.get(hwAddrLenOffset));
610
611 // Expect the expected.
612 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
613 assertNotNull(offerPacket);
614 assertEquals(6, offerPacket.getClientMac().length);
615 assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
616
617 // Reduce the hardware address length and verify that it shortens the client MAC.
618 packet.flip();
619 packet.put(hwAddrLenOffset, (byte) 5);
620 offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
621 assertNotNull(offerPacket);
622 assertEquals(5, offerPacket.getClientMac().length);
623 assertEquals(expectedClientMac.substring(0, 10),
624 HexDump.toHexString(offerPacket.getClientMac()));
625
626 packet.flip();
627 packet.put(hwAddrLenOffset, (byte) 3);
628 offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
629 assertNotNull(offerPacket);
630 assertEquals(3, offerPacket.getClientMac().length);
631 assertEquals(expectedClientMac.substring(0, 6),
632 HexDump.toHexString(offerPacket.getClientMac()));
633
634 // Set the the hardware address length to 0xff and verify that we a) don't treat it as -1
635 // and crash, and b) hardcode it to 6.
636 packet.flip();
637 packet.put(hwAddrLenOffset, (byte) -1);
638 offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
639 assertNotNull(offerPacket);
640 assertEquals(6, offerPacket.getClientMac().length);
641 assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
642
643 // Set the the hardware address length to a positive invalid value (> 16) and verify that we
644 // hardcode it to 6.
645 packet.flip();
646 packet.put(hwAddrLenOffset, (byte) 17);
647 offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
648 assertNotNull(offerPacket);
649 assertEquals(6, offerPacket.getClientMac().length);
650 assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
651 }
652
653 @SmallTest
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900654 public void testPadAndOverloadedOptionsOffer() throws Exception {
655 // A packet observed in the real world that is interesting for two reasons:
656 //
657 // 1. It uses pad bytes, which we previously didn't support correctly.
658 // 2. It uses DHCP option overloading, which we don't currently support (but it doesn't
659 // store any information in the overloaded fields).
660 //
661 // For now, we just check that it parses correctly.
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900662 final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900663 // Ethernet header.
664 "b4cef6000000e80462236e300800" +
665 // IP header.
666 "4500014c00000000ff11741701010101ac119876" +
667 // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
668 "004300440138ae5a" +
669 // BOOTP header.
670 "020106000fa0059f0000000000000000ac1198760000000000000000" +
671 // MAC address.
672 "b4cef600000000000000000000000000" +
673 // Server name.
674 "ff00000000000000000000000000000000000000000000000000000000000000" +
675 "0000000000000000000000000000000000000000000000000000000000000000" +
676 // File.
677 "ff00000000000000000000000000000000000000000000000000000000000000" +
678 "0000000000000000000000000000000000000000000000000000000000000000" +
679 "0000000000000000000000000000000000000000000000000000000000000000" +
680 "0000000000000000000000000000000000000000000000000000000000000000" +
681 // Options
682 "638253633501023604010101010104ffff000033040000a8c03401030304ac1101010604ac110101" +
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900683 "0000000000000000000000000000000000000000000000ff000000"));
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900684
685 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
686 assertTrue(offerPacket instanceof DhcpOfferPacket);
687 DhcpResults dhcpResults = offerPacket.toDhcpResults();
688 assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1",
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900689 null, "1.1.1.1", null, 43200, false, 0, dhcpResults);
Lorenzo Colittib0b3d0b2015-07-06 12:29:43 +0900690 }
Lorenzo Colittif28e62b2015-07-27 16:35:22 +0900691
692 @SmallTest
693 public void testBug2111() throws Exception {
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900694 final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
Lorenzo Colittif28e62b2015-07-27 16:35:22 +0900695 // IP header.
696 "4500014c00000000ff119beac3eaf3880a3f5d04" +
697 // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
698 "0043004401387464" +
699 // BOOTP header.
700 "0201060002554812000a0000000000000a3f5d040000000000000000" +
701 // MAC address.
702 "00904c00000000000000000000000000" +
703 // Server name.
704 "0000000000000000000000000000000000000000000000000000000000000000" +
705 "0000000000000000000000000000000000000000000000000000000000000000" +
706 // File.
707 "0000000000000000000000000000000000000000000000000000000000000000" +
708 "0000000000000000000000000000000000000000000000000000000000000000" +
709 "0000000000000000000000000000000000000000000000000000000000000000" +
710 "0000000000000000000000000000000000000000000000000000000000000000" +
711 // Options.
712 "638253633501023604c00002fe33040000bfc60104fffff00003040a3f50010608c0000201c0000202" +
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900713 "0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"));
Lorenzo Colittif28e62b2015-07-27 16:35:22 +0900714
715 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
716 assertTrue(offerPacket instanceof DhcpOfferPacket);
717 DhcpResults dhcpResults = offerPacket.toDhcpResults();
718 assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2",
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900719 "domain123.co.uk", "192.0.2.254", null, 49094, false, 0, dhcpResults);
Lorenzo Colittif28e62b2015-07-27 16:35:22 +0900720 }
721
722 @SmallTest
723 public void testBug2136() throws Exception {
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900724 final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
Lorenzo Colittif28e62b2015-07-27 16:35:22 +0900725 // Ethernet header.
726 "bcf5ac000000d0c7890000000800" +
727 // IP header.
728 "4500014c00000000ff119beac3eaf3880a3f5d04" +
729 // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
730 "0043004401387574" +
731 // BOOTP header.
732 "0201060163339a3000050000000000000a209ecd0000000000000000" +
733 // MAC address.
734 "bcf5ac00000000000000000000000000" +
735 // Server name.
736 "0000000000000000000000000000000000000000000000000000000000000000" +
737 "0000000000000000000000000000000000000000000000000000000000000000" +
738 // File.
739 "0000000000000000000000000000000000000000000000000000000000000000" +
740 "0000000000000000000000000000000000000000000000000000000000000000" +
741 "0000000000000000000000000000000000000000000000000000000000000000" +
742 "0000000000000000000000000000000000000000000000000000000000000000" +
743 // Options.
744 "6382536335010236040a20ff80330400001c200104fffff00003040a20900106089458413494584135" +
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900745 "0f0b6c616e63732e61632e756b000000000000000000ff00000000"));
Lorenzo Colittif28e62b2015-07-27 16:35:22 +0900746
747 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
748 assertTrue(offerPacket instanceof DhcpOfferPacket);
749 assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac()));
750 DhcpResults dhcpResults = offerPacket.toDhcpResults();
751 assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900752 "lancs.ac.uk", "10.32.255.128", null, 7200, false, 0, dhcpResults);
Lorenzo Colittif28e62b2015-07-27 16:35:22 +0900753 }
Erik Klineb19238c2015-10-06 18:43:17 +0900754
755 @SmallTest
756 public void testUdpServerAnySourcePort() throws Exception {
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900757 final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
Erik Klineb19238c2015-10-06 18:43:17 +0900758 // Ethernet header.
759 "9cd917000000001c2e0000000800" +
760 // IP header.
761 "45a00148000040003d115087d18194fb0a0f7af2" +
762 // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
763 // NOTE: The server source port is not the canonical port 67.
764 "C29F004401341268" +
765 // BOOTP header.
766 "02010600d628ba8200000000000000000a0f7af2000000000a0fc818" +
767 // MAC address.
768 "9cd91700000000000000000000000000" +
769 // Server name.
770 "0000000000000000000000000000000000000000000000000000000000000000" +
771 "0000000000000000000000000000000000000000000000000000000000000000" +
772 // File.
773 "0000000000000000000000000000000000000000000000000000000000000000" +
774 "0000000000000000000000000000000000000000000000000000000000000000" +
775 "0000000000000000000000000000000000000000000000000000000000000000" +
776 "0000000000000000000000000000000000000000000000000000000000000000" +
777 // Options.
778 "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900779 "d18180060f0777766d2e6564751c040a0fffffff000000"));
Erik Klineb19238c2015-10-06 18:43:17 +0900780
781 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
782 assertTrue(offerPacket instanceof DhcpOfferPacket);
783 assertEquals("9CD917000000", HexDump.toHexString(offerPacket.getClientMac()));
784 DhcpResults dhcpResults = offerPacket.toDhcpResults();
785 assertDhcpResults("10.15.122.242/16", "10.15.200.23",
786 "209.129.128.3,209.129.148.3,209.129.128.6",
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900787 "wvm.edu", "10.1.105.252", null, 86400, false, 0, dhcpResults);
Erik Klineb19238c2015-10-06 18:43:17 +0900788 }
Lorenzo Colitti025f4a52015-09-17 07:55:29 +0900789
790 @SmallTest
Lorenzo Colittif55c9c12016-03-02 13:31:52 +0900791 public void testUdpInvalidDstPort() throws Exception {
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900792 final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
Lorenzo Colittif55c9c12016-03-02 13:31:52 +0900793 // Ethernet header.
794 "9cd917000000001c2e0000000800" +
795 // IP header.
796 "45a00148000040003d115087d18194fb0a0f7af2" +
797 // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
798 // NOTE: The destination port is a non-DHCP port.
799 "0043aaaa01341268" +
800 // BOOTP header.
801 "02010600d628ba8200000000000000000a0f7af2000000000a0fc818" +
802 // MAC address.
803 "9cd91700000000000000000000000000" +
804 // Server name.
805 "0000000000000000000000000000000000000000000000000000000000000000" +
806 "0000000000000000000000000000000000000000000000000000000000000000" +
807 // File.
808 "0000000000000000000000000000000000000000000000000000000000000000" +
809 "0000000000000000000000000000000000000000000000000000000000000000" +
810 "0000000000000000000000000000000000000000000000000000000000000000" +
811 "0000000000000000000000000000000000000000000000000000000000000000" +
812 // Options.
813 "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900814 "d18180060f0777766d2e6564751c040a0fffffff000000"));
Lorenzo Colittif55c9c12016-03-02 13:31:52 +0900815
816 try {
817 DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
818 fail("Packet with invalid dst port did not throw ParseException");
819 } catch (ParseException expected) {}
820 }
821
822 @SmallTest
Lorenzo Colitti025f4a52015-09-17 07:55:29 +0900823 public void testMultipleRouters() throws Exception {
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900824 final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
Lorenzo Colitti025f4a52015-09-17 07:55:29 +0900825 // Ethernet header.
826 "fc3d93000000" + "081735000000" + "0800" +
827 // IP header.
828 "45000148c2370000ff117ac2c0a8bd02ffffffff" +
829 // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
830 "0043004401343beb" +
831 // BOOTP header.
832 "0201060027f518e20000800000000000c0a8bd310000000000000000" +
833 // MAC address.
834 "fc3d9300000000000000000000000000" +
835 // Server name.
836 "0000000000000000000000000000000000000000000000000000000000000000" +
837 "0000000000000000000000000000000000000000000000000000000000000000" +
838 // File.
839 "0000000000000000000000000000000000000000000000000000000000000000" +
840 "0000000000000000000000000000000000000000000000000000000000000000" +
841 "0000000000000000000000000000000000000000000000000000000000000000" +
842 "0000000000000000000000000000000000000000000000000000000000000000" +
843 // Options.
844 "638253633501023604c0abbd023304000070803a04000038403b04000062700104ffffff00" +
Hugo Benichie0ea7fe2016-10-05 18:33:21 +0900845 "0308c0a8bd01ffffff0006080808080808080404ff000000000000"));
Lorenzo Colitti025f4a52015-09-17 07:55:29 +0900846
847 DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
848 assertTrue(offerPacket instanceof DhcpOfferPacket);
849 assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
850 DhcpResults dhcpResults = offerPacket.toDhcpResults();
851 assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4",
Lorenzo Colitti77fdf232016-03-31 16:20:22 +0900852 null, "192.171.189.2", null, 28800, false, 0, dhcpResults);
Lorenzo Colitti025f4a52015-09-17 07:55:29 +0900853 }
Lorenzo Colitti6c7acb62015-06-29 17:10:45 +0900854
855 @SmallTest
856 public void testDiscoverPacket() throws Exception {
857 short secs = 7;
858 int transactionId = 0xdeadbeef;
859 byte[] hwaddr = {
860 (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a
861 };
Lorenzo Colitti6c7acb62015-06-29 17:10:45 +0900862
863 ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
864 DhcpPacket.ENCAP_L2, transactionId, secs, hwaddr,
Erik Kline1d511ab2016-03-24 17:30:13 +0900865 false /* do unicast */, DhcpClient.REQUESTED_PARAMS);
Lorenzo Colitti6c7acb62015-06-29 17:10:45 +0900866
867 byte[] headers = new byte[] {
868 // Ethernet header.
869 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
870 (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a,
871 (byte) 0x08, (byte) 0x00,
872 // IP header.
Erik Kline1d511ab2016-03-24 17:30:13 +0900873 (byte) 0x45, (byte) 0x10, (byte) 0x01, (byte) 0x56,
Lorenzo Colitti6c7acb62015-06-29 17:10:45 +0900874 (byte) 0x00, (byte) 0x00, (byte) 0x40, (byte) 0x00,
Erik Kline1d511ab2016-03-24 17:30:13 +0900875 (byte) 0x40, (byte) 0x11, (byte) 0x39, (byte) 0x88,
Lorenzo Colitti6c7acb62015-06-29 17:10:45 +0900876 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
877 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
878 // UDP header.
879 (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43,
Erik Kline1d511ab2016-03-24 17:30:13 +0900880 (byte) 0x01, (byte) 0x42, (byte) 0x6a, (byte) 0x4a,
Lorenzo Colitti6c7acb62015-06-29 17:10:45 +0900881 // BOOTP.
882 (byte) 0x01, (byte) 0x01, (byte) 0x06, (byte) 0x00,
883 (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
884 (byte) 0x00, (byte) 0x07, (byte) 0x00, (byte) 0x00,
885 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
886 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
887 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
888 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
889 (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b,
890 (byte) 0xb1, (byte) 0x7a
891 };
892 byte[] options = new byte[] {
893 // Magic cookie 0x63825363.
894 (byte) 0x63, (byte) 0x82, (byte) 0x53, (byte) 0x63,
895 // Message type DISCOVER.
896 (byte) 0x35, (byte) 0x01, (byte) 0x01,
897 // Client identifier Ethernet, da:01:19:5b:b1:7a.
898 (byte) 0x3d, (byte) 0x07,
899 (byte) 0x01,
900 (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a,
901 // Max message size 1500.
902 (byte) 0x39, (byte) 0x02, (byte) 0x05, (byte) 0xdc,
903 // Version "android-dhcp-???".
904 (byte) 0x3c, (byte) 0x10,
905 'a', 'n', 'd', 'r', 'o', 'i', 'd', '-', 'd', 'h', 'c', 'p', '-', '?', '?', '?',
906 // Hostname "android-01234567890abcde"
907 (byte) 0x0c, (byte) 0x18,
908 'a', 'n', 'd', 'r', 'o', 'i', 'd', '-',
909 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e',
910 // Requested parameter list.
Erik Kline1d511ab2016-03-24 17:30:13 +0900911 (byte) 0x37, (byte) 0x0a,
Lorenzo Colitti6c7acb62015-06-29 17:10:45 +0900912 DHCP_SUBNET_MASK,
913 DHCP_ROUTER,
914 DHCP_DNS_SERVER,
915 DHCP_DOMAIN_NAME,
916 DHCP_MTU,
Erik Kline1d511ab2016-03-24 17:30:13 +0900917 DHCP_BROADCAST_ADDRESS,
Lorenzo Colitti6c7acb62015-06-29 17:10:45 +0900918 DHCP_LEASE_TIME,
Erik Kline1d511ab2016-03-24 17:30:13 +0900919 DHCP_RENEWAL_TIME,
920 DHCP_REBINDING_TIME,
921 DHCP_VENDOR_INFO,
Lorenzo Colitti6c7acb62015-06-29 17:10:45 +0900922 // End options.
923 (byte) 0xff,
924 // Our packets are always of even length. TODO: find out why and possibly fix it.
925 (byte) 0x00
926 };
927 byte[] expected = new byte[DhcpPacket.MIN_PACKET_LENGTH_L2 + options.length];
928 assertTrue((expected.length & 1) == 0);
929 System.arraycopy(headers, 0, expected, 0, headers.length);
930 System.arraycopy(options, 0, expected, DhcpPacket.MIN_PACKET_LENGTH_L2, options.length);
931
932 byte[] actual = new byte[packet.limit()];
933 packet.get(actual);
934 String msg =
935 "Expected:\n " + Arrays.toString(expected) +
936 "\nActual:\n " + Arrays.toString(actual);
937 assertTrue(msg, Arrays.equals(expected, actual));
938 }
Lorenzo Colittic2abb2b2015-03-31 16:26:57 +0900939}