Do DNS64 prefix discovery in netd
Test: as follows
- built, flashed, booted
- system/netd/tests/runtests.sh passes
- dumpsys netd observes DNS64 discovery output
Bug: 78545619
Change-Id: I447c35229b07e8077546a03489d36e7be9d969a3
diff --git a/libnetdutils/InternetAddresses.cpp b/libnetdutils/InternetAddresses.cpp
new file mode 100644
index 0000000..c8e4c4c
--- /dev/null
+++ b/libnetdutils/InternetAddresses.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include "netdutils/InternetAddresses.h"
+
+#include <android-base/stringprintf.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+namespace android {
+
+using base::StringPrintf;
+
+namespace netdutils {
+
+std::string IPAddress::toString() const noexcept {
+ char repr[INET6_ADDRSTRLEN] = {0};
+
+ switch (mData.family) {
+ case AF_UNSPEC:
+ return "<unspecified>";
+ case AF_INET: {
+ // Address of packed member may not have correct alignment.
+ const in_addr v4 = mData.ip.v4;
+ inet_ntop(AF_INET, &v4, repr, sizeof(repr));
+ break;
+ }
+ case AF_INET6: {
+ // Address of packed member may not have correct alignment.
+ const in6_addr v6 = mData.ip.v6;
+ inet_ntop(AF_INET6, &v6, repr, sizeof(repr));
+ break;
+ }
+ default:
+ return "<unknown_family>";
+ }
+
+ if (mData.family == AF_INET6 && mData.scope_id > 0) {
+ return StringPrintf("%s%%%u", repr, mData.scope_id);
+ }
+
+ return repr;
+}
+
+bool IPAddress::forString(const std::string& repr, IPAddress* ip) {
+ const addrinfo hints = {
+ .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV,
+ };
+ addrinfo* res;
+ const int ret = getaddrinfo(repr.c_str(), nullptr, &hints, &res);
+ // TODO: move ScopedAddrinfo into libnetdutils and use it here.
+ if (ret != 0) {
+ freeaddrinfo(res);
+ return false;
+ }
+
+ bool rval = true;
+ switch (res[0].ai_family) {
+ case AF_INET: {
+ sockaddr_in* sin = (sockaddr_in*) res[0].ai_addr;
+ if (ip) *ip = IPAddress(sin->sin_addr);
+ break;
+ }
+ case AF_INET6: {
+ sockaddr_in6* sin6 = (sockaddr_in6*) res[0].ai_addr;
+ if (ip) *ip = IPAddress(sin6->sin6_addr, sin6->sin6_scope_id);
+ break;
+ }
+ default:
+ rval = false;
+ break;
+ }
+
+ freeaddrinfo(res);
+ return rval;
+}
+
+IPPrefix::IPPrefix(const IPAddress& ip, int length) : IPPrefix(ip) {
+ // Silently treat CIDR lengths like "-1" as meaning the full bit length
+ // appropriate to the address family.
+ if (length < 0) return;
+ if (length >= mData.cidrlen) return;
+
+ switch (mData.family) {
+ case AF_UNSPEC:
+ break;
+ case AF_INET: {
+ const in_addr_t mask = (length > 0) ? (~0U) << (IPV4_ADDR_BITS - length) : 0U;
+ mData.ip.v4.s_addr &= htonl(mask);
+ mData.cidrlen = static_cast<uint8_t>(length);
+ break;
+ }
+ case AF_INET6: {
+ // The byte in which this CIDR length falls.
+ const int which = (length == 0) ? 0 : length / 8;
+ const int mask = (length % 8 == 0) ? 0 : 0xff << (8 - length % 8);
+ mData.ip.v6.s6_addr[which] &= mask;
+ for (int i = which + 1; i < IPV6_ADDR_LEN; i++) {
+ mData.ip.v6.s6_addr[i] = 0U;
+ }
+ mData.cidrlen = static_cast<uint8_t>(length);
+ break;
+ }
+ default:
+ // TODO: Complain bitterly about possible data corruption?
+ return;
+ }
+}
+
+std::string IPPrefix::toString() const noexcept {
+ return StringPrintf("%s/%d", ip().toString().c_str(), mData.cidrlen);
+}
+
+std::string IPSockAddr::toString() const noexcept {
+ switch (mData.family) {
+ case AF_INET6:
+ return StringPrintf("[%s]:%u", ip().toString().c_str(), mData.port);
+ default:
+ return StringPrintf("%s:%u", ip().toString().c_str(), mData.port);
+ }
+}
+
+} // namespace netdutils
+} // namespace android