From 910166b3d67652abb54dece7e1cacdc9dcfdb659 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 28 May 2020 04:06:28 +0200 Subject: iproxy: Allow specifying source address for the listening socket --- common/socket.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++--------- common/socket.h | 2 +- tools/iproxy.c | 24 ++++++++++++--- 3 files changed, 99 insertions(+), 21 deletions(-) diff --git a/common/socket.c b/common/socket.c index a47de2a..1c38965 100644 --- a/common/socket.c +++ b/common/socket.c @@ -255,7 +255,7 @@ int socket_connect_unix(const char *filename) } #endif -int socket_create(uint16_t port) +int socket_create(const char* addr, uint16_t port) { int sfd = -1; int yes = 1; @@ -269,9 +269,79 @@ int socket_create(uint16_t port) wsa_init = 1; } #endif + struct sockaddr* srcaddr; + int srcaddr_len = 0; + int domain = PF_INET; + +#if defined(AF_INET6) + struct sockaddr_in6 saddr6; + memset((void*) &saddr6, 0, sizeof(saddr6)); + saddr6.sin6_family = AF_INET6; + saddr6.sin6_port = htons(port); + saddr6.sin6_addr = in6addr_loopback; +#endif + struct sockaddr_in saddr; + memset((void*) &saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + saddr.sin_port = htons(port); + + if (addr) { + if (strchr(addr, ':')) { +#ifdef AF_INET6 +#ifdef WIN32 + struct sockaddr_storage ss; + int ss_size = sizeof(ss); + if (WSAStringToAddress((LPSTR)addr, AF_INET6, NULL, (struct sockaddr*)&ss, &ss_size) == 0) { + memcpy(&(saddr6.sin6_addr), &(((struct sockaddr_in6*)&ss)->sin6_addr), sizeof(struct in6_addr)); + } else +#else + if (inet_pton(AF_INET6, addr, &(saddr6.sin6_addr)) != 1) +#endif + { + fprintf(stderr, "FATAL: Failed to convert '%s' to an IPv6 address.\n", addr); + socket_close(sfd); + return -1; + } + srcaddr = (struct sockaddr*)&saddr6; + srcaddr_len = sizeof(saddr6); + domain = PF_INET6; +#else + fprintf(stderr, "FATAL: Got IPv6 address but AF_INET6 is not supported.\n"); + socket_close(sfd); + return -1; +#endif + } else { +#ifdef WIN32 + struct sockaddr_storage ss; + int ss_size = sizeof(ss); + if (WSAStringToAddress((LPSTR)addr, AF_INET, NULL, (struct sockaddr*)&ss, &ss_size) == 0) { + saddr.sin_addr.s_addr = ((struct sockaddr_in*)&ss)->sin_addr.s_addr; + } else +#else + if (inet_pton(AF_INET, addr, &(saddr.sin_addr)) != 1) +#endif + { + fprintf(stderr, "FATAL: Failed to convert '%s' to an IPv4 address.\n", addr); + socket_close(sfd); + return -1; + } + srcaddr = (struct sockaddr*)&saddr; + srcaddr_len = sizeof(saddr); + } + } else { +#if !defined(WIN32) && defined(AF_INET6) + srcaddr = (struct sockaddr*)&saddr6; + srcaddr_len = sizeof(saddr6); + domain = PF_INET6; +#else + srcaddr = (struct sockaddr*)&saddr; + srcaddr_len = sizeof(saddr); +#endif + } - if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) { + if ((sfd = socket(domain, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("socket()"); return -1; } @@ -290,18 +360,13 @@ int socket_create(uint16_t port) } #endif - memset((void *) &saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - saddr.sin_port = htons(port); - - if (0 > bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr))) { + if (bind(sfd, srcaddr, srcaddr_len) < 0) { perror("bind()"); socket_close(sfd); return -1; } - if (listen(sfd, 1) == -1) { + if (listen(sfd, 1) < 0) { perror("listen()"); socket_close(sfd); return -1; @@ -626,14 +691,13 @@ int socket_accept(int fd, uint16_t port) socklen_t addr_len; #endif int result; +#ifdef AF_INET6 + struct sockaddr_in6 addr; + addr_len = sizeof(addr); +#else struct sockaddr_in addr; - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = htons(port); - addr_len = sizeof(addr); +#endif result = accept(fd, (struct sockaddr*)&addr, &addr_len); return result; diff --git a/common/socket.h b/common/socket.h index 38eeddf..f510147 100644 --- a/common/socket.h +++ b/common/socket.h @@ -45,7 +45,7 @@ typedef enum fd_mode fd_mode; int socket_create_unix(const char *filename); int socket_connect_unix(const char *filename); #endif -int socket_create(uint16_t port); +int socket_create(const char *addr, uint16_t port); int socket_connect_addr(struct sockaddr *addr, uint16_t port); int socket_connect(const char *addr, uint16_t port); int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout); diff --git a/tools/iproxy.c b/tools/iproxy.c index 8321143..e9524a4 100644 --- a/tools/iproxy.c +++ b/tools/iproxy.c @@ -220,6 +220,7 @@ static void print_usage(int argc, char **argv, int is_error) " -u, --udid UDID target specific device by UDID\n" \ " -n, --network connect to network device\n" \ " -l, --local connect to USB device (default)\n" \ + " -s, --source ADDR source address for listening socket (default 127.0.0.1)\n" \ " -h, --help prints usage information\n" \ " -d, --debug increase debug level\n" \ "\n" \ @@ -233,6 +234,7 @@ int main(int argc, char **argv) { int mysock = -1; char* device_udid = NULL; + char* source_addr = NULL; uint16_t listen_port = 0; uint16_t device_port = 0; enum usbmux_lookup_options lookup_opts = 0; @@ -243,10 +245,11 @@ int main(int argc, char **argv) { "udid", required_argument, NULL, 'u' }, { "local", no_argument, NULL, 'l' }, { "network", no_argument, NULL, 'n' }, + { "source", required_argument, NULL, 's' }, { NULL, 0, NULL, 0} }; int c = 0; - while ((c = getopt_long(argc, argv, "dhu:ln", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "dhu:lns:", longopts, NULL)) != -1) { switch (c) { case 'd': libusbmuxd_set_debug_level(++debug_level); @@ -266,6 +269,15 @@ int main(int argc, char **argv) case 'n': lookup_opts |= DEVICE_LOOKUP_NETWORK; break; + case 's': + if (!*optarg) { + fprintf(stderr, "ERROR: source address must not be empty!\n"); + print_usage(argc, argv, 1); + return 2; + } + free(source_addr); + source_addr = strdup(optarg); + break; case 'h': print_usage(argc, argv, 0); return 0; @@ -307,7 +319,7 @@ int main(int argc, char **argv) signal(SIGPIPE, SIG_IGN); #endif // first create the listening socket endpoint waiting for connections. - mysock = socket_create(listen_port); + mysock = socket_create(source_addr, listen_port); if (mysock < 0) { fprintf(stderr, "Error creating socket: %s\n", strerror(errno)); free(device_udid); @@ -323,7 +335,10 @@ int main(int argc, char **argv) while (1) { printf("waiting for connection\n"); c_sock = socket_accept(mysock, listen_port); - if (c_sock) { + if (c_sock < 0) { + fprintf(stderr, "accept: %s\n", strerror(errno)); + break; + } else { printf("accepted connection, fd = %d\n", c_sock); cdata = (struct client_data*)malloc(sizeof(struct client_data)); if (!cdata) { @@ -344,8 +359,6 @@ int main(int argc, char **argv) pthread_create(&acceptor, NULL, acceptor_thread, cdata); pthread_detach(acceptor); #endif - } else { - break; } } socket_close(c_sock); @@ -353,6 +366,7 @@ int main(int argc, char **argv) } free(device_udid); + free(source_addr); return 0; } -- cgit v1.1-32-gdbae