From d6b48fe4e1abc88f831535df6cc9c062eecb17d2 Mon Sep 17 00:00:00 2001 From: frekky Date: Thu, 4 Feb 2016 20:44:34 +0800 Subject: [PATCH] Updated client-side TCP forwarding command line options --- src/client.c | 26 ++++++++----- src/client.h | 3 +- src/iodine.c | 107 ++++++++++++++++++++++++++++++--------------------- 3 files changed, 82 insertions(+), 54 deletions(-) diff --git a/src/client.c b/src/client.c index 8ab06ba..ddcc7e4 100644 --- a/src/client.c +++ b/src/client.c @@ -1372,31 +1372,39 @@ send_login(char *login, int len) { uint8_t flags = 0, data[100]; int length = 17, addrlen = 0; + uint16_t port; if (len != 16) DEBUG(1, "Login calculated incorrect length hash! len=%d", len); memcpy(data + 1, login, 16); - if (this.remote_forward_port > 0) { + if (this.remote_forward_addr.ss_family != AF_UNSPEC) { + struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &this.remote_forward_addr; + struct sockaddr_in *s = (struct sockaddr_in *) &this.remote_forward_addr; + + port = (this.remote_forward_addr.ss_family == AF_INET ? s->sin_port : s6->sin6_port); + + *(uint16_t *) (data + length) = port; + flags |= 1; - *(uint16_t *) (data + length) = (uint16_t) this.remote_forward_port; length += 2; /* set remote IP to be non-localhost if this.remote_forward_addr set */ - if (this.remote_forward_addr_len) { + if (this.remote_forward_addr.ss_family == AF_INET && s->sin_addr.s_addr != INADDR_LOOPBACK) { if (this.remote_forward_addr.ss_family == AF_INET6) { /* IPv6 address */ - addrlen = sizeof(struct in6_addr); + addrlen = sizeof(s6); flags |= 4; - memcpy(data + length, &((struct sockaddr_in6 *) &this.remote_forward_addr)->sin6_addr, addrlen); + memcpy(data + length, &s6->sin6_addr, addrlen); } else { /* IPv4 address */ flags |= 2; - addrlen = sizeof(struct in_addr); - memcpy(data + length, &((struct sockaddr_in *) &this.remote_forward_addr)->sin_addr, addrlen); + addrlen = sizeof(s); + memcpy(data + length, &s->sin_addr, addrlen); } + length += addrlen; } - DEBUG(2, "Sending TCP forward login request: port %d, length %d, addr %d", - this.remote_forward_port, length, addrlen); + DEBUG(2, "Sending TCP forward login request: port %hu, length %d, addrlen %d", + port, length, addrlen); } data[0] = flags; diff --git a/src/client.h b/src/client.h index 65027f7..eee25b0 100644 --- a/src/client.h +++ b/src/client.h @@ -46,8 +46,7 @@ struct client_instance { /* Remote TCP forwarding stuff (for -R) */ struct sockaddr_storage remote_forward_addr; - socklen_t remote_forward_addr_len; /* 0 if connecting to localhost */ - int remote_forward_port; /* 0 if no forwarding used */ + int use_remote_forward; /* 0 if no forwarding used */ int tun_fd; int dns_fd; diff --git a/src/iodine.c b/src/iodine.c index 39bf2ec..437e0e2 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -81,7 +81,8 @@ struct client_instance this; .maxfragsize_up = 100, \ .next_downstream_ack = -1, \ .num_immediate = 1, \ - .rtt_total_ms = 200 + .rtt_total_ms = 200, \ + .remote_forward_addr = {.ss_family = AF_UNSPEC} static struct client_instance preset_default = { .raw_mode = 1, @@ -302,6 +303,62 @@ version() exit(0); } +static int +parse_tcp_forward_option() +{ + char *remote_port_str, *remote_host_str; + int retval; + + if (strrchr(optarg, ':')) { + remote_port_str = strrchr(optarg, ':') + 1; + if (optarg[0] == '[') { + /* IPv6 address enclosed in square brackets */ + remote_host_str = optarg + 1; + /* replace closing bracket with null terminator */ + *strchr(remote_host_str, ']') = 0; + this.remote_forward_addr.ss_family = AF_INET6; + retval = inet_pton(AF_INET6, remote_host_str, + &((struct sockaddr_in6 *) &this.remote_forward_addr)->sin6_addr); + } else { + remote_host_str = optarg; + /* replace separator with null terminator */ + *strchr(remote_host_str, ':') = 0; + this.remote_forward_addr.ss_family = AF_INET; + retval = inet_aton(remote_host_str, + &((struct sockaddr_in *) &this.remote_forward_addr)->sin_addr); + } + } else { + /* no address specified (use server localhost IPv4), optarg is port */ + remote_port_str = optarg; + this.remote_forward_addr.ss_family = AF_INET; + ((struct sockaddr_in *) &this.remote_forward_addr)->sin_addr.s_addr = INADDR_LOOPBACK; + } + + if (retval <= 0) { + errx(12, "Invalid remote forward address (-R)! Must be [host:]port,\n" + "where IPv6 addresses are enclosed in literal square brackets []."); + usage(); + /* not reached */ + } + + /* parse port */ + int port = atoi(remote_port_str); + if (port < 1 || port > 65535) { + fprintf(stderr, "Remote forward (-R) TCP port must be between 1 and 65535."); + usage(); + /* not reached */ + } + + if (this.remote_forward_addr.ss_family == AF_INET) { + /* set port as sockaddr_in (IPv4) */ + ((struct sockaddr_in *) &this.remote_forward_addr)->sin_port = port; + } else { + /* set port in IPv6 sockaddr */ + ((struct sockaddr_in6 *) &this.remote_forward_addr)->sin6_port = port; + } + return port; +} + int main(int argc, char **argv) { @@ -318,7 +375,7 @@ main(int argc, char **argv) char *device = NULL; char *pidfile = NULL; - char *remote_host_str = NULL, *remote_port_str = NULL; + int remote_forward_port; char *nameserv_host = NULL; struct sockaddr_storage nameservaddr; @@ -452,40 +509,8 @@ main(int argc, char **argv) case 'R': /* Argument format: [host:]port */ if (!optarg) break; - - if (strrchr(optarg, ':')) { - remote_port_str = strrchr(optarg, ':') + 1; - if (optarg[0] == '[') { - /* IPv6 address enclosed in square brackets */ - remote_host_str = optarg + 1; - /* replace closing bracket with null terminator */ - *strchr(remote_host_str, ']') = 0; - this.remote_forward_addr.ss_family = AF_INET6; - retval = inet_pton(AF_INET6, remote_host_str, - &((struct sockaddr_in6 *) &this.remote_forward_addr)->sin6_addr); - } else { - remote_host_str = optarg; - /* replace separator with null terminator */ - *strchr(remote_host_str, ':') = 0; - this.remote_forward_addr.ss_family = AF_INET; - retval = inet_aton(remote_host_str, - &((struct sockaddr_in *) &this.remote_forward_addr)->sin_addr); - } - } else { - /* no address specified, optarg is port */ - remote_port_str = optarg; - } - - /* parse port */ - this.remote_forward_port = atoi(remote_port_str); - if (this.remote_forward_port < 0 || this.remote_forward_port > 65535) - this.remote_forward_port = -1; - - if (retval <= 0) { - errx(12, "Invalid remote TCP forwarding specification! Check help for info."); - usage(); - /* not reached */ - } + this.use_remote_forward = 1; + remote_forward_port = parse_tcp_forward_option(); break; case OPT_NODROP: // TODO implement TCP-over-tun optimisations @@ -587,11 +612,7 @@ main(int argc, char **argv) this.foreground = 1; } - if (this.remote_forward_port == -1) { - fprintf(stderr, "Remote TCP port must be between 1 and 65535."); - usage(); - /* not reached */ - } + this.nameserv_hosts_len = argc - 1; if (this.nameserv_hosts_len <= 0) @@ -712,9 +733,9 @@ main(int argc, char **argv) (a != this.nameserv_addrs_len - 1) ? ", " : ""); fprintf(stderr, "\n"); - if (this.remote_forward_port) + if (this.remote_forward_addr.ss_family != AF_UNSPEC) fprintf(stderr, "Requesting TCP data forwarding from server to %s:%d\n", - format_addr(&this.remote_forward_addr, sizeof(struct sockaddr_storage)), this.remote_forward_port); + format_addr(&this.remote_forward_addr, sizeof(struct sockaddr_storage)), remote_forward_port); if (client_handshake()) { retval = 1;