Support RFC 7858 DNS over TLS
This change adds the core capability for DNS over TLS, and creates
private APIs for activating it, but does not provide any way to
activate the functionality in a development environment or on a
real device.
Based on https://android-review.googlesource.com/#/c/373776/
Test: Complete unit+integration tests. Manual tests look good.
Bug: 34953048
Change-Id: Ib99ac1f631fd2c2c8fbf53bdb05f67f8be7713ac
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index 65de0c3..41fc8c3 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -32,6 +32,7 @@
#include <netinet/in.h>
#include <linux/if.h>
#include <linux/if_tun.h>
+#include <openssl/base64.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
@@ -605,3 +606,90 @@
}
}
}
+
+static std::string base64Encode(const std::vector<uint8_t>& input) {
+ size_t out_len;
+ EXPECT_EQ(1, EVP_EncodedLength(&out_len, input.size()));
+ // out_len includes the trailing NULL.
+ uint8_t output_bytes[out_len];
+ EXPECT_EQ(out_len - 1, EVP_EncodeBlock(output_bytes, input.data(), input.size()));
+ return std::string(reinterpret_cast<char*>(output_bytes));
+}
+
+TEST_F(BinderTest, TestAddPrivateDnsServer) {
+ std::vector<uint8_t> fp(SHA256_SIZE);
+ static const struct TestData {
+ const std::string address;
+ const int port;
+ const std::string fingerprintAlgorithm;
+ const std::set<std::vector<uint8_t>> fingerprints;
+ const int expectedReturnCode;
+ } kTestData[] = {
+ { "192.0.2.1", 853, "", {}, INetd::PRIVATE_DNS_SUCCESS },
+ { "2001:db8::2", 65535, "", {}, INetd::PRIVATE_DNS_SUCCESS },
+ { "192.0.2.3", 443, "SHA-256", { fp }, INetd::PRIVATE_DNS_SUCCESS },
+ { "2001:db8::4", 1, "SHA-256", { fp }, INetd::PRIVATE_DNS_SUCCESS },
+ { "192.0.*.5", 853, "", {}, INetd::PRIVATE_DNS_BAD_ADDRESS },
+ { "", 853, "", {}, INetd::PRIVATE_DNS_BAD_ADDRESS },
+ { "2001:dg8::6", 65535, "", {}, INetd::PRIVATE_DNS_BAD_ADDRESS },
+ { "192.0.2.7", 0, "SHA-256", { fp }, INetd::PRIVATE_DNS_BAD_PORT },
+ { "2001:db8::8", 65536, "", {}, INetd::PRIVATE_DNS_BAD_PORT },
+ { "192.0.2.9", 50053, "SHA-512", { fp }, INetd::PRIVATE_DNS_UNKNOWN_ALGORITHM },
+ { "2001:db8::a", 853, "", { fp }, INetd::PRIVATE_DNS_BAD_FINGERPRINT },
+ { "192.0.2.11", 853, "SHA-256", {}, INetd::PRIVATE_DNS_BAD_FINGERPRINT },
+ { "2001:db8::c", 853, "SHA-256", { { 1 } }, INetd::PRIVATE_DNS_BAD_FINGERPRINT },
+ { "192.0.2.12", 853, "SHA-256", { std::vector<uint8_t>(SHA256_SIZE + 1) },
+ INetd::PRIVATE_DNS_BAD_FINGERPRINT },
+ { "2001:db8::e", 1, "SHA-256", { fp, fp, fp }, INetd::PRIVATE_DNS_SUCCESS },
+ { "192.0.2.14", 853, "SHA-256", { fp, { 1 } }, INetd::PRIVATE_DNS_BAD_FINGERPRINT },
+ };
+
+ for (unsigned int i = 0; i < arraysize(kTestData); i++) {
+ const auto &td = kTestData[i];
+
+ std::vector<std::string> fingerprints;
+ for (const std::vector<uint8_t>& fingerprint : td.fingerprints) {
+ fingerprints.push_back(base64Encode(fingerprint));
+ }
+ const binder::Status status = mNetd->addPrivateDnsServer(
+ td.address, td.port, td.fingerprintAlgorithm, fingerprints);
+
+ if (td.expectedReturnCode == INetd::PRIVATE_DNS_SUCCESS) {
+ SCOPED_TRACE(String8::format("test case %d should have passed", i));
+ SCOPED_TRACE(status.toString8());
+ EXPECT_EQ(0, status.exceptionCode());
+ } else {
+ SCOPED_TRACE(String8::format("test case %d should have failed", i));
+ EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, status.exceptionCode());
+ }
+ EXPECT_EQ(td.expectedReturnCode, status.serviceSpecificErrorCode());
+ }
+}
+
+TEST_F(BinderTest, TestRemovePrivateDnsServer) {
+ static const struct TestData {
+ const std::string address;
+ const int expectedReturnCode;
+ } kTestData[] = {
+ { "192.0.2.1", INetd::PRIVATE_DNS_SUCCESS },
+ { "2001:db8::2", INetd::PRIVATE_DNS_SUCCESS },
+ { "192.0.*.3", INetd::PRIVATE_DNS_BAD_ADDRESS },
+ { "2001:dg8::4", INetd::PRIVATE_DNS_BAD_ADDRESS },
+ { "", INetd::PRIVATE_DNS_BAD_ADDRESS },
+ };
+
+ for (unsigned int i = 0; i < arraysize(kTestData); i++) {
+ const auto &td = kTestData[i];
+
+ const binder::Status status = mNetd->removePrivateDnsServer(td.address);
+
+ if (td.expectedReturnCode == INetd::PRIVATE_DNS_SUCCESS) {
+ SCOPED_TRACE(String8::format("test case %d should have passed", i));
+ EXPECT_EQ(0, status.exceptionCode());
+ } else {
+ SCOPED_TRACE(String8::format("test case %d should have failed", i));
+ EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, status.exceptionCode());
+ }
+ EXPECT_EQ(td.expectedReturnCode, status.serviceSpecificErrorCode());
+ }
+}