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