1 /*
2  * Copyright (C) 2019 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 
17 package com.android.net.module.util;
18 
19 import static android.net.DnsResolver.CLASS_IN;
20 import static android.net.DnsResolver.TYPE_A;
21 import static android.net.DnsResolver.TYPE_AAAA;
22 
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertNotEquals;
25 import static org.junit.Assert.assertNull;
26 import static org.junit.Assert.assertThrows;
27 import static org.junit.Assert.assertTrue;
28 import static org.junit.Assert.fail;
29 
30 import android.annotation.NonNull;
31 import android.annotation.Nullable;
32 
33 import androidx.test.filters.SmallTest;
34 import androidx.test.runner.AndroidJUnit4;
35 
36 import libcore.net.InetAddressUtils;
37 
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import java.io.IOException;
42 import java.nio.BufferUnderflowException;
43 import java.nio.ByteBuffer;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.List;
47 
48 @RunWith(AndroidJUnit4.class)
49 @SmallTest
50 public class DnsPacketTest {
51     private static final int TEST_DNS_PACKET_ID = 0x7722;
52     private static final int TEST_DNS_PACKET_FLAGS = 0x8180;
53 
assertHeaderParses(DnsPacket.DnsHeader header, int id, int flag, int qCount, int aCount, int nsCount, int arCount)54     private void assertHeaderParses(DnsPacket.DnsHeader header, int id, int flag,
55             int qCount, int aCount, int nsCount, int arCount) {
56         assertEquals(header.getId(), id);
57         assertEquals(header.getFlags(), flag);
58         assertEquals(header.getRecordCount(DnsPacket.QDSECTION), qCount);
59         assertEquals(header.getRecordCount(DnsPacket.ANSECTION), aCount);
60         assertEquals(header.getRecordCount(DnsPacket.NSSECTION), nsCount);
61         assertEquals(header.getRecordCount(DnsPacket.ARSECTION), arCount);
62     }
63 
assertRecordParses(DnsPacket.DnsRecord record, String dname, int dtype, int dclass, int ttl, byte[] rr)64     private void assertRecordParses(DnsPacket.DnsRecord record, String dname,
65             int dtype, int dclass, int ttl, byte[] rr) {
66         assertEquals(record.dName, dname);
67         assertEquals(record.nsType, dtype);
68         assertEquals(record.nsClass, dclass);
69         assertEquals(record.ttl, ttl);
70         assertTrue(Arrays.equals(record.getRR(), rr));
71     }
72 
73     static class TestDnsPacket extends DnsPacket {
TestDnsPacket(byte[] data)74         TestDnsPacket(byte[] data) throws DnsPacket.ParseException {
75             super(data);
76         }
77 
TestDnsPacket(@onNull DnsHeader header, @Nullable ArrayList<DnsRecord> qd, @Nullable ArrayList<DnsRecord> an)78         TestDnsPacket(@NonNull DnsHeader header, @Nullable ArrayList<DnsRecord> qd,
79                 @Nullable ArrayList<DnsRecord> an) {
80             super(header, qd, an);
81         }
82 
getHeader()83         public DnsHeader getHeader() {
84             return mHeader;
85         }
getRecordList(int secType)86         public List<DnsRecord> getRecordList(int secType) {
87             return mRecords[secType];
88         }
89     }
90 
91     @Test
testNullDisallowed()92     public void testNullDisallowed() {
93         try {
94             new TestDnsPacket(null);
95             fail("Exception not thrown for null byte array");
96         } catch (DnsPacket.ParseException e) {
97         }
98     }
99 
100     @Test
testV4Answer()101     public void testV4Answer() throws Exception {
102         final byte[] v4blob = new byte[] {
103             /* Header */
104             0x55, 0x66, /* Transaction ID */
105             (byte) 0x81, (byte) 0x80, /* Flags */
106             0x00, 0x01, /* Questions */
107             0x00, 0x01, /* Answer RRs */
108             0x00, 0x00, /* Authority RRs */
109             0x00, 0x00, /* Additional RRs */
110             /* Queries */
111             0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
112             0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
113             0x00, 0x01, /* Type */
114             0x00, 0x01, /* Class */
115             /* Answers */
116             (byte) 0xc0, 0x0c, /* Name */
117             0x00, 0x01, /* Type */
118             0x00, 0x01, /* Class */
119             0x00, 0x00, 0x01, 0x2b, /* TTL */
120             0x00, 0x04, /* Data length */
121             (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */
122         };
123         TestDnsPacket packet = new TestDnsPacket(v4blob);
124 
125         // Header part
126         assertHeaderParses(packet.getHeader(), 0x5566, 0x8180, 1, 1, 0, 0);
127 
128         // Record part
129         List<DnsPacket.DnsRecord> qdRecordList =
130                 packet.getRecordList(DnsPacket.QDSECTION);
131         assertEquals(qdRecordList.size(), 1);
132         assertRecordParses(qdRecordList.get(0), "www.google.com", 1, 1, 0, null);
133 
134         List<DnsPacket.DnsRecord> anRecordList =
135                 packet.getRecordList(DnsPacket.ANSECTION);
136         assertEquals(anRecordList.size(), 1);
137         assertRecordParses(anRecordList.get(0), "www.google.com", 1, 1, 0x12b,
138                 new byte[]{ (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 });
139     }
140 
141     @Test
testV6Answer()142     public void testV6Answer() throws Exception {
143         final byte[] v6blob = new byte[] {
144             /* Header */
145             0x77, 0x22, /* Transaction ID */
146             (byte) 0x81, (byte) 0x80, /* Flags */
147             0x00, 0x01, /* Questions */
148             0x00, 0x01, /* Answer RRs */
149             0x00, 0x00, /* Authority RRs */
150             0x00, 0x00, /* Additional RRs */
151             /* Queries */
152             0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
153             0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
154             0x00, 0x1c, /* Type */
155             0x00, 0x01, /* Class */
156             /* Answers */
157             (byte) 0xc0, 0x0c, /* Name */
158             0x00, 0x1c, /* Type */
159             0x00, 0x01, /* Class */
160             0x00, 0x00, 0x00, 0x37, /* TTL */
161             0x00, 0x10, /* Data length */
162             0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d,
163             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 /* Address */
164         };
165         TestDnsPacket packet = new TestDnsPacket(v6blob);
166 
167         // Header part
168         assertHeaderParses(packet.getHeader(), 0x7722, 0x8180, 1, 1, 0, 0);
169 
170         // Record part
171         List<DnsPacket.DnsRecord> qdRecordList =
172                 packet.getRecordList(DnsPacket.QDSECTION);
173         assertEquals(qdRecordList.size(), 1);
174         assertRecordParses(qdRecordList.get(0), "www.google.com", 28, 1, 0, null);
175 
176         List<DnsPacket.DnsRecord> anRecordList =
177                 packet.getRecordList(DnsPacket.ANSECTION);
178         assertEquals(anRecordList.size(), 1);
179         assertRecordParses(anRecordList.get(0), "www.google.com", 28, 1, 0x37,
180                 new byte[]{ 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d,
181                     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 });
182     }
183 
184     /** Verifies that the synthesized {@link DnsPacket.DnsHeader} can be parsed correctly. */
185     @Test
testDnsHeaderSynthesize()186     public void testDnsHeaderSynthesize() {
187         final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID,
188                 TEST_DNS_PACKET_FLAGS, 3 /* qcount */, 5 /* ancount */);
189         final DnsPacket.DnsHeader actualHeader = new DnsPacket.DnsHeader(
190                 ByteBuffer.wrap(testHeader.getBytes()));
191         assertEquals(testHeader, actualHeader);
192     }
193 
194     /** Verifies that the synthesized {@link DnsPacket.DnsRecord} can be parsed correctly. */
195     @Test
testDnsRecordSynthesize()196     public void testDnsRecordSynthesize() throws IOException {
197         assertDnsRecordRoundTrip(
198                 DnsPacket.DnsRecord.makeAOrAAAARecord(DnsPacket.ANSECTION,
199                         "test.com", CLASS_IN, 5 /* ttl */,
200                         InetAddressUtils.parseNumericAddress("abcd::fedc")));
201         assertDnsRecordRoundTrip(DnsPacket.DnsRecord.makeQuestion("test.com", TYPE_AAAA, CLASS_IN));
202         assertDnsRecordRoundTrip(DnsPacket.DnsRecord.makeCNameRecord(DnsPacket.ANSECTION,
203                 "test.com", CLASS_IN, 0 /* ttl */, "example.com"));
204     }
205 
206     /** Verifies that the type of implementation returned from DnsRecord#parse is correct */
207     @Test
testDnsRecordParse()208     public void testDnsRecordParse() throws IOException {
209         final byte[] svcbQuestionRecord = new byte[] {
210                 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00, /* Name */
211                 0x00, 0x40, /* Type */
212                 0x00, 0x01, /* Class */
213         };
214         assertTrue(DnsPacket.DnsRecord.parse(DnsPacket.QDSECTION,
215                 ByteBuffer.wrap(svcbQuestionRecord)) instanceof DnsSvcbRecord);
216 
217         final byte[] svcbAnswerRecord = new byte[] {
218                 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00, /* Name */
219                 0x00, 0x40, /* Type */
220                 0x00, 0x01, /* Class */
221                 0x00, 0x00, 0x01, 0x2b, /* TTL */
222                 0x00, 0x0b, /* Data length */
223                 0x00, 0x01, /* SvcPriority */
224                 0x03, 'd', 'o', 't', 0x03, 'c', 'o', 'm', 0x00, /* TargetName */
225         };
226         assertTrue(DnsPacket.DnsRecord.parse(DnsPacket.ANSECTION,
227                 ByteBuffer.wrap(svcbAnswerRecord)) instanceof DnsSvcbRecord);
228     }
229 
230     /**
231      * Verifies ttl/rData error handling when parsing
232      * {@link DnsPacket.DnsRecord} from bytes.
233      */
234     @Test
testDnsRecordTTLRDataErrorHandling()235     public void testDnsRecordTTLRDataErrorHandling() throws IOException {
236         // Verify the constructor ignore ttl/rData of questions even if they are supplied.
237         final byte[] qdWithTTLRData = new byte[]{
238                 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
239                 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
240                 0x00, 0x00, /* Type */
241                 0x00, 0x01, /* Class */
242                 0x00, 0x00, 0x01, 0x2b, /* TTL */
243                 0x00, 0x04, /* Data length */
244                 (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */};
245         final DnsPacket.DnsRecord questionsFromBytes =
246                 DnsPacket.DnsRecord.parse(DnsPacket.QDSECTION, ByteBuffer.wrap(qdWithTTLRData));
247         assertEquals(0, questionsFromBytes.ttl);
248         assertNull(questionsFromBytes.getRR());
249 
250         // Verify ANSECTION must have rData when constructing.
251         final byte[] anWithoutTTLRData = new byte[]{
252                 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
253                 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
254                 0x00, 0x01, /* Type */
255                 0x00, 0x01, /* Class */};
256         assertThrows(BufferUnderflowException.class, () ->
257                 DnsPacket.DnsRecord.parse(DnsPacket.ANSECTION, ByteBuffer.wrap(anWithoutTTLRData)));
258     }
259 
assertDnsRecordRoundTrip(DnsPacket.DnsRecord before)260     private void assertDnsRecordRoundTrip(DnsPacket.DnsRecord before)
261             throws IOException {
262         final DnsPacket.DnsRecord after = DnsPacket.DnsRecord.parse(before.rType,
263                 ByteBuffer.wrap(before.getBytes()));
264         assertEquals(after, before);
265     }
266 
267     /** Verifies that the synthesized {@link DnsPacket} can be parsed correctly. */
268     @Test
testDnsPacketSynthesize()269     public void testDnsPacketSynthesize() throws IOException {
270         // Ipv4 dns response packet generated by scapy:
271         //   dns_r = scapy.DNS(
272         //      id=0xbeef,
273         //      qr=1,
274         //      qd=scapy.DNSQR(qname="hello.example.com"),
275         //      an=scapy.DNSRR(rrname="hello.example.com", type="CNAME", rdata='test.com') /
276         //      scapy.DNSRR(rrname="hello.example.com", rdata='1.2.3.4'))
277         //   scapy.hexdump(dns_r)
278         //   dns_r.show2()
279         // Note that since the synthesizing does not support name compression yet, the domain
280         // name of the sample need to be uncompressed when generating.
281         final byte[] v4BlobUncompressed = new byte[]{
282                 /* Header */
283                 (byte) 0xbe, (byte) 0xef, /* Transaction ID */
284                 (byte) 0x81, 0x00, /* Flags */
285                 0x00, 0x01, /* Questions */
286                 0x00, 0x02, /* Answer RRs */
287                 0x00, 0x00, /* Authority RRs */
288                 0x00, 0x00, /* Additional RRs */
289                 /* Queries */
290                 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61,
291                 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */
292                 0x00, 0x01, /* Type */
293                 0x00, 0x01, /* Class */
294                 /* Answers */
295                 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61,
296                 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */
297                 0x00, 0x05, /* Type */
298                 0x00, 0x01, /* Class */
299                 0x00, 0x00, 0x00, 0x00, /* TTL */
300                 0x00, 0x0A, /* Data length */
301                 0x04, 0x74, 0x65, 0x73, 0x74, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Alias: test.com */
302                 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61,
303                 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */
304                 0x00, 0x01, /* Type */
305                 0x00, 0x01, /* Class */
306                 0x00, 0x00, 0x00, 0x00, /* TTL */
307                 0x00, 0x04, /* Data length */
308                 0x01, 0x02, 0x03, 0x04, /* Address: 1.2.3.4 */
309         };
310 
311         // Forge one via constructors.
312         final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(0xbeef,
313                 0x8100, 1 /* qcount */, 2 /* ancount */);
314         final ArrayList<DnsPacket.DnsRecord> qlist = new ArrayList<>();
315         final ArrayList<DnsPacket.DnsRecord> alist = new ArrayList<>();
316         qlist.add(DnsPacket.DnsRecord.makeQuestion(
317                 "hello.example.com", TYPE_A, CLASS_IN));
318         alist.add(DnsPacket.DnsRecord.makeCNameRecord(
319                 DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, "test.com"));
320         alist.add(DnsPacket.DnsRecord.makeAOrAAAARecord(
321                 DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */,
322                 InetAddressUtils.parseNumericAddress("1.2.3.4")));
323         final TestDnsPacket testPacket = new TestDnsPacket(testHeader, qlist, alist);
324 
325         // Assert content equals in both ways.
326         assertTrue(Arrays.equals(v4BlobUncompressed, testPacket.getBytes()));
327         assertEquals(new TestDnsPacket(v4BlobUncompressed), testPacket);
328     }
329 
330     @Test
testDnsPacketSynthesize_recordCountMismatch()331     public void testDnsPacketSynthesize_recordCountMismatch() throws IOException {
332         final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(0xbeef,
333                 0x8100, 1 /* qcount */, 1 /* ancount */);
334         final ArrayList<DnsPacket.DnsRecord> qlist = new ArrayList<>();
335         final ArrayList<DnsPacket.DnsRecord> alist = new ArrayList<>();
336         qlist.add(DnsPacket.DnsRecord.makeQuestion(
337                 "hello.example.com", TYPE_A, CLASS_IN));
338 
339         // Assert throws if the supplied answer records fewer than the declared count.
340         assertThrows(IllegalArgumentException.class, () ->
341                 new TestDnsPacket(testHeader, qlist, alist));
342 
343         // Assert throws if the supplied answer records more than the declared count.
344         alist.add(DnsPacket.DnsRecord.makeCNameRecord(
345                 DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, "test.com"));
346         alist.add(DnsPacket.DnsRecord.makeAOrAAAARecord(
347                 DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */,
348                 InetAddressUtils.parseNumericAddress("1.2.3.4")));
349         assertThrows(IllegalArgumentException.class, () ->
350                 new TestDnsPacket(testHeader, qlist, alist));
351 
352         // Assert counts matched if the byte buffer still has data when parsing ended.
353         final byte[] blobTooMuchData = new byte[]{
354                 /* Header */
355                 (byte) 0xbe, (byte) 0xef, /* Transaction ID */
356                 (byte) 0x81, 0x00, /* Flags */
357                 0x00, 0x00, /* Questions */
358                 0x00, 0x00, /* Answer RRs */
359                 0x00, 0x00, /* Authority RRs */
360                 0x00, 0x00, /* Additional RRs */
361                 /* Queries */
362                 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61,
363                 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */
364                 0x00, 0x01, /* Type */
365                 0x00, 0x01, /* Class */
366         };
367         final TestDnsPacket packetFromTooMuchData = new TestDnsPacket(blobTooMuchData);
368         for (int i = 0; i < DnsPacket.NUM_SECTIONS; i++) {
369             assertEquals(0, packetFromTooMuchData.getRecordList(i).size());
370             assertEquals(0, packetFromTooMuchData.getHeader().getRecordCount(i));
371         }
372 
373         // Assert throws if the byte buffer ended when expecting more records.
374         final byte[] blobNotEnoughData = new byte[]{
375                 /* Header */
376                 (byte) 0xbe, (byte) 0xef, /* Transaction ID */
377                 (byte) 0x81, 0x00, /* Flags */
378                 0x00, 0x01, /* Questions */
379                 0x00, 0x02, /* Answer RRs */
380                 0x00, 0x00, /* Authority RRs */
381                 0x00, 0x00, /* Additional RRs */
382                 /* Queries */
383                 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61,
384                 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */
385                 0x00, 0x01, /* Type */
386                 0x00, 0x01, /* Class */
387                 /* Answers */
388                 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61,
389                 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */
390                 0x00, 0x01, /* Type */
391                 0x00, 0x01, /* Class */
392                 0x00, 0x00, 0x00, 0x00, /* TTL */
393                 0x00, 0x04, /* Data length */
394                 0x01, 0x02, 0x03, 0x04, /* Address */
395         };
396         assertThrows(DnsPacket.ParseException.class, () -> new TestDnsPacket(blobNotEnoughData));
397     }
398 
399     @Test
testEqualsAndHashCode()400     public void testEqualsAndHashCode() throws IOException {
401         // Verify DnsHeader equals and hashCode.
402         final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID,
403                 TEST_DNS_PACKET_FLAGS, 1 /* qcount */, 1 /* ancount */);
404         final DnsPacket.DnsHeader emptyHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID + 1,
405                 TEST_DNS_PACKET_FLAGS + 0x08, 0 /* qcount */, 0 /* ancount */);
406         final DnsPacket.DnsHeader headerFromBytes =
407                 new DnsPacket.DnsHeader(ByteBuffer.wrap(testHeader.getBytes()));
408         assertEquals(testHeader, headerFromBytes);
409         assertEquals(testHeader.hashCode(), headerFromBytes.hashCode());
410         assertNotEquals(testHeader, emptyHeader);
411         assertNotEquals(testHeader.hashCode(), emptyHeader.hashCode());
412         assertNotEquals(headerFromBytes, emptyHeader);
413         assertNotEquals(headerFromBytes.hashCode(), emptyHeader.hashCode());
414 
415         // Verify DnsRecord equals and hashCode.
416         final DnsPacket.DnsRecord testQuestion = DnsPacket.DnsRecord.makeQuestion(
417                 "test.com", TYPE_AAAA, CLASS_IN);
418         final DnsPacket.DnsRecord testAnswer = DnsPacket.DnsRecord.makeCNameRecord(
419                 DnsPacket.ANSECTION, "test.com", CLASS_IN, 9, "www.test.com");
420         final DnsPacket.DnsRecord questionFromBytes = DnsPacket.DnsRecord.parse(DnsPacket.QDSECTION,
421                 ByteBuffer.wrap(testQuestion.getBytes()));
422         assertEquals(testQuestion, questionFromBytes);
423         assertEquals(testQuestion.hashCode(), questionFromBytes.hashCode());
424         assertNotEquals(testQuestion, testAnswer);
425         assertNotEquals(testQuestion.hashCode(), testAnswer.hashCode());
426         assertNotEquals(questionFromBytes, testAnswer);
427         assertNotEquals(questionFromBytes.hashCode(), testAnswer.hashCode());
428 
429         // Verify DnsPacket equals and hashCode.
430         final ArrayList<DnsPacket.DnsRecord> qlist = new ArrayList<>();
431         final ArrayList<DnsPacket.DnsRecord> alist = new ArrayList<>();
432         qlist.add(testQuestion);
433         alist.add(testAnswer);
434         final TestDnsPacket testPacket = new TestDnsPacket(testHeader, qlist, alist);
435         final TestDnsPacket emptyPacket = new TestDnsPacket(
436                 emptyHeader, new ArrayList<>(), new ArrayList<>());
437         final TestDnsPacket packetFromBytes = new TestDnsPacket(testPacket.getBytes());
438         assertEquals(testPacket, packetFromBytes);
439         assertEquals(testPacket.hashCode(), packetFromBytes.hashCode());
440         assertNotEquals(testPacket, emptyPacket);
441         assertNotEquals(testPacket.hashCode(), emptyPacket.hashCode());
442         assertNotEquals(packetFromBytes, emptyPacket);
443         assertNotEquals(packetFromBytes.hashCode(), emptyPacket.hashCode());
444 
445         // Verify DnsPacket with empty list.
446         final TestDnsPacket emptyPacketFromBytes = new TestDnsPacket(emptyPacket.getBytes());
447         assertEquals(emptyPacket, emptyPacketFromBytes);
448         assertEquals(emptyPacket.hashCode(), emptyPacketFromBytes.hashCode());
449     }
450 }
451