Updated client-side TCP forwarding command line options

This commit is contained in:
frekky 2016-02-04 20:44:34 +08:00
parent b1d7a78adf
commit d6b48fe4e1
3 changed files with 82 additions and 54 deletions

View File

@ -1372,31 +1372,39 @@ send_login(char *login, int len)
{ {
uint8_t flags = 0, data[100]; uint8_t flags = 0, data[100];
int length = 17, addrlen = 0; int length = 17, addrlen = 0;
uint16_t port;
if (len != 16) if (len != 16)
DEBUG(1, "Login calculated incorrect length hash! len=%d", len); DEBUG(1, "Login calculated incorrect length hash! len=%d", len);
memcpy(data + 1, login, 16); 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; flags |= 1;
*(uint16_t *) (data + length) = (uint16_t) this.remote_forward_port;
length += 2; length += 2;
/* set remote IP to be non-localhost if this.remote_forward_addr set */ /* 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 */ if (this.remote_forward_addr.ss_family == AF_INET6) { /* IPv6 address */
addrlen = sizeof(struct in6_addr); addrlen = sizeof(s6);
flags |= 4; 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 */ } else { /* IPv4 address */
flags |= 2; flags |= 2;
addrlen = sizeof(struct in_addr); addrlen = sizeof(s);
memcpy(data + length, &((struct sockaddr_in *) &this.remote_forward_addr)->sin_addr, addrlen); memcpy(data + length, &s->sin_addr, addrlen);
} }
length += addrlen; length += addrlen;
} }
DEBUG(2, "Sending TCP forward login request: port %d, length %d, addr %d", DEBUG(2, "Sending TCP forward login request: port %hu, length %d, addrlen %d",
this.remote_forward_port, length, addrlen); port, length, addrlen);
} }
data[0] = flags; data[0] = flags;

View File

@ -46,8 +46,7 @@ struct client_instance {
/* Remote TCP forwarding stuff (for -R) */ /* Remote TCP forwarding stuff (for -R) */
struct sockaddr_storage remote_forward_addr; struct sockaddr_storage remote_forward_addr;
socklen_t remote_forward_addr_len; /* 0 if connecting to localhost */ int use_remote_forward; /* 0 if no forwarding used */
int remote_forward_port; /* 0 if no forwarding used */
int tun_fd; int tun_fd;
int dns_fd; int dns_fd;

View File

@ -81,7 +81,8 @@ struct client_instance this;
.maxfragsize_up = 100, \ .maxfragsize_up = 100, \
.next_downstream_ack = -1, \ .next_downstream_ack = -1, \
.num_immediate = 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 = { static struct client_instance preset_default = {
.raw_mode = 1, .raw_mode = 1,
@ -302,6 +303,62 @@ version()
exit(0); 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 int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -318,7 +375,7 @@ main(int argc, char **argv)
char *device = NULL; char *device = NULL;
char *pidfile = NULL; char *pidfile = NULL;
char *remote_host_str = NULL, *remote_port_str = NULL; int remote_forward_port;
char *nameserv_host = NULL; char *nameserv_host = NULL;
struct sockaddr_storage nameservaddr; struct sockaddr_storage nameservaddr;
@ -452,40 +509,8 @@ main(int argc, char **argv)
case 'R': case 'R':
/* Argument format: [host:]port */ /* Argument format: [host:]port */
if (!optarg) break; if (!optarg) break;
this.use_remote_forward = 1;
if (strrchr(optarg, ':')) { remote_forward_port = parse_tcp_forward_option();
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 */
}
break; break;
case OPT_NODROP: case OPT_NODROP:
// TODO implement TCP-over-tun optimisations // TODO implement TCP-over-tun optimisations
@ -587,11 +612,7 @@ main(int argc, char **argv)
this.foreground = 1; 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; this.nameserv_hosts_len = argc - 1;
if (this.nameserv_hosts_len <= 0) if (this.nameserv_hosts_len <= 0)
@ -712,9 +733,9 @@ main(int argc, char **argv)
(a != this.nameserv_addrs_len - 1) ? ", " : ""); (a != this.nameserv_addrs_len - 1) ? ", " : "");
fprintf(stderr, "\n"); 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", 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()) { if (client_handshake()) {
retval = 1; retval = 1;