Revert "[ST02] Add methods for synthesizing DNS packets"
Revert "[ST02.1] Add TYPE_CNAME constant to DnsResolver"
Revert submission 1387135-st02
Reason for revert: Usage of TYPE_CNAME in a library shared among
modules does not interact well with current module release process
Reverted Changes:
Ib5616c65c:[ST02.2] Use the getters of DnsHeader
I5e58f99b0:[ST02.1] Add TYPE_CNAME constant to DnsResolver
I0c1547cbc:[ST02] Add methods for synthesizing DNS packets
Change-Id: I9f8de47c9ba9fb4db7cf3695966f222f68a9a290
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index f4997a1..4dfc752 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -96,10 +96,7 @@
visibility: [
"//packages/services/Iwlan:__subpackages__",
],
- libs: [
- "framework-annotations-lib",
- "framework-connectivity.stubs.module_lib",
- ],
+ libs: ["framework-annotations-lib"],
}
filegroup {
diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacket.java b/staticlibs/framework/com/android/net/module/util/DnsPacket.java
index 13a83ad..080781c 100644
--- a/staticlibs/framework/com/android/net/module/util/DnsPacket.java
+++ b/staticlibs/framework/com/android/net/module/util/DnsPacket.java
@@ -16,35 +16,15 @@
package com.android.net.module.util;
-import static android.net.DnsResolver.TYPE_A;
-import static android.net.DnsResolver.TYPE_AAAA;
-import static android.net.DnsResolver.TYPE_CNAME;
-
-import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
-import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
-import static com.android.net.module.util.DnsPacketUtils.DnsRecordParser.domainNameToLabels;
-
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.text.TextUtils;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.DnsPacketUtils.DnsRecordParser;
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.net.InetAddress;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
-import java.util.Objects;
/**
* Defines basic data for DNS protocol based on RFC 1035.
@@ -70,29 +50,13 @@
}
/**
- * DNS header for DNS protocol based on RFC 1035 section 4.1.1.
- *
- * 1 1 1 1 1 1
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | ID |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | QDCOUNT |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | ANCOUNT |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | NSCOUNT |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | ARCOUNT |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * DNS header for DNS protocol based on RFC 1035.
*/
- public static class DnsHeader {
+ public class DnsHeader {
private static final String TAG = "DnsHeader";
- private static final int SIZE_IN_BYTES = 12;
- private final int mId;
- private final int mFlags;
+ public final int id;
+ public final int flags;
+ public final int rcode;
private final int[] mRecordCount;
/* If this bit in the 'flags' field is set to 0, the DNS message corresponding to this
@@ -109,11 +73,10 @@
* advanced to the end of the DNS header record.
* This is meant to chain with other methods reading a DNS response in sequence.
*/
- @VisibleForTesting
- public DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException {
- Objects.requireNonNull(buf);
- mId = Short.toUnsignedInt(buf.getShort());
- mFlags = Short.toUnsignedInt(buf.getShort());
+ DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException {
+ id = Short.toUnsignedInt(buf.getShort());
+ flags = Short.toUnsignedInt(buf.getShort());
+ rcode = flags & 0xF;
mRecordCount = new int[NUM_SECTIONS];
for (int i = 0; i < NUM_SECTIONS; ++i) {
mRecordCount[i] = Short.toUnsignedInt(buf.getShort());
@@ -125,23 +88,7 @@
* RFC 1035 Section 4.1.1.
*/
public boolean isResponse() {
- return (mFlags & (1 << FLAGS_SECTION_QR_BIT)) != 0;
- }
-
- /**
- * Create a new DnsHeader from specified parameters.
- *
- * This constructor only builds the question and answer sections. Authority
- * and additional sections are not supported. Useful when synthesizing dns
- * responses from query or reply packets.
- */
- @VisibleForTesting
- public DnsHeader(int id, int flags, int qdcount, int ancount) {
- this.mId = id;
- this.mFlags = flags;
- mRecordCount = new int[NUM_SECTIONS];
- mRecordCount[QDSECTION] = qdcount;
- mRecordCount[ANSECTION] = ancount;
+ return (flags & (1 << FLAGS_SECTION_QR_BIT)) != 0;
}
/**
@@ -150,103 +97,15 @@
public int getRecordCount(int type) {
return mRecordCount[type];
}
-
- /**
- * Get flags of this instance.
- */
- public int getFlags() {
- return mFlags;
- }
-
- /**
- * Get id of this instance.
- */
- public int getId() {
- return mId;
- }
-
- @Override
- public String toString() {
- return "DnsHeader{" + "id=" + mId + ", flags=" + mFlags
- + ", recordCounts=" + Arrays.toString(mRecordCount) + '}';
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o.getClass() != getClass()) return false;
- final DnsHeader other = (DnsHeader) o;
- return mId == other.mId
- && mFlags == other.mFlags
- && Arrays.equals(mRecordCount, other.mRecordCount);
- }
-
- @Override
- public int hashCode() {
- return 31 * mId + 37 * mFlags + Arrays.hashCode(mRecordCount);
- }
-
- /**
- * Get DnsHeader as byte array.
- */
- @NonNull
- public byte[] getBytes() {
- // TODO: if this is called often, optimize the ByteBuffer out and write to the
- // array directly.
- final ByteBuffer buf = ByteBuffer.allocate(SIZE_IN_BYTES);
- buf.putShort((short) mId);
- buf.putShort((short) mFlags);
- for (int i = 0; i < NUM_SECTIONS; ++i) {
- buf.putShort((short) mRecordCount[i]);
- }
- return buf.array();
- }
}
/**
* Superclass for DNS questions and DNS resource records.
*
- * DNS questions (No TTL/RDLENGTH/RDATA) based on RFC 1035 section 4.1.2.
- * 1 1 1 1 1 1
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | |
- * / QNAME /
- * / /
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | QTYPE |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | QCLASS |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *
- * DNS resource records (With TTL/RDLENGTH/RDATA) based on RFC 1035 section 4.1.3.
- * 1 1 1 1 1 1
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | |
- * / /
- * / NAME /
- * | |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | TYPE |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | CLASS |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | TTL |
- * | |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- * | RDLENGTH |
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
- * / RDATA /
- * / /
- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * DNS questions (No TTL/RDATA)
+ * DNS resource records (With TTL/RDATA)
*/
- // TODO: Make DnsResourceRecord and DnsQuestion subclasses of DnsRecord, and construct
- // corresponding object from factory methods.
- public static class DnsRecord {
- // Refer to RFC 1035 section 2.3.4 for MAXNAMESIZE.
- // NAME_NORMAL and NAME_COMPRESSION are used for checking name compression,
- // refer to rfc 1035 section 4.1.4.
+ public class DnsRecord {
private static final int MAXNAMESIZE = 255;
public static final int NAME_NORMAL = 0;
public static final int NAME_COMPRESSION = 0xC0;
@@ -258,31 +117,22 @@
public final int nsClass;
public final long ttl;
private final byte[] mRdata;
- /**
- * Type of this DNS record.
- */
- @RecordType
- public final int rType;
/**
* Create a new DnsRecord from a positioned ByteBuffer.
*
* Reads the passed ByteBuffer from its current position and decodes a DNS record.
* When this constructor returns, the reading position of the ByteBuffer has been
- * advanced to the end of the DNS resource record.
+ * advanced to the end of the DNS header record.
* This is meant to chain with other methods reading a DNS response in sequence.
*
- * @param rType Type of the record.
* @param buf ByteBuffer input of record, must be in network byte order
* (which is the default).
*/
- @VisibleForTesting(visibility = PACKAGE)
- public DnsRecord(@RecordType int rType, @NonNull ByteBuffer buf)
+ DnsRecord(int recordType, @NonNull ByteBuffer buf)
throws BufferUnderflowException, ParseException {
- Objects.requireNonNull(buf);
- this.rType = rType;
dName = DnsRecordParser.parseName(buf, 0 /* Parse depth */,
- true /* isNameCompressionSupported */);
+ /* isNameCompressionSupported= */ true);
if (dName.length() > MAXNAMESIZE) {
throw new ParseException(
"Parse name fail, name size is too long: " + dName.length());
@@ -290,7 +140,7 @@
nsType = Short.toUnsignedInt(buf.getShort());
nsClass = Short.toUnsignedInt(buf.getShort());
- if (rType != QDSECTION) {
+ if (recordType != QDSECTION) {
ttl = Integer.toUnsignedLong(buf.getInt());
final int length = Short.toUnsignedInt(buf.getShort());
mRdata = new byte[length];
@@ -302,95 +152,6 @@
}
/**
- * Make an A or AAAA record based on the specified parameters.
- *
- * @param rType Type of the record, can be {@link #ANSECTION}, {@link #ARSECTION}
- * or {@link #NSSECTION}.
- * @param dName Domain name of the record.
- * @param nsClass Class of the record. See RFC 1035 section 3.2.4.
- * @param ttl time interval (in seconds) that the resource record may be
- * cached before it should be discarded. Zero values are
- * interpreted to mean that the RR can only be used for the
- * transaction in progress, and should not be cached.
- * @param address Instance of {@link InetAddress}
- * @return A record if the {@code address} is an IPv4 address, or AAAA record if the
- * {@code address} is an IPv6 address.
- */
- public static DnsRecord makeAOrAAAARecord(int rType, @NonNull String dName,
- int nsClass, long ttl, @NonNull InetAddress address) throws IOException {
- final int nsType = (address.getAddress().length == 4) ? TYPE_A : TYPE_AAAA;
- return new DnsRecord(rType, dName, nsType, nsClass, ttl, address, null /* rDataStr */);
- }
-
- /**
- * Make an CNAME record based on the specified parameters.
- *
- * @param rType Type of the record, can be {@link #ANSECTION}, {@link #ARSECTION}
- * or {@link #NSSECTION}.
- * @param dName Domain name of the record.
- * @param nsClass Class of the record. See RFC 1035 section 3.2.4.
- * @param ttl time interval (in seconds) that the resource record may be
- * cached before it should be discarded. Zero values are
- * interpreted to mean that the RR can only be used for the
- * transaction in progress, and should not be cached.
- * @param domainName Canonical name of the {@code dName}.
- * @return A record if the {@code address} is an IPv4 address, or AAAA record if the
- * {@code address} is an IPv6 address.
- */
- public static DnsRecord makeCNameRecord(int rType, @NonNull String dName, int nsClass,
- long ttl, @NonNull String domainName) throws IOException {
- return new DnsRecord(rType, dName, TYPE_CNAME, nsClass, ttl, null /* address */,
- domainName);
- }
-
- /**
- * Make a DNS question based on the specified parameters.
- */
- public static DnsRecord makeQuestion(@NonNull String dName, int nsType, int nsClass) {
- return new DnsRecord(dName, nsType, nsClass);
- }
-
- private static String requireHostName(@NonNull String name) {
- if (!DnsRecordParser.isHostName(name)) {
- throw new IllegalArgumentException("Expected domain name but got " + name);
- }
- return name;
- }
-
- /**
- * Create a new query DnsRecord from specified parameters, useful when synthesizing
- * dns response.
- */
- private DnsRecord(@NonNull String dName, int nsType, int nsClass) {
- this.rType = QDSECTION;
- this.dName = requireHostName(dName);
- this.nsType = nsType;
- this.nsClass = nsClass;
- mRdata = null;
- this.ttl = 0;
- }
-
- /**
- * Create a new CNAME/A/AAAA DnsRecord from specified parameters.
- *
- * @param address The address only used when synthesizing A or AAAA record.
- * @param rDataStr The alias of the domain, only used when synthesizing CNAME record.
- */
- private DnsRecord(@RecordType int rType, @NonNull String dName, int nsType, int nsClass,
- long ttl, @Nullable InetAddress address, @Nullable String rDataStr)
- throws IOException {
- this.rType = rType;
- this.dName = requireHostName(dName);
- this.nsType = nsType;
- this.nsClass = nsClass;
- if (rType < 0 || rType >= NUM_SECTIONS || rType == QDSECTION) {
- throw new IllegalArgumentException("Unexpected record type: " + rType);
- }
- mRdata = nsType == TYPE_CNAME ? domainNameToLabels(rDataStr) : address.getAddress();
- this.ttl = ttl;
- }
-
- /**
* Get a copy of rdata.
*/
@Nullable
@@ -398,84 +159,13 @@
return (mRdata == null) ? null : mRdata.clone();
}
- /**
- * Get DnsRecord as byte array.
- */
- @NonNull
- public byte[] getBytes() throws IOException {
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- final DataOutputStream dos = new DataOutputStream(baos);
- dos.write(domainNameToLabels(dName));
- dos.writeShort(nsType);
- dos.writeShort(nsClass);
- if (rType != QDSECTION) {
- dos.writeInt((int) ttl);
- if (mRdata == null) {
- dos.writeShort(0);
- } else {
- dos.writeShort(mRdata.length);
- dos.write(mRdata);
- }
- }
- return baos.toByteArray();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o.getClass() != getClass()) return false;
- final DnsRecord other = (DnsRecord) o;
- return rType == other.rType
- && nsType == other.nsType
- && nsClass == other.nsClass
- && ttl == other.ttl
- && TextUtils.equals(dName, other.dName)
- && Arrays.equals(mRdata, other.mRdata);
- }
-
- @Override
- public int hashCode() {
- return 31 * Objects.hash(dName)
- + 37 * ((int) (ttl & 0xFFFFFFFF))
- + 41 * ((int) (ttl >> 32))
- + 43 * nsType
- + 47 * nsClass
- + 53 * rType
- + Arrays.hashCode(mRdata);
- }
-
- @Override
- public String toString() {
- return "DnsRecord{"
- + "rType=" + rType
- + ", dName='" + dName + '\''
- + ", nsType=" + nsType
- + ", nsClass=" + nsClass
- + ", ttl=" + ttl
- + ", mRdata=" + Arrays.toString(mRdata)
- + '}';
- }
}
- /**
- * Header section types, refer to RFC 1035 section 4.1.1.
- */
public static final int QDSECTION = 0;
public static final int ANSECTION = 1;
public static final int NSSECTION = 2;
public static final int ARSECTION = 3;
- @VisibleForTesting(visibility = PRIVATE)
- static final int NUM_SECTIONS = ARSECTION + 1;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- QDSECTION,
- ANSECTION,
- NSSECTION,
- ARSECTION,
- })
- public @interface RecordType {}
-
+ private static final int NUM_SECTIONS = ARSECTION + 1;
private static final String TAG = DnsPacket.class.getSimpleName();
@@ -499,7 +189,9 @@
for (int i = 0; i < NUM_SECTIONS; ++i) {
final int count = mHeader.getRecordCount(i);
- mRecords[i] = new ArrayList(count);
+ if (count > 0) {
+ mRecords[i] = new ArrayList(count);
+ }
for (int j = 0; j < count; ++j) {
try {
mRecords[i].add(new DnsRecord(i, buffer));
@@ -509,61 +201,4 @@
}
}
}
-
- /**
- * Create a new {@link #DnsPacket} from specified parameters.
- *
- * Note that authority records section and additional records section is not supported.
- */
- protected DnsPacket(@NonNull DnsHeader header, @NonNull List<DnsRecord> qd,
- @NonNull List<DnsRecord> an) {
- mHeader = Objects.requireNonNull(header);
- mRecords = new List[NUM_SECTIONS];
- mRecords[QDSECTION] = Collections.unmodifiableList(new ArrayList<>(qd));
- mRecords[ANSECTION] = Collections.unmodifiableList(new ArrayList<>(an));
- mRecords[NSSECTION] = new ArrayList<>();
- mRecords[ARSECTION] = new ArrayList<>();
- for (int i = 0; i < NUM_SECTIONS; i++) {
- if (mHeader.mRecordCount[i] != mRecords[i].size()) {
- throw new IllegalArgumentException("Record count mismatch: expected "
- + mHeader.mRecordCount[i] + " but was " + mRecords[i]);
- }
- }
- }
-
- /**
- * Get DnsPacket as byte array.
- */
- public @NonNull byte[] getBytes() throws IOException {
- final ByteArrayOutputStream buf = new ByteArrayOutputStream();
- buf.write(mHeader.getBytes());
-
- for (int i = 0; i < NUM_SECTIONS; ++i) {
- for (final DnsRecord record : mRecords[i]) {
- buf.write(record.getBytes());
- }
- }
- return buf.toByteArray();
- }
-
- @Override
- public String toString() {
- return "DnsPacket{" + "header=" + mHeader + ", records='" + Arrays.toString(mRecords) + '}';
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o.getClass() != getClass()) return false;
- final DnsPacket other = (DnsPacket) o;
- return Objects.equals(mHeader, other.mHeader)
- && Arrays.deepEquals(mRecords, other.mRecords);
- }
-
- @Override
- public int hashCode() {
- int result = Objects.hash(mHeader);
- result = 31 * result + Arrays.hashCode(mRecords);
- return result;
- }
}
diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java
index c47bfa0..3448cad 100644
--- a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java
@@ -20,19 +20,10 @@
import static com.android.net.module.util.DnsPacket.DnsRecord.NAME_NORMAL;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.InetAddresses;
-import android.net.ParseException;
import android.text.TextUtils;
-import android.util.Patterns;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.FieldPosition;
@@ -47,7 +38,6 @@
*/
public static class DnsRecordParser {
private static final int MAXLABELSIZE = 63;
- private static final int MAXNAMESIZE = 255;
private static final int MAXLABELCOUNT = 128;
private static final DecimalFormat sByteFormat = new DecimalFormat();
@@ -58,8 +48,7 @@
*
* <p>Follows the same conversion rules of the native code (ns_name.c in libc).
*/
- @VisibleForTesting
- static String labelToString(@NonNull byte[] label) {
+ private static String labelToString(@NonNull byte[] label) {
final StringBuffer sb = new StringBuffer();
for (int i = 0; i < label.length; ++i) {
@@ -83,52 +72,6 @@
}
/**
- * Converts domain name to labels according to RFC 1035.
- *
- * @param name Domain name as String that needs to be converted to labels.
- * @return An encoded byte array that is constructed out of labels,
- * and ends with zero-length label.
- * @throws ParseException if failed to parse the given domain name or
- * IOException if failed to output labels.
- */
- public static @NonNull byte[] domainNameToLabels(@NonNull String name) throws
- IOException, ParseException {
- if (name.length() > MAXNAMESIZE) {
- throw new ParseException("Domain name exceeds max length: " + name.length());
- }
- if (!isHostName(name)) {
- throw new ParseException("Failed to parse domain name: " + name);
- }
- final ByteArrayOutputStream buf = new ByteArrayOutputStream();
- final String[] labels = name.split("\\.");
- for (final String label : labels) {
- if (label.length() > MAXLABELSIZE) {
- throw new ParseException("label is too long: " + label);
- }
- buf.write(label.length());
- // Encode as UTF-8 as suggested in RFC 6055 section 3.
- buf.write(label.getBytes(StandardCharsets.UTF_8));
- }
- buf.write(0x00); // end with zero-length label
- return buf.toByteArray();
- }
-
- /**
- * Check whether the input is a valid hostname based on rfc 1035 section 3.3.
- *
- * @param hostName the target host name.
- * @return true if the input is a valid hostname.
- */
- public static boolean isHostName(@Nullable String hostName) {
- // TODO: Use {@code Patterns.HOST_NAME} if available.
- // Patterns.DOMAIN_NAME accepts host names or IP addresses, so reject
- // IP addresses.
- return hostName != null
- && Patterns.DOMAIN_NAME.matcher(hostName).matches()
- && !InetAddresses.isNumericAddress(hostName);
- }
-
- /**
* Parses the domain / target name of a DNS record.
*
* As described in RFC 1035 Section 4.1.3, the NAME field of a DNS Resource Record always
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java
index 409c1eb..1bbba08 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java
@@ -16,45 +16,26 @@
package com.android.net.module.util;
-import static android.net.DnsResolver.CLASS_IN;
-import static android.net.DnsResolver.TYPE_A;
-import static android.net.DnsResolver.TYPE_AAAA;
-
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import libcore.net.InetAddressUtils;
-
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.IOException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DnsPacketTest {
- private static final int TEST_DNS_PACKET_ID = 0x7722;
- private static final int TEST_DNS_PACKET_FLAGS = 0x8180;
-
private void assertHeaderParses(DnsPacket.DnsHeader header, int id, int flag,
int qCount, int aCount, int nsCount, int arCount) {
- assertEquals(header.getId(), id);
- assertEquals(header.getFlags(), flag);
+ assertEquals(header.id, id);
+ assertEquals(header.flags, flag);
assertEquals(header.getRecordCount(DnsPacket.QDSECTION), qCount);
assertEquals(header.getRecordCount(DnsPacket.ANSECTION), aCount);
assertEquals(header.getRecordCount(DnsPacket.NSSECTION), nsCount);
@@ -70,16 +51,11 @@
assertTrue(Arrays.equals(record.getRR(), rr));
}
- static class TestDnsPacket extends DnsPacket {
+ class TestDnsPacket extends DnsPacket {
TestDnsPacket(byte[] data) throws DnsPacket.ParseException {
super(data);
}
- TestDnsPacket(@NonNull DnsHeader header, @Nullable ArrayList<DnsRecord> qd,
- @Nullable ArrayList<DnsRecord> an) {
- super(header, qd, an);
- }
-
public DnsHeader getHeader() {
return mHeader;
}
@@ -180,247 +156,4 @@
new byte[]{ 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 });
}
-
- /** Verifies that the synthesized {@link DnsPacket.DnsHeader} can be parsed correctly. */
- @Test
- public void testDnsHeaderSynthesize() {
- final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID,
- TEST_DNS_PACKET_FLAGS, 3 /* qcount */, 5 /* ancount */);
- final DnsPacket.DnsHeader actualHeader = new DnsPacket.DnsHeader(
- ByteBuffer.wrap(testHeader.getBytes()));
- assertEquals(testHeader, actualHeader);
- }
-
- /** Verifies that the synthesized {@link DnsPacket.DnsRecord} can be parsed correctly. */
- @Test
- public void testDnsRecordSynthesize() throws IOException {
- assertDnsRecordRoundTrip(
- DnsPacket.DnsRecord.makeAOrAAAARecord(DnsPacket.ANSECTION,
- "test.com", CLASS_IN, 5 /* ttl */,
- InetAddressUtils.parseNumericAddress("abcd::fedc")));
- assertDnsRecordRoundTrip(DnsPacket.DnsRecord.makeQuestion("test.com", TYPE_AAAA, CLASS_IN));
- assertDnsRecordRoundTrip(DnsPacket.DnsRecord.makeCNameRecord(DnsPacket.ANSECTION,
- "test.com", CLASS_IN, 0 /* ttl */, "example.com"));
- }
-
- /**
- * Verifies ttl/rData error handling when parsing
- * {@link DnsPacket.DnsRecord} from bytes.
- */
- @Test
- public void testDnsRecordTTLRDataErrorHandling() throws IOException {
- // Verify the constructor ignore ttl/rData of questions even if they are supplied.
- final byte[] qdWithTTLRData = new byte[]{
- 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
- 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
- 0x00, 0x00, /* Type */
- 0x00, 0x01, /* Class */
- 0x00, 0x00, 0x01, 0x2b, /* TTL */
- 0x00, 0x04, /* Data length */
- (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */};
- final DnsPacket.DnsRecord questionsFromBytes =
- new DnsPacket.DnsRecord(DnsPacket.QDSECTION, ByteBuffer.wrap(qdWithTTLRData));
- assertEquals(0, questionsFromBytes.ttl);
- assertNull(questionsFromBytes.getRR());
-
- // Verify ANSECTION must have rData when constructing.
- final byte[] anWithoutTTLRData = new byte[]{
- 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
- 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
- 0x00, 0x01, /* Type */
- 0x00, 0x01, /* Class */};
- assertThrows(BufferUnderflowException.class, () ->
- new DnsPacket.DnsRecord(DnsPacket.ANSECTION, ByteBuffer.wrap(anWithoutTTLRData)));
- }
-
- private void assertDnsRecordRoundTrip(DnsPacket.DnsRecord before)
- throws IOException {
- final DnsPacket.DnsRecord after = new DnsPacket.DnsRecord(before.rType,
- ByteBuffer.wrap(before.getBytes()));
- assertEquals(after, before);
- }
-
- /** Verifies that the synthesized {@link DnsPacket} can be parsed correctly. */
- @Test
- public void testDnsPacketSynthesize() throws IOException {
- // Ipv4 dns response packet generated by scapy:
- // dns_r = scapy.DNS(
- // id=0xbeef,
- // qr=1,
- // qd=scapy.DNSQR(qname="hello.example.com"),
- // an=scapy.DNSRR(rrname="hello.example.com", type="CNAME", rdata='test.com') /
- // scapy.DNSRR(rrname="hello.example.com", rdata='1.2.3.4'))
- // scapy.hexdump(dns_r)
- // dns_r.show2()
- // Note that since the synthesizing does not support name compression yet, the domain
- // name of the sample need to be uncompressed when generating.
- final byte[] v4BlobUncompressed = new byte[]{
- /* Header */
- (byte) 0xbe, (byte) 0xef, /* Transaction ID */
- (byte) 0x81, 0x00, /* Flags */
- 0x00, 0x01, /* Questions */
- 0x00, 0x02, /* Answer RRs */
- 0x00, 0x00, /* Authority RRs */
- 0x00, 0x00, /* Additional RRs */
- /* Queries */
- 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61,
- 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */
- 0x00, 0x01, /* Type */
- 0x00, 0x01, /* Class */
- /* Answers */
- 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61,
- 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */
- 0x00, 0x05, /* Type */
- 0x00, 0x01, /* Class */
- 0x00, 0x00, 0x00, 0x00, /* TTL */
- 0x00, 0x0A, /* Data length */
- 0x04, 0x74, 0x65, 0x73, 0x74, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Alias: test.com */
- 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61,
- 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */
- 0x00, 0x01, /* Type */
- 0x00, 0x01, /* Class */
- 0x00, 0x00, 0x00, 0x00, /* TTL */
- 0x00, 0x04, /* Data length */
- 0x01, 0x02, 0x03, 0x04, /* Address: 1.2.3.4 */
- };
-
- // Forge one via constructors.
- final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(0xbeef,
- 0x8100, 1 /* qcount */, 2 /* ancount */);
- final ArrayList<DnsPacket.DnsRecord> qlist = new ArrayList<>();
- final ArrayList<DnsPacket.DnsRecord> alist = new ArrayList<>();
- qlist.add(DnsPacket.DnsRecord.makeQuestion(
- "hello.example.com", TYPE_A, CLASS_IN));
- alist.add(DnsPacket.DnsRecord.makeCNameRecord(
- DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, "test.com"));
- alist.add(DnsPacket.DnsRecord.makeAOrAAAARecord(
- DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */,
- InetAddressUtils.parseNumericAddress("1.2.3.4")));
- final TestDnsPacket testPacket = new TestDnsPacket(testHeader, qlist, alist);
-
- // Assert content equals in both ways.
- assertTrue(Arrays.equals(v4BlobUncompressed, testPacket.getBytes()));
- assertEquals(new TestDnsPacket(v4BlobUncompressed), testPacket);
- }
-
- @Test
- public void testDnsPacketSynthesize_recordCountMismatch() throws IOException {
- final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(0xbeef,
- 0x8100, 1 /* qcount */, 1 /* ancount */);
- final ArrayList<DnsPacket.DnsRecord> qlist = new ArrayList<>();
- final ArrayList<DnsPacket.DnsRecord> alist = new ArrayList<>();
- qlist.add(DnsPacket.DnsRecord.makeQuestion(
- "hello.example.com", TYPE_A, CLASS_IN));
-
- // Assert throws if the supplied answer records fewer than the declared count.
- assertThrows(IllegalArgumentException.class, () ->
- new TestDnsPacket(testHeader, qlist, alist));
-
- // Assert throws if the supplied answer records more than the declared count.
- alist.add(DnsPacket.DnsRecord.makeCNameRecord(
- DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, "test.com"));
- alist.add(DnsPacket.DnsRecord.makeAOrAAAARecord(
- DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */,
- InetAddressUtils.parseNumericAddress("1.2.3.4")));
- assertThrows(IllegalArgumentException.class, () ->
- new TestDnsPacket(testHeader, qlist, alist));
-
- // Assert counts matched if the byte buffer still has data when parsing ended.
- final byte[] blobTooMuchData = new byte[]{
- /* Header */
- (byte) 0xbe, (byte) 0xef, /* Transaction ID */
- (byte) 0x81, 0x00, /* Flags */
- 0x00, 0x00, /* Questions */
- 0x00, 0x00, /* Answer RRs */
- 0x00, 0x00, /* Authority RRs */
- 0x00, 0x00, /* Additional RRs */
- /* Queries */
- 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61,
- 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */
- 0x00, 0x01, /* Type */
- 0x00, 0x01, /* Class */
- };
- final TestDnsPacket packetFromTooMuchData = new TestDnsPacket(blobTooMuchData);
- for (int i = 0; i < DnsPacket.NUM_SECTIONS; i++) {
- assertEquals(0, packetFromTooMuchData.getRecordList(i).size());
- assertEquals(0, packetFromTooMuchData.getHeader().getRecordCount(i));
- }
-
- // Assert throws if the byte buffer ended when expecting more records.
- final byte[] blobNotEnoughData = new byte[]{
- /* Header */
- (byte) 0xbe, (byte) 0xef, /* Transaction ID */
- (byte) 0x81, 0x00, /* Flags */
- 0x00, 0x01, /* Questions */
- 0x00, 0x02, /* Answer RRs */
- 0x00, 0x00, /* Authority RRs */
- 0x00, 0x00, /* Additional RRs */
- /* Queries */
- 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61,
- 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */
- 0x00, 0x01, /* Type */
- 0x00, 0x01, /* Class */
- /* Answers */
- 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61,
- 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */
- 0x00, 0x01, /* Type */
- 0x00, 0x01, /* Class */
- 0x00, 0x00, 0x00, 0x00, /* TTL */
- 0x00, 0x04, /* Data length */
- 0x01, 0x02, 0x03, 0x04, /* Address */
- };
- assertThrows(DnsPacket.ParseException.class, () -> new TestDnsPacket(blobNotEnoughData));
- }
-
- @Test
- public void testEqualsAndHashCode() throws IOException {
- // Verify DnsHeader equals and hashCode.
- final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID,
- TEST_DNS_PACKET_FLAGS, 1 /* qcount */, 1 /* ancount */);
- final DnsPacket.DnsHeader emptyHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID + 1,
- TEST_DNS_PACKET_FLAGS + 0x08, 0 /* qcount */, 0 /* ancount */);
- final DnsPacket.DnsHeader headerFromBytes =
- new DnsPacket.DnsHeader(ByteBuffer.wrap(testHeader.getBytes()));
- assertEquals(testHeader, headerFromBytes);
- assertEquals(testHeader.hashCode(), headerFromBytes.hashCode());
- assertNotEquals(testHeader, emptyHeader);
- assertNotEquals(testHeader.hashCode(), emptyHeader.hashCode());
- assertNotEquals(headerFromBytes, emptyHeader);
- assertNotEquals(headerFromBytes.hashCode(), emptyHeader.hashCode());
-
- // Verify DnsRecord equals and hashCode.
- final DnsPacket.DnsRecord testQuestion = DnsPacket.DnsRecord.makeQuestion(
- "test.com", TYPE_AAAA, CLASS_IN);
- final DnsPacket.DnsRecord testAnswer = DnsPacket.DnsRecord.makeCNameRecord(
- DnsPacket.ANSECTION, "test.com", CLASS_IN, 9, "www.test.com");
- final DnsPacket.DnsRecord questionFromBytes = new DnsPacket.DnsRecord(DnsPacket.QDSECTION,
- ByteBuffer.wrap(testQuestion.getBytes()));
- assertEquals(testQuestion, questionFromBytes);
- assertEquals(testQuestion.hashCode(), questionFromBytes.hashCode());
- assertNotEquals(testQuestion, testAnswer);
- assertNotEquals(testQuestion.hashCode(), testAnswer.hashCode());
- assertNotEquals(questionFromBytes, testAnswer);
- assertNotEquals(questionFromBytes.hashCode(), testAnswer.hashCode());
-
- // Verify DnsPacket equals and hashCode.
- final ArrayList<DnsPacket.DnsRecord> qlist = new ArrayList<>();
- final ArrayList<DnsPacket.DnsRecord> alist = new ArrayList<>();
- qlist.add(testQuestion);
- alist.add(testAnswer);
- final TestDnsPacket testPacket = new TestDnsPacket(testHeader, qlist, alist);
- final TestDnsPacket emptyPacket = new TestDnsPacket(
- emptyHeader, new ArrayList<>(), new ArrayList<>());
- final TestDnsPacket packetFromBytes = new TestDnsPacket(testPacket.getBytes());
- assertEquals(testPacket, packetFromBytes);
- assertEquals(testPacket.hashCode(), packetFromBytes.hashCode());
- assertNotEquals(testPacket, emptyPacket);
- assertNotEquals(testPacket.hashCode(), emptyPacket.hashCode());
- assertNotEquals(packetFromBytes, emptyPacket);
- assertNotEquals(packetFromBytes.hashCode(), emptyPacket.hashCode());
-
- // Verify DnsPacket with empty list.
- final TestDnsPacket emptyPacketFromBytes = new TestDnsPacket(emptyPacket.getBytes());
- assertEquals(emptyPacket, emptyPacketFromBytes);
- assertEquals(emptyPacket.hashCode(), emptyPacketFromBytes.hashCode());
- }
}
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java
index 9e1ab82..48777ac 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java
@@ -18,20 +18,12 @@
import static com.android.net.module.util.DnsPacketUtils.DnsRecordParser;
-import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
-import android.net.ParseException;
-import android.os.Build;
-
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.testutils.DevSdkIgnoreRule;
-
-import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,8 +32,6 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DnsPacketUtilsTest {
- @Rule
- public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
/**
* Verifies that the compressed NAME field in the answer section of the DNS message is parsed
@@ -126,31 +116,4 @@
notNameCompressedBuf, /* depth= */ 0, /* isNameCompressionSupported= */ false);
assertEquals(domainName, "www.google.com");
}
-
- // Skip test on R- devices since ParseException only available on S+ devices.
- @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
- @Test
- public void testDomainNameToLabels() throws Exception {
- assertArrayEquals(
- new byte[]{3, 'w', 'w', 'w', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm', 0},
- DnsRecordParser.domainNameToLabels("www.google.com"));
- assertThrows(ParseException.class, () ->
- DnsRecordParser.domainNameToLabels("aaa."));
- assertThrows(ParseException.class, () ->
- DnsRecordParser.domainNameToLabels("aaa"));
- assertThrows(ParseException.class, () ->
- DnsRecordParser.domainNameToLabels("."));
- assertThrows(ParseException.class, () ->
- DnsRecordParser.domainNameToLabels(""));
- }
-
- @Test
- public void testIsHostName() {
- Assert.assertTrue(DnsRecordParser.isHostName("www.google.com"));
- Assert.assertFalse(DnsRecordParser.isHostName("com"));
- Assert.assertFalse(DnsRecordParser.isHostName("1.2.3.4"));
- Assert.assertFalse(DnsRecordParser.isHostName("1234::5678"));
- Assert.assertFalse(DnsRecordParser.isHostName(null));
- Assert.assertFalse(DnsRecordParser.isHostName(""));
- }
}