From 8539cb3f759170ef08a583a7497caf439ad1988c Mon Sep 17 00:00:00 2001 From: Callum Ryan Date: Thu, 31 Oct 2019 07:21:42 -0700 Subject: [PATCH] Allow the adb server to bind on ::1 Currently the adb server can only bind on 127.0.0.1 or * if -a is provided. This diff adds the ability for adb to bind on ::1 as well for use cases where you might want to force adb to be IPv6 only. To bind the adb server on ::1 ``` $ ./adb -L tcp:[::1]:1234 server $ lsof -nPi :1234 COMMAND ... NODE NAME adb ... TCP [::1]:1234 (LISTEN) ``` The original behaviour is also retained, so this would only affect users explicitly specifying ::1 in the socket spec ``` $ export ANDROID_ADB_SERVER_PORT=1234 $ ./adb server $ lsof -nPi :1234 COMMAND ... NODE NAME adb ... TCP 127.0.0.1:1234 (LISTEN) ``` Note: I've only implemented this behaviour for posix base systems, due to my limited understanding of networking on windows. If needed I can do some research to implement it there as well, but there is currently no IPv6 support at all on the windows side. Test: New unit test and the commands in the summary Change-Id: I23e4531e8dfda4de9348124ad7491d728aecdbf7 --- adb/socket_spec.cpp | 4 +++- adb/sysdeps/network.h | 2 +- adb/sysdeps/posix/network.cpp | 11 +++++++---- adb/sysdeps_win32.cpp | 5 +++-- adb/test_adb.py | 31 +++++++++++++++++++++++++++++++ 5 files changed, 45 insertions(+), 8 deletions(-) diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp index 98468b5cf..27e8c4605 100644 --- a/adb/socket_spec.cpp +++ b/adb/socket_spec.cpp @@ -272,7 +272,9 @@ int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_ if (hostname.empty() && gListenAll) { result = network_inaddr_any_server(port, SOCK_STREAM, error); } else if (tcp_host_is_local(hostname)) { - result = network_loopback_server(port, SOCK_STREAM, error); + result = network_loopback_server(port, SOCK_STREAM, error, true); + } else if (hostname == "::1") { + result = network_loopback_server(port, SOCK_STREAM, error, false); } else { // TODO: Implement me. *error = "listening on specified hostname currently unsupported"; diff --git a/adb/sysdeps/network.h b/adb/sysdeps/network.h index 83ce37112..fadd15598 100644 --- a/adb/sysdeps/network.h +++ b/adb/sysdeps/network.h @@ -19,4 +19,4 @@ #include int network_loopback_client(int port, int type, std::string* error); -int network_loopback_server(int port, int type, std::string* error); +int network_loopback_server(int port, int type, std::string* error, bool prefer_ipv4); diff --git a/adb/sysdeps/posix/network.cpp b/adb/sysdeps/posix/network.cpp index c5c227568..a4d9013d3 100644 --- a/adb/sysdeps/posix/network.cpp +++ b/adb/sysdeps/posix/network.cpp @@ -119,12 +119,15 @@ static int _network_loopback_server(bool ipv6, int port, int type, std::string* return s.release(); } -int network_loopback_server(int port, int type, std::string* error) { - int rc = _network_loopback_server(false, port, type, error); +int network_loopback_server(int port, int type, std::string* error, bool prefer_ipv4) { + int rc = -1; + if (prefer_ipv4) { + rc = _network_loopback_server(false, port, type, error); + } - // Only attempt to listen on IPv6 if IPv4 is unavailable. + // Only attempt to listen on IPv6 if IPv4 is unavailable or prefer_ipv4 is false // We don't want to start an IPv6 server if there's already an IPv4 one running. - if (rc == -1 && (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)) { + if (rc == -1 && (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || !prefer_ipv4)) { return _network_loopback_server(true, port, type, error); } return rc; diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp index 4d6cf3de5..d9cc36f83 100644 --- a/adb/sysdeps_win32.cpp +++ b/adb/sysdeps_win32.cpp @@ -920,7 +920,8 @@ static int _network_server(int port, int type, u_long interface_address, std::st return fd; } -int network_loopback_server(int port, int type, std::string* error) { +int network_loopback_server(int port, int type, std::string* error, bool prefer_ipv4) { + // TODO implement IPv6 support on windows return _network_server(port, type, INADDR_LOOPBACK, error); } @@ -1132,7 +1133,7 @@ int adb_socketpair(int sv[2]) { int local_port = -1; std::string error; - server = network_loopback_server(0, SOCK_STREAM, &error); + server = network_loopback_server(0, SOCK_STREAM, &error, true); if (server < 0) { D("adb_socketpair: failed to create server: %s", error.c_str()); goto fail; diff --git a/adb/test_adb.py b/adb/test_adb.py index 8272722e8..3d6de2665 100755 --- a/adb/test_adb.py +++ b/adb/test_adb.py @@ -281,6 +281,37 @@ class ServerTest(unittest.TestCase): subprocess.check_output(["adb", "-P", str(port), "kill-server"], stderr=subprocess.STDOUT) + @unittest.skipUnless( + os.name == "posix", + "adb doesn't yet support IPv6 on Windows", + ) + def test_starts_on_ipv6_localhost(self): + """ + Tests that the server can start up on ::1 and that it's accessible + """ + server_port = 5037 + # Kill any existing server on this non-default port. + subprocess.check_output( + ["adb", "-P", str(server_port), "kill-server"], + stderr=subprocess.STDOUT, + ) + try: + subprocess.check_output( + ["adb", "-L", "tcp:[::1]:{}".format(server_port), "server"], + stderr=subprocess.STDOUT, + ) + with fake_adbd() as (port, _): + with adb_connect(self, serial="localhost:{}".format(port)): + pass + finally: + # If we started a server, kill it. + subprocess.check_output( + ["adb", "-P", str(server_port), "kill-server"], + stderr=subprocess.STDOUT, + ) + + + class EmulatorTest(unittest.TestCase): """Tests for the emulator connection."""