summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/net/DnsPacket.java235
-rw-r--r--core/java/android/net/DnsResolver.java15
-rw-r--r--packages/Tethering/jarjar-rules.txt3
-rw-r--r--tests/net/java/android/net/DnsPacketTest.java159
4 files changed, 15 insertions, 397 deletions
diff --git a/core/java/android/net/DnsPacket.java b/core/java/android/net/DnsPacket.java
deleted file mode 100644
index 83e57e0a047b..000000000000
--- a/core/java/android/net/DnsPacket.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.text.TextUtils;
-
-import com.android.internal.util.BitUtils;
-
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.text.DecimalFormat;
-import java.text.FieldPosition;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Defines basic data for DNS protocol based on RFC 1035.
- * Subclasses create the specific format used in DNS packet.
- *
- * @hide
- */
-public abstract class DnsPacket {
- public class DnsHeader {
- private static final String TAG = "DnsHeader";
- public final int id;
- public final int flags;
- public final int rcode;
- private final int[] mRecordCount;
-
- /**
- * Create a new DnsHeader from a positioned ByteBuffer.
- *
- * The ByteBuffer must be in network byte order (which is the default).
- * Reads the passed ByteBuffer from its current position and decodes a DNS header.
- * When this constructor returns, the reading position of the ByteBuffer has been
- * advanced to the end of the DNS header record.
- * This is meant to chain with other methods reading a DNS response in sequence.
- */
- DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException {
- id = BitUtils.uint16(buf.getShort());
- flags = BitUtils.uint16(buf.getShort());
- rcode = flags & 0xF;
- mRecordCount = new int[NUM_SECTIONS];
- for (int i = 0; i < NUM_SECTIONS; ++i) {
- mRecordCount[i] = BitUtils.uint16(buf.getShort());
- }
- }
-
- /**
- * Get record count by type.
- */
- public int getRecordCount(int type) {
- return mRecordCount[type];
- }
- }
-
- /**
- * Superclass for DNS questions and DNS resource records.
- *
- * DNS questions (No TTL/RDATA)
- * DNS resource records (With TTL/RDATA)
- */
- public class DnsRecord {
- private static final int MAXNAMESIZE = 255;
- private static final int MAXLABELSIZE = 63;
- private static final int MAXLABELCOUNT = 128;
- private static final int NAME_NORMAL = 0;
- private static final int NAME_COMPRESSION = 0xC0;
- private final DecimalFormat byteFormat = new DecimalFormat();
- private final FieldPosition pos = new FieldPosition(0);
-
- private static final String TAG = "DnsRecord";
-
- public final String dName;
- public final int nsType;
- public final int nsClass;
- public final long ttl;
- private final byte[] mRdata;
-
- /**
- * 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 header record.
- * This is meant to chain with other methods reading a DNS response in sequence.
- *
- * @param ByteBuffer input of record, must be in network byte order
- * (which is the default).
- */
- DnsRecord(int recordType, @NonNull ByteBuffer buf)
- throws BufferUnderflowException, ParseException {
- dName = parseName(buf, 0 /* Parse depth */);
- if (dName.length() > MAXNAMESIZE) {
- throw new ParseException(
- "Parse name fail, name size is too long: " + dName.length());
- }
- nsType = BitUtils.uint16(buf.getShort());
- nsClass = BitUtils.uint16(buf.getShort());
-
- if (recordType != QDSECTION) {
- ttl = BitUtils.uint32(buf.getInt());
- final int length = BitUtils.uint16(buf.getShort());
- mRdata = new byte[length];
- buf.get(mRdata);
- } else {
- ttl = 0;
- mRdata = null;
- }
- }
-
- /**
- * Get a copy of rdata.
- */
- @Nullable
- public byte[] getRR() {
- return (mRdata == null) ? null : mRdata.clone();
- }
-
- /**
- * Convert label from {@code byte[]} to {@code String}
- *
- * Follows the same conversion rules of the native code (ns_name.c in libc)
- */
- private String labelToString(@NonNull byte[] label) {
- final StringBuffer sb = new StringBuffer();
- for (int i = 0; i < label.length; ++i) {
- int b = BitUtils.uint8(label[i]);
- // Control characters and non-ASCII characters.
- if (b <= 0x20 || b >= 0x7f) {
- // Append the byte as an escaped decimal number, e.g., "\19" for 0x13.
- sb.append('\\');
- byteFormat.format(b, sb, pos);
- } else if (b == '"' || b == '.' || b == ';' || b == '\\'
- || b == '(' || b == ')' || b == '@' || b == '$') {
- // Append the byte as an escaped character, e.g., "\:" for 0x3a.
- sb.append('\\');
- sb.append((char) b);
- } else {
- // Append the byte as a character, e.g., "a" for 0x61.
- sb.append((char) b);
- }
- }
- return sb.toString();
- }
-
- private String parseName(@NonNull ByteBuffer buf, int depth) throws
- BufferUnderflowException, ParseException {
- if (depth > MAXLABELCOUNT) {
- throw new ParseException("Failed to parse name, too many labels");
- }
- final int len = BitUtils.uint8(buf.get());
- final int mask = len & NAME_COMPRESSION;
- if (0 == len) {
- return "";
- } else if (mask != NAME_NORMAL && mask != NAME_COMPRESSION) {
- throw new ParseException("Parse name fail, bad label type");
- } else if (mask == NAME_COMPRESSION) {
- // Name compression based on RFC 1035 - 4.1.4 Message compression
- final int offset = ((len & ~NAME_COMPRESSION) << 8) + BitUtils.uint8(buf.get());
- final int oldPos = buf.position();
- if (offset >= oldPos - 2) {
- throw new ParseException("Parse compression name fail, invalid compression");
- }
- buf.position(offset);
- final String pointed = parseName(buf, depth + 1);
- buf.position(oldPos);
- return pointed;
- } else {
- final byte[] label = new byte[len];
- buf.get(label);
- final String head = labelToString(label);
- if (head.length() > MAXLABELSIZE) {
- throw new ParseException("Parse name fail, invalid label length");
- }
- final String tail = parseName(buf, depth + 1);
- return TextUtils.isEmpty(tail) ? head : head + "." + tail;
- }
- }
- }
-
- public static final int QDSECTION = 0;
- public static final int ANSECTION = 1;
- public static final int NSSECTION = 2;
- public static final int ARSECTION = 3;
- private static final int NUM_SECTIONS = ARSECTION + 1;
-
- private static final String TAG = DnsPacket.class.getSimpleName();
-
- protected final DnsHeader mHeader;
- protected final List<DnsRecord>[] mRecords;
-
- protected DnsPacket(@NonNull byte[] data) throws ParseException {
- if (null == data) throw new ParseException("Parse header failed, null input data");
- final ByteBuffer buffer;
- try {
- buffer = ByteBuffer.wrap(data);
- mHeader = new DnsHeader(buffer);
- } catch (BufferUnderflowException e) {
- throw new ParseException("Parse Header fail, bad input data", e);
- }
-
- mRecords = new ArrayList[NUM_SECTIONS];
-
- for (int i = 0; i < NUM_SECTIONS; ++i) {
- final int count = mHeader.getRecordCount(i);
- if (count > 0) {
- mRecords[i] = new ArrayList(count);
- }
- for (int j = 0; j < count; ++j) {
- try {
- mRecords[i].add(new DnsRecord(i, buffer));
- } catch (BufferUnderflowException e) {
- throw new ParseException("Parse record fail", e);
- }
- }
- }
- }
-}
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index 0b1a84534e38..3f7660f5709a 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -38,6 +38,8 @@ import android.os.MessageQueue;
import android.system.ErrnoException;
import android.util.Log;
+import com.android.net.module.util.DnsPacket;
+
import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -97,7 +99,7 @@ public final class DnsResolver {
@interface DnsError {}
/**
* Indicates that there was an error parsing the response the query.
- * The cause of this error is available via getCause() and is a ParseException.
+ * The cause of this error is available via getCause() and is a {@link ParseException}.
*/
public static final int ERROR_PARSE = 0;
/**
@@ -290,8 +292,15 @@ public final class DnsResolver {
}
try {
mAllAnswers.addAll(new DnsAddressAnswer(answer).getAddresses());
- } catch (ParseException e) {
- mDnsException = new DnsException(ERROR_PARSE, e);
+ } catch (DnsPacket.ParseException e) {
+ // Convert the com.android.net.module.util.DnsPacket.ParseException to an
+ // android.net.ParseException. This is the type that was used in Q and is implied
+ // by the public documentation of ERROR_PARSE.
+ //
+ // DnsPacket cannot throw android.net.ParseException directly because it's @hide.
+ ParseException pe = new ParseException(e.reason, e.getCause());
+ pe.setStackTrace(e.getStackTrace());
+ mDnsException = new DnsException(ERROR_PARSE, pe);
}
maybeReportAnswer();
}
diff --git a/packages/Tethering/jarjar-rules.txt b/packages/Tethering/jarjar-rules.txt
index e90a2ccaa2a3..8f072e4cd217 100644
--- a/packages/Tethering/jarjar-rules.txt
+++ b/packages/Tethering/jarjar-rules.txt
@@ -15,3 +15,6 @@ rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.t
rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1
rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1
+
+# Classes from net-utils-framework-common
+rule com.android.net.module.util.** com.android.networkstack.tethering.util.@1 \ No newline at end of file
diff --git a/tests/net/java/android/net/DnsPacketTest.java b/tests/net/java/android/net/DnsPacketTest.java
deleted file mode 100644
index 975abf416944..000000000000
--- a/tests/net/java/android/net/DnsPacketTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DnsPacketTest {
- private void assertHeaderParses(DnsPacket.DnsHeader header, int id, int flag,
- int qCount, int aCount, int nsCount, int arCount) {
- 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);
- assertEquals(header.getRecordCount(DnsPacket.ARSECTION), arCount);
- }
-
- private void assertRecordParses(DnsPacket.DnsRecord record, String dname,
- int dtype, int dclass, int ttl, byte[] rr) {
- assertEquals(record.dName, dname);
- assertEquals(record.nsType, dtype);
- assertEquals(record.nsClass, dclass);
- assertEquals(record.ttl, ttl);
- assertTrue(Arrays.equals(record.getRR(), rr));
- }
-
- class TestDnsPacket extends DnsPacket {
- TestDnsPacket(byte[] data) throws ParseException {
- super(data);
- }
-
- public DnsHeader getHeader() {
- return mHeader;
- }
- public List<DnsRecord> getRecordList(int secType) {
- return mRecords[secType];
- }
- }
-
- @Test
- public void testNullDisallowed() {
- try {
- new TestDnsPacket(null);
- fail("Exception not thrown for null byte array");
- } catch (ParseException e) {
- }
- }
-
- @Test
- public void testV4Answer() throws Exception {
- final byte[] v4blob = new byte[] {
- /* Header */
- 0x55, 0x66, /* Transaction ID */
- (byte) 0x81, (byte) 0x80, /* Flags */
- 0x00, 0x01, /* Questions */
- 0x00, 0x01, /* Answer RRs */
- 0x00, 0x00, /* Authority RRs */
- 0x00, 0x00, /* Additional RRs */
- /* Queries */
- 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
- 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
- 0x00, 0x01, /* Type */
- 0x00, 0x01, /* Class */
- /* Answers */
- (byte) 0xc0, 0x0c, /* Name */
- 0x00, 0x01, /* Type */
- 0x00, 0x01, /* Class */
- 0x00, 0x00, 0x01, 0x2b, /* TTL */
- 0x00, 0x04, /* Data length */
- (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */
- };
- TestDnsPacket packet = new TestDnsPacket(v4blob);
-
- // Header part
- assertHeaderParses(packet.getHeader(), 0x5566, 0x8180, 1, 1, 0, 0);
-
- // Record part
- List<DnsPacket.DnsRecord> qdRecordList =
- packet.getRecordList(DnsPacket.QDSECTION);
- assertEquals(qdRecordList.size(), 1);
- assertRecordParses(qdRecordList.get(0), "www.google.com", 1, 1, 0, null);
-
- List<DnsPacket.DnsRecord> anRecordList =
- packet.getRecordList(DnsPacket.ANSECTION);
- assertEquals(anRecordList.size(), 1);
- assertRecordParses(anRecordList.get(0), "www.google.com", 1, 1, 0x12b,
- new byte[]{ (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 });
- }
-
- @Test
- public void testV6Answer() throws Exception {
- final byte[] v6blob = new byte[] {
- /* Header */
- 0x77, 0x22, /* Transaction ID */
- (byte) 0x81, (byte) 0x80, /* Flags */
- 0x00, 0x01, /* Questions */
- 0x00, 0x01, /* Answer RRs */
- 0x00, 0x00, /* Authority RRs */
- 0x00, 0x00, /* Additional RRs */
- /* Queries */
- 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
- 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
- 0x00, 0x1c, /* Type */
- 0x00, 0x01, /* Class */
- /* Answers */
- (byte) 0xc0, 0x0c, /* Name */
- 0x00, 0x1c, /* Type */
- 0x00, 0x01, /* Class */
- 0x00, 0x00, 0x00, 0x37, /* TTL */
- 0x00, 0x10, /* Data length */
- 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 /* Address */
- };
- TestDnsPacket packet = new TestDnsPacket(v6blob);
-
- // Header part
- assertHeaderParses(packet.getHeader(), 0x7722, 0x8180, 1, 1, 0, 0);
-
- // Record part
- List<DnsPacket.DnsRecord> qdRecordList =
- packet.getRecordList(DnsPacket.QDSECTION);
- assertEquals(qdRecordList.size(), 1);
- assertRecordParses(qdRecordList.get(0), "www.google.com", 28, 1, 0, null);
-
- List<DnsPacket.DnsRecord> anRecordList =
- packet.getRecordList(DnsPacket.ANSECTION);
- assertEquals(anRecordList.size(), 1);
- assertRecordParses(anRecordList.get(0), "www.google.com", 28, 1, 0x37,
- new byte[]{ 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 });
- }
-}