From 9c7ecf6d14a82c1b1a97e1b4a328460ba8762299 Mon Sep 17 00:00:00 2001 From: houseofkodai Date: Mon, 1 May 2017 08:26:15 +0530 Subject: cli_bind_address_connect * replaces -b dummy option in dbclient to be similar with openssh -b option * useful in multi-wan connections --- netio.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'netio.c') diff --git a/netio.c b/netio.c index 2f37e70..b594e84 100644 --- a/netio.c +++ b/netio.c @@ -19,6 +19,7 @@ struct dropbear_progress_connection { int sock; char* errstring; + struct addrinfo *bind_addrinfo; }; /* Deallocate a progress connection. Removes from the pending list if iter!=NULL. @@ -30,6 +31,7 @@ static void remove_connect(struct dropbear_progress_connection *c, m_list_elem * m_free(c->remotehost); m_free(c->remoteport); m_free(c->errstring); + if (c->bind_addrinfo) freeaddrinfo(c->bind_addrinfo); m_free(c); if (iter) { @@ -66,6 +68,17 @@ static void connect_try_next(struct dropbear_progress_connection *c) { continue; } + if (c->bind_addrinfo) { + if (bind(c->sock, c->bind_addrinfo->ai_addr, c->bind_addrinfo->ai_addrlen) < 0) { + /* failure */ + m_free(c->errstring); + c->errstring = m_strdup(strerror(errno)); + close(c->sock); + c->sock = -1; + continue; + } + } + ses.maxfd = MAX(ses.maxfd, c->sock); set_sock_nodelay(c->sock); setnonblocking(c->sock); @@ -130,7 +143,7 @@ static void connect_try_next(struct dropbear_progress_connection *c) { /* Connect via TCP to a host. */ struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport, - connect_callback cb, void* cb_data) + connect_callback cb, void* cb_data, char* bind_address) { struct dropbear_progress_connection *c = NULL; int err; @@ -142,6 +155,7 @@ struct dropbear_progress_connection *connect_remote(const char* remotehost, cons c->sock = -1; c->cb = cb; c->cb_data = cb_data; + c->bind_addrinfo = NULL; list_append(&ses.conn_pending, c); @@ -160,6 +174,22 @@ struct dropbear_progress_connection *connect_remote(const char* remotehost, cons } else { c->res_iter = c->res; } + + if (NULL != bind_address) { + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + err = getaddrinfo(bind_address, NULL, &hints, &c->bind_addrinfo); + if (err) { + int len; + len = 100 + strlen(gai_strerror(err)); + c->errstring = (char*)m_malloc(len); + snprintf(c->errstring, len, "Error resolving '%s'. %s", + bind_address, gai_strerror(err)); + TRACE(("Error resolving: %s", gai_strerror(err))) + c->res_iter = NULL; + } + } return c; } -- cgit v1.2.3 From e4ac7ea1ca910e0d245232a8ab16415f252b006b Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 26 Jan 2018 00:27:48 +0800 Subject: bind to port as well with -b --- cli-main.c | 7 ++++--- cli-runopts.c | 18 +++++++++++++++-- cli-tcpfwd.c | 2 +- dbclient.1 | 6 +++++- netio.c | 62 +++++++++++++++++++++++++++++++++++++++-------------------- netio.h | 2 +- runopts.h | 1 + svr-tcpfwd.c | 2 +- 8 files changed, 70 insertions(+), 30 deletions(-) (limited to 'netio.c') diff --git a/cli-main.c b/cli-main.c index d541e2a..3e02e6d 100644 --- a/cli-main.c +++ b/cli-main.c @@ -66,8 +66,8 @@ int main(int argc, char ** argv) { } #endif - TRACE(("user='%s' host='%s' port='%s' bind_address='%s'", cli_opts.username, - cli_opts.remotehost, cli_opts.remoteport, cli_opts.bind_address)) + TRACE(("user='%s' host='%s' port='%s' bind_address='%s' bind_port='%s'", cli_opts.username, + cli_opts.remotehost, cli_opts.remoteport, cli_opts.bind_address, cli_opts.bind_port)) if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { dropbear_exit("signal() error"); @@ -86,7 +86,8 @@ int main(int argc, char ** argv) { } else #endif { - progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport, cli_connected, &ses, cli_opts.bind_address); + progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport, + cli_connected, &ses, cli_opts.bind_address, cli_opts.bind_port); sock_in = sock_out = -1; } diff --git a/cli-runopts.c b/cli-runopts.c index 4057824..d69a719 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -92,7 +92,7 @@ static void printhelp() { "-c Specify preferred ciphers ('-c help' to list options)\n" "-m Specify preferred MACs for packet verification (or '-m help')\n" #endif - "-b bind_address\n" + "-b [bind_address][:bind_port]\n" "-V Version\n" #if DEBUG_TRACE "-v verbose (compiled with DEBUG_TRACE)\n" @@ -131,6 +131,7 @@ void cli_getopts(int argc, char ** argv) { char* keepalive_arg = NULL; char* idle_timeout_arg = NULL; char *host_arg = NULL; + char *bind_arg = NULL; char c; /* see printhelp() for options */ @@ -167,6 +168,7 @@ void cli_getopts(int argc, char ** argv) { cli_opts.proxycmd = NULL; #endif cli_opts.bind_address = NULL; + cli_opts.bind_port = NULL; #ifndef DISABLE_ZLIB opts.compress_mode = DROPBEAR_COMPRESS_ON; #endif @@ -315,7 +317,7 @@ void cli_getopts(int argc, char ** argv) { exit(EXIT_SUCCESS); break; case 'b': - next = &cli_opts.bind_address; + next = &bind_arg; break; default: fprintf(stderr, @@ -421,6 +423,18 @@ void cli_getopts(int argc, char ** argv) { cli_opts.remoteport = "22"; } + if (bind_arg) { + /* split [host][:port] */ + char *port = strrchr(bind_arg, ':'); + if (port) { + cli_opts.bind_port = m_strdup(port+1); + *port = '\0'; + } + if (strlen(bind_arg) > 0) { + cli_opts.bind_address = m_strdup(bind_arg); + } + } + /* If not explicitly specified with -t or -T, we don't want a pty if * there's a command, but we do otherwise */ if (cli_opts.wantpty == 9) { diff --git a/cli-tcpfwd.c b/cli-tcpfwd.c index b9ea91e..1a1850d 100644 --- a/cli-tcpfwd.c +++ b/cli-tcpfwd.c @@ -274,7 +274,7 @@ static int newtcpforwarded(struct Channel * channel) { } snprintf(portstring, sizeof(portstring), "%u", fwd->connectport); - channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel, NULL); + channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel, NULL, NULL); channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE; diff --git a/dbclient.1 b/dbclient.1 index fee23c6..8607254 100644 --- a/dbclient.1 +++ b/dbclient.1 @@ -133,8 +133,8 @@ Can be used to give options in the format used by OpenSSH config file. This is useful for specifying options for which there is no separate command-line flag. For full details of the options listed below, and their possible values, see ssh_config(5). +The following options have currently been implemented: -For now following options have been implemented: .RS .TP .B ExitOnForwardFailure @@ -147,6 +147,10 @@ Send dbclient log messages to syslog in addition to stderr. .B \-s The specified command will be requested as a subsystem, used for sftp. Dropbear doesn't implement sftp itself but the OpenSSH sftp client can be used eg \fIsftp -S dbclient user@host\fR .TP +.B \-b \fI[address][:port] +Bind to a specific local address when connecting to the remote host. This can be used to choose from +multiple outgoing interfaces. Either address or port (or both) can be given. +.TP .B \-V Print the version diff --git a/netio.c b/netio.c index b594e84..04413e1 100644 --- a/netio.c +++ b/netio.c @@ -19,7 +19,7 @@ struct dropbear_progress_connection { int sock; char* errstring; - struct addrinfo *bind_addrinfo; + char *bind_address, *bind_port; }; /* Deallocate a progress connection. Removes from the pending list if iter!=NULL. @@ -31,7 +31,8 @@ static void remove_connect(struct dropbear_progress_connection *c, m_list_elem * m_free(c->remotehost); m_free(c->remoteport); m_free(c->errstring); - if (c->bind_addrinfo) freeaddrinfo(c->bind_addrinfo); + m_free(c->bind_address); + m_free(c->bind_port); m_free(c); if (iter) { @@ -53,6 +54,7 @@ void cancel_connect(struct dropbear_progress_connection *c) { static void connect_try_next(struct dropbear_progress_connection *c) { struct addrinfo *r; + int err; int res = 0; int fastopen = 0; #if DROPBEAR_CLIENT_TCP_FAST_OPEN @@ -68,11 +70,38 @@ static void connect_try_next(struct dropbear_progress_connection *c) { continue; } - if (c->bind_addrinfo) { - if (bind(c->sock, c->bind_addrinfo->ai_addr, c->bind_addrinfo->ai_addrlen) < 0) { + if (c->bind_address || c->bind_port) { + /* bind to a source port/address */ + struct addrinfo hints; + struct addrinfo *bindaddr = NULL; + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = r->ai_family; + hints.ai_flags = AI_PASSIVE; + + err = getaddrinfo(c->bind_address, c->bind_port, &hints, &bindaddr); + if (err) { + int len = 100 + strlen(gai_strerror(err)); + m_free(c->errstring); + c->errstring = (char*)m_malloc(len); + snprintf(c->errstring, len, "Error resolving bind address '%s' (port %s). %s", + c->bind_address, c->bind_port, gai_strerror(err)); + TRACE(("Error resolving bind: %s", gai_strerror(err))) + close(c->sock); + c->sock = -1; + continue; + } + res = bind(c->sock, bindaddr->ai_addr, bindaddr->ai_addrlen); + freeaddrinfo(bindaddr); + bindaddr = NULL; + if (res < 0) { /* failure */ + int keep_errno = errno; + int len = 300; m_free(c->errstring); - c->errstring = m_strdup(strerror(errno)); + c->errstring = m_malloc(len); + snprintf(c->errstring, len, "Error binding local address '%s' (port %s). %s", + c->bind_address, c->bind_port, strerror(keep_errno)); close(c->sock); c->sock = -1; continue; @@ -143,7 +172,8 @@ static void connect_try_next(struct dropbear_progress_connection *c) { /* Connect via TCP to a host. */ struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport, - connect_callback cb, void* cb_data, char* bind_address) + connect_callback cb, void* cb_data, + const char* bind_address, const char* bind_port) { struct dropbear_progress_connection *c = NULL; int err; @@ -155,7 +185,6 @@ struct dropbear_progress_connection *connect_remote(const char* remotehost, cons c->sock = -1; c->cb = cb; c->cb_data = cb_data; - c->bind_addrinfo = NULL; list_append(&ses.conn_pending, c); @@ -175,20 +204,11 @@ struct dropbear_progress_connection *connect_remote(const char* remotehost, cons c->res_iter = c->res; } - if (NULL != bind_address) { - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = AF_UNSPEC; - err = getaddrinfo(bind_address, NULL, &hints, &c->bind_addrinfo); - if (err) { - int len; - len = 100 + strlen(gai_strerror(err)); - c->errstring = (char*)m_malloc(len); - snprintf(c->errstring, len, "Error resolving '%s'. %s", - bind_address, gai_strerror(err)); - TRACE(("Error resolving: %s", gai_strerror(err))) - c->res_iter = NULL; - } + if (bind_address) { + c->bind_address = m_strdup(bind_address); + } + if (bind_port) { + c->bind_port = m_strdup(bind_port); } return c; diff --git a/netio.h b/netio.h index 4e627cb..d61ef5e 100644 --- a/netio.h +++ b/netio.h @@ -30,7 +30,7 @@ typedef void(*connect_callback)(int result, int sock, void* data, const char* er /* Always returns a progress connection, if it fails it will call the callback at a later point */ struct dropbear_progress_connection * connect_remote (const char* remotehost, const char* remoteport, - connect_callback cb, void *cb_data, char* bind_address); + connect_callback cb, void *cb_data, const char* bind_address, const char* bind_port); /* Sets up for select() */ void set_connect_fds(fd_set *writefd); diff --git a/runopts.h b/runopts.h index 5fa8c61..770ae8f 100644 --- a/runopts.h +++ b/runopts.h @@ -168,6 +168,7 @@ typedef struct cli_runopts { char *proxycmd; #endif char *bind_address; + char *bind_port; } cli_runopts; extern cli_runopts cli_opts; diff --git a/svr-tcpfwd.c b/svr-tcpfwd.c index fc3f46e..480beb6 100644 --- a/svr-tcpfwd.c +++ b/svr-tcpfwd.c @@ -285,7 +285,7 @@ static int newtcpdirect(struct Channel * channel) { } snprintf(portstring, sizeof(portstring), "%u", destport); - channel->conn_pending = connect_remote(desthost, portstring, channel_connect_done, channel, NULL); + channel->conn_pending = connect_remote(desthost, portstring, channel_connect_done, channel, NULL, NULL); channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE; -- cgit v1.2.3