adb: implement "adb reverse <local> <remote>"
This implements the logical opposite of 'adb forward', i.e. the ability to reverse network connections from the device to the host. This feature is very useful for testing various programs running on an Android device without root or poking at the host's routing table. Options and parameters are exactly the same as those for 'adb forward', except that the direction is reversed. Examples: adb reverse tcp:5000 tcp:6000 connections to localhost:5000 on the device will be forwarded to localhost:6000 on the host. adb reverse --no-rebind tcp:5000 tcp:6000 same as above, but fails if the socket is already bound through a previous 'adb reverse tcp:5000 ...' command. adb reverse --list list all active reversed connections for the target device. Note: there is no command to list all reversed connections for all devices at once. adb reverse --remove tcp:5000 remove any reversed connection on the device from localhost:5000 adb reverse --remove-all remove all reversed connections form the current device. Reversed connections are tied to a transport, in other words, they disappear as soon as a device is disconnected. Simple testing protocol: adb forward tcp:5000 tcp:6000 adb reverse tcp:6000 tcp:7000 nc -l localhost 7000 in another terminal: echo "Hello" | nc localhost 5000 Will print "Hello" on the first terminal. Change-Id: I761af790cdb06829b68430afa4145a919fa0e6d5
This commit is contained in:
parent
5fe6fcc35d
commit
2525869419
5 changed files with 198 additions and 101 deletions
|
@ -240,3 +240,20 @@ sync:
|
|||
This starts the file synchronisation service, used to implement "adb push"
|
||||
and "adb pull". Since this service is pretty complex, it will be detailed
|
||||
in a companion document named SYNC.TXT
|
||||
|
||||
reverse:<forward-command>
|
||||
This implements the 'adb reverse' feature, i.e. the ability to reverse
|
||||
socket connections from a device to the host. <forward-command> is one
|
||||
of the forwarding commands that are described above, as in:
|
||||
|
||||
list-forward
|
||||
forward:<local>;<remote>
|
||||
forward:norebind:<local>;<remote>
|
||||
killforward-all
|
||||
killforward:<local>
|
||||
|
||||
Note that in this case, <local> corresponds to the socket on the device
|
||||
and <remote> corresponds to the socket on the host.
|
||||
|
||||
The output of reverse:list-forward is the same as host:list-forward
|
||||
except that <serial> will be just 'host'.
|
||||
|
|
221
adb/adb.c
221
adb/adb.c
|
@ -318,7 +318,18 @@ static size_t fill_connect_data(char *buf, size_t bufsize)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void send_msg_with_okay(int fd, char* msg, size_t msglen) {
|
||||
#if !ADB_HOST
|
||||
static void send_msg_with_header(int fd, const char* msg, size_t msglen) {
|
||||
char header[5];
|
||||
if (msglen > 0xffff)
|
||||
msglen = 0xffff;
|
||||
snprintf(header, sizeof(header), "%04x", (unsigned)msglen);
|
||||
writex(fd, header, 4);
|
||||
writex(fd, msg, msglen);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void send_msg_with_okay(int fd, const char* msg, size_t msglen) {
|
||||
char header[9];
|
||||
if (msglen > 0xffff)
|
||||
msglen = 0xffff;
|
||||
|
@ -1428,6 +1439,120 @@ int adb_main(int is_daemon, int server_port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Try to handle a network forwarding request.
|
||||
// This returns 1 on success, 0 on failure, and -1 to indicate this is not
|
||||
// a forwarding-related request.
|
||||
int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd)
|
||||
{
|
||||
if (!strcmp(service, "list-forward")) {
|
||||
// Create the list of forward redirections.
|
||||
int buffer_size = format_listeners(NULL, 0);
|
||||
// Add one byte for the trailing zero.
|
||||
char* buffer = malloc(buffer_size + 1);
|
||||
if (buffer == NULL) {
|
||||
sendfailmsg(reply_fd, "not enough memory");
|
||||
return 1;
|
||||
}
|
||||
(void) format_listeners(buffer, buffer_size + 1);
|
||||
#if ADB_HOST
|
||||
send_msg_with_okay(reply_fd, buffer, buffer_size);
|
||||
#else
|
||||
send_msg_with_header(reply_fd, buffer, buffer_size);
|
||||
#endif
|
||||
free(buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(service, "killforward-all")) {
|
||||
remove_all_listeners();
|
||||
#if ADB_HOST
|
||||
/* On the host: 1st OKAY is connect, 2nd OKAY is status */
|
||||
adb_write(reply_fd, "OKAY", 4);
|
||||
#endif
|
||||
adb_write(reply_fd, "OKAY", 4);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(service, "forward:",8) ||
|
||||
!strncmp(service, "killforward:",12)) {
|
||||
char *local, *remote, *err;
|
||||
int r;
|
||||
atransport *transport;
|
||||
|
||||
int createForward = strncmp(service, "kill", 4);
|
||||
int no_rebind = 0;
|
||||
|
||||
local = strchr(service, ':') + 1;
|
||||
|
||||
// Handle forward:norebind:<local>... here
|
||||
if (createForward && !strncmp(local, "norebind:", 9)) {
|
||||
no_rebind = 1;
|
||||
local = strchr(local, ':') + 1;
|
||||
}
|
||||
|
||||
remote = strchr(local,';');
|
||||
|
||||
if (createForward) {
|
||||
// Check forward: parameter format: '<local>;<remote>'
|
||||
if(remote == 0) {
|
||||
sendfailmsg(reply_fd, "malformed forward spec");
|
||||
return 1;
|
||||
}
|
||||
|
||||
*remote++ = 0;
|
||||
if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
|
||||
sendfailmsg(reply_fd, "malformed forward spec");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
// Check killforward: parameter format: '<local>'
|
||||
if (local[0] == 0) {
|
||||
sendfailmsg(reply_fd, "malformed forward spec");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
|
||||
if (!transport) {
|
||||
sendfailmsg(reply_fd, err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (createForward) {
|
||||
r = install_listener(local, remote, transport, no_rebind);
|
||||
} else {
|
||||
r = remove_listener(local, transport);
|
||||
}
|
||||
if(r == 0) {
|
||||
#if ADB_HOST
|
||||
/* On the host: 1st OKAY is connect, 2nd OKAY is status */
|
||||
writex(reply_fd, "OKAY", 4);
|
||||
#endif
|
||||
writex(reply_fd, "OKAY", 4);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (createForward) {
|
||||
const char* message;
|
||||
switch (r) {
|
||||
case INSTALL_STATUS_CANNOT_BIND:
|
||||
message = "cannot bind to socket";
|
||||
break;
|
||||
case INSTALL_STATUS_CANNOT_REBIND:
|
||||
message = "cannot rebind existing socket";
|
||||
break;
|
||||
default:
|
||||
message = "internal error";
|
||||
}
|
||||
sendfailmsg(reply_fd, message);
|
||||
} else {
|
||||
sendfailmsg(reply_fd, "cannot remove listener");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
|
||||
{
|
||||
atransport *transport = NULL;
|
||||
|
@ -1548,97 +1673,9 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
|
|||
}
|
||||
#endif // ADB_HOST
|
||||
|
||||
if(!strcmp(service,"list-forward")) {
|
||||
// Create the list of forward redirections.
|
||||
int buffer_size = format_listeners(NULL, 0);
|
||||
// Add one byte for the trailing zero.
|
||||
char* buffer = malloc(buffer_size+1);
|
||||
(void) format_listeners(buffer, buffer_size+1);
|
||||
send_msg_with_okay(reply_fd, buffer, buffer_size);
|
||||
free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(service,"killforward-all")) {
|
||||
remove_all_listeners();
|
||||
adb_write(reply_fd, "OKAYOKAY", 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!strncmp(service,"forward:",8) ||
|
||||
!strncmp(service,"killforward:",12)) {
|
||||
char *local, *remote, *err;
|
||||
int r;
|
||||
atransport *transport;
|
||||
|
||||
int createForward = strncmp(service,"kill",4);
|
||||
int no_rebind = 0;
|
||||
|
||||
local = strchr(service, ':') + 1;
|
||||
|
||||
// Handle forward:norebind:<local>... here
|
||||
if (createForward && !strncmp(local, "norebind:", 9)) {
|
||||
no_rebind = 1;
|
||||
local = strchr(local, ':') + 1;
|
||||
}
|
||||
|
||||
remote = strchr(local,';');
|
||||
|
||||
if (createForward) {
|
||||
// Check forward: parameter format: '<local>;<remote>'
|
||||
if(remote == 0) {
|
||||
sendfailmsg(reply_fd, "malformed forward spec");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*remote++ = 0;
|
||||
if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
|
||||
sendfailmsg(reply_fd, "malformed forward spec");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// Check killforward: parameter format: '<local>'
|
||||
if (local[0] == 0) {
|
||||
sendfailmsg(reply_fd, "malformed forward spec");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
|
||||
if (!transport) {
|
||||
sendfailmsg(reply_fd, err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (createForward) {
|
||||
r = install_listener(local, remote, transport, no_rebind);
|
||||
} else {
|
||||
r = remove_listener(local, transport);
|
||||
}
|
||||
if(r == 0) {
|
||||
/* 1st OKAY is connect, 2nd OKAY is status */
|
||||
writex(reply_fd, "OKAYOKAY", 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (createForward) {
|
||||
const char* message;
|
||||
switch (r) {
|
||||
case INSTALL_STATUS_CANNOT_BIND:
|
||||
message = "cannot bind to socket";
|
||||
break;
|
||||
case INSTALL_STATUS_CANNOT_REBIND:
|
||||
message = "cannot rebind existing socket";
|
||||
break;
|
||||
default:
|
||||
message = "internal error";
|
||||
}
|
||||
sendfailmsg(reply_fd, message);
|
||||
} else {
|
||||
sendfailmsg(reply_fd, "cannot remove listener");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int ret = handle_forward_request(service, ttype, serial, reply_fd);
|
||||
if (ret >= 0)
|
||||
return ret - 1;
|
||||
|
||||
if(!strncmp(service,"get-state",strlen("get-state"))) {
|
||||
transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
|
||||
|
|
|
@ -323,6 +323,8 @@ asocket* create_jdwp_tracker_service_socket();
|
|||
int create_jdwp_connection_fd(int jdwp_pid);
|
||||
#endif
|
||||
|
||||
int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);
|
||||
|
||||
#if !ADB_HOST
|
||||
typedef enum {
|
||||
BACKUP,
|
||||
|
|
|
@ -136,6 +136,19 @@ void help()
|
|||
" if <local> is already forwarded\n"
|
||||
" adb forward --remove <local> - remove a specific forward socket connection\n"
|
||||
" adb forward --remove-all - remove all forward socket connections\n"
|
||||
" adb reverse --list - list all reverse socket connections from device\n"
|
||||
" adb reverse <remote> <local> - reverse socket connections\n"
|
||||
" reverse specs are one of:\n"
|
||||
" tcp:<port>\n"
|
||||
" localabstract:<unix domain socket name>\n"
|
||||
" localreserved:<unix domain socket name>\n"
|
||||
" localfilesystem:<unix domain socket name>\n"
|
||||
" adb reverse --norebind <remote> <local>\n"
|
||||
" - same as 'adb reverse <remote> <local>' but fails\n"
|
||||
" if <remote> is already reversed.\n"
|
||||
" adb reverse --remove <remote>\n"
|
||||
" - remove a specific reversed socket connection\n"
|
||||
" adb reverse --remove-all - remove all reversed socket connections from device\n"
|
||||
" adb jdwp - list PIDs of processes hosting a JDWP transport\n"
|
||||
" adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n"
|
||||
" - push this package file to the device and install it\n"
|
||||
|
@ -1299,8 +1312,11 @@ top:
|
|||
return 0;
|
||||
}
|
||||
|
||||
if(!strcmp(argv[0], "forward")) {
|
||||
if(!strcmp(argv[0], "forward") ||
|
||||
!strcmp(argv[0], "reverse"))
|
||||
{
|
||||
char host_prefix[64];
|
||||
char reverse = (char) !strcmp(argv[0], "reverse");
|
||||
char remove = 0;
|
||||
char remove_all = 0;
|
||||
char list = 0;
|
||||
|
@ -1329,15 +1345,19 @@ top:
|
|||
}
|
||||
|
||||
// Determine the <host-prefix> for this command.
|
||||
if (serial) {
|
||||
snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
|
||||
serial);
|
||||
} else if (ttype == kTransportUsb) {
|
||||
snprintf(host_prefix, sizeof host_prefix, "host-usb");
|
||||
} else if (ttype == kTransportLocal) {
|
||||
snprintf(host_prefix, sizeof host_prefix, "host-local");
|
||||
if (reverse) {
|
||||
snprintf(host_prefix, sizeof host_prefix, "reverse");
|
||||
} else {
|
||||
snprintf(host_prefix, sizeof host_prefix, "host");
|
||||
if (serial) {
|
||||
snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
|
||||
serial);
|
||||
} else if (ttype == kTransportUsb) {
|
||||
snprintf(host_prefix, sizeof host_prefix, "host-usb");
|
||||
} else if (ttype == kTransportLocal) {
|
||||
snprintf(host_prefix, sizeof host_prefix, "host-local");
|
||||
} else {
|
||||
snprintf(host_prefix, sizeof host_prefix, "host");
|
||||
}
|
||||
}
|
||||
|
||||
// Implement forward --list
|
||||
|
|
|
@ -154,6 +154,17 @@ cleanup:
|
|||
adb_close(fd);
|
||||
}
|
||||
|
||||
void reverse_service(int fd, void* arg)
|
||||
{
|
||||
const char* command = arg;
|
||||
|
||||
if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) {
|
||||
sendfailmsg(fd, "not a reverse forwarding command");
|
||||
}
|
||||
free(arg);
|
||||
adb_close(fd);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int create_service_thread(void (*func)(int, void *), void *cookie)
|
||||
|
@ -398,6 +409,16 @@ int service_to_fd(const char *name)
|
|||
ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port);
|
||||
} else if(!strncmp(name, "usb:", 4)) {
|
||||
ret = create_service_thread(restart_usb_service, NULL);
|
||||
} else if (!strncmp(name, "reverse:", 8)) {
|
||||
char* cookie = strdup(name + 8);
|
||||
if (cookie == NULL) {
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = create_service_thread(reverse_service, cookie);
|
||||
if (ret < 0) {
|
||||
free(cookie);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (ret >= 0) {
|
||||
|
|
Loading…
Reference in a new issue