adb: don't try to resolve 'localhost'
Misconfigured systems can have localhost pointing to an address that
isn't 127.0.0.1 or ::1.
adb is the only caller of the libcutils socket_loopback functions, so
move them into adb and switch the implementations over to using
INADDR_LOOPBACK and in6addr_loopback, instead of resolving 'localhost'
when connecting.
Bug: http://b/37282612
Test: `killall adb; adb shell`
Test: `killall adb; ip addr del 127.0.0.1/8 dev lo; adb shell`
Change-Id: I01c1885f1d9757ad0f7b353dd04b4d1f057741c8
diff --git a/Android.mk b/Android.mk
index e841205..94ccc08 100644
--- a/Android.mk
+++ b/Android.mk
@@ -81,12 +81,14 @@
LIBADB_darwin_SRC_FILES := \
sysdeps_unix.cpp \
+ sysdeps/posix/network.cpp \
client/usb_dispatch.cpp \
client/usb_libusb.cpp \
client/usb_osx.cpp \
LIBADB_linux_SRC_FILES := \
sysdeps_unix.cpp \
+ sysdeps/posix/network.cpp \
client/usb_dispatch.cpp \
client/usb_libusb.cpp \
client/usb_linux.cpp \
@@ -123,6 +125,7 @@
$(LIBADB_SRC_FILES) \
adbd_auth.cpp \
jdwp_service.cpp \
+ sysdeps/posix/network.cpp \
LOCAL_SANITIZE := $(adb_target_sanitize)
diff --git a/sysdeps.h b/sysdeps.h
index f95a855..5cd0cd1 100644
--- a/sysdeps.h
+++ b/sysdeps.h
@@ -35,6 +35,7 @@
#include <android-base/utf8.h>
#include "sysdeps/errno.h"
+#include "sysdeps/network.h"
#include "sysdeps/stat.h"
/*
@@ -248,8 +249,6 @@
int unix_isatty(int fd);
#define isatty ___xxx_isatty
-int network_loopback_client(int port, int type, std::string* error);
-int network_loopback_server(int port, int type, std::string* error);
int network_inaddr_any_server(int port, int type, std::string* error);
inline int network_local_client(const char* name, int namespace_id, int type, std::string* error) {
@@ -587,17 +586,6 @@
return fd;
}
-inline int network_loopback_client(int port, int type, std::string* error) {
- return _fd_set_error_str(socket_network_client("localhost", port, type), error);
-}
-
-inline int network_loopback_server(int port, int type, std::string* error) {
- int fd = socket_loopback_server(port, type);
- if (fd < 0 && errno == EAFNOSUPPORT)
- return _fd_set_error_str(socket_loopback_server6(port, type), error);
- return _fd_set_error_str(fd, error);
-}
-
inline int network_inaddr_any_server(int port, int type, std::string* error) {
return _fd_set_error_str(socket_inaddr_any_server(port, type), error);
}
diff --git a/sysdeps/network.h b/sysdeps/network.h
new file mode 100644
index 0000000..83ce371
--- /dev/null
+++ b/sysdeps/network.h
@@ -0,0 +1,22 @@
+#pragma once
+
+/*
+ * Copyright (C) 2017 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 <string>
+
+int network_loopback_client(int port, int type, std::string* error);
+int network_loopback_server(int port, int type, std::string* error);
diff --git a/sysdeps/posix/network.cpp b/sysdeps/posix/network.cpp
new file mode 100644
index 0000000..45da5af
--- /dev/null
+++ b/sysdeps/posix/network.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2017 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 "sysdeps/network.h"
+
+#include <errno.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <string>
+
+#include "adb_unique_fd.h"
+
+static void set_error(std::string* error) {
+ if (error) {
+ *error = strerror(errno);
+ }
+}
+
+static sockaddr* loopback_addr4(sockaddr_storage* addr, socklen_t* addrlen, int port) {
+ struct sockaddr_in* addr4 = reinterpret_cast<sockaddr_in*>(addr);
+ *addrlen = sizeof(*addr4);
+
+ addr4->sin_family = AF_INET;
+ addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr4->sin_port = htons(port);
+ return reinterpret_cast<sockaddr*>(addr);
+}
+
+static sockaddr* loopback_addr6(sockaddr_storage* addr, socklen_t* addrlen, int port) {
+ struct sockaddr_in6* addr6 = reinterpret_cast<sockaddr_in6*>(addr);
+ *addrlen = sizeof(*addr6);
+
+ addr6->sin6_family = AF_INET6;
+ addr6->sin6_addr = in6addr_loopback;
+ addr6->sin6_port = htons(port);
+ return reinterpret_cast<sockaddr*>(addr);
+}
+
+static int _network_loopback_client(bool ipv6, int port, int type, std::string* error) {
+ unique_fd s(socket(ipv6 ? AF_INET6 : AF_INET, type, 0));
+ if (s == -1) {
+ set_error(error);
+ return -1;
+ }
+
+ struct sockaddr_storage addr_storage = {};
+ socklen_t addrlen = sizeof(addr_storage);
+ sockaddr* addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, 0);
+
+ if (bind(s.get(), addr, addrlen) != 0) {
+ set_error(error);
+ return -1;
+ }
+
+ addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, port);
+
+ if (connect(s.get(), addr, addrlen) != 0) {
+ set_error(error);
+ return -1;
+ }
+
+ return s.release();
+}
+
+int network_loopback_client(int port, int type, std::string* error) {
+ // Try IPv4 first, use IPv6 as a fallback.
+ int rc = _network_loopback_client(false, port, type, error);
+ if (rc == -1) {
+ return _network_loopback_client(true, port, type, error);
+ }
+ return rc;
+}
+
+static int _network_loopback_server(bool ipv6, int port, int type, std::string* error) {
+ unique_fd s(socket(ipv6 ? AF_INET6 : AF_INET, type, 0));
+ if (s == -1) {
+ set_error(error);
+ return -1;
+ }
+
+ int n = 1;
+ setsockopt(s.get(), SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+
+ struct sockaddr_storage addr_storage = {};
+ socklen_t addrlen = sizeof(addr_storage);
+ sockaddr* addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, port);
+
+ if (bind(s, addr, addrlen) != 0) {
+ set_error(error);
+ return -1;
+ }
+
+ if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {
+ // Arbitrarily selected value, ported from libcutils.
+ if (listen(s, 4) != 0) {
+ set_error(error);
+ return -1;
+ }
+ }
+
+ return s.release();
+}
+
+int network_loopback_server(int port, int type, std::string* error) {
+ int rc = _network_loopback_server(false, port, type, error);
+
+ // Only attempt to listen on IPv6 if IPv4 is unavailable.
+ // We don't want to start an IPv6 server if there's already an IPv4 one running.
+ if (rc == -1 && (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)) {
+ return _network_loopback_server(true, port, type, error);
+ }
+ return rc;
+}