summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli-main.c6
-rw-r--r--cli-runopts.c7
-rw-r--r--cli-tcpfwd.c2
-rw-r--r--netio.c32
-rw-r--r--netio.h2
-rw-r--r--runopts.h1
-rw-r--r--svr-tcpfwd.c2
7 files changed, 42 insertions, 10 deletions
diff --git a/cli-main.c b/cli-main.c
index 57a07cc..d541e2a 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'", cli_opts.username,
- cli_opts.remotehost, cli_opts.remoteport))
+ TRACE(("user='%s' host='%s' port='%s' bind_address='%s'", cli_opts.username,
+ cli_opts.remotehost, cli_opts.remoteport, cli_opts.bind_address))
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
dropbear_exit("signal() error");
@@ -86,7 +86,7 @@ int main(int argc, char ** argv) {
} else
#endif
{
- progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport, cli_connected, &ses);
+ progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport, cli_connected, &ses, cli_opts.bind_address);
sock_in = sock_out = -1;
}
diff --git a/cli-runopts.c b/cli-runopts.c
index ca50709..4057824 100644
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -92,6 +92,7 @@ static void printhelp() {
"-c <cipher list> Specify preferred ciphers ('-c help' to list options)\n"
"-m <MAC list> Specify preferred MACs for packet verification (or '-m help')\n"
#endif
+ "-b bind_address\n"
"-V Version\n"
#if DEBUG_TRACE
"-v verbose (compiled with DEBUG_TRACE)\n"
@@ -125,7 +126,6 @@ void cli_getopts(int argc, char ** argv) {
OPT_OTHER
} opt;
unsigned int cmdlen;
- char* dummy = NULL; /* Not used for anything real */
char* recv_window_arg = NULL;
char* keepalive_arg = NULL;
@@ -166,6 +166,7 @@ void cli_getopts(int argc, char ** argv) {
#if DROPBEAR_CLI_PROXYCMD
cli_opts.proxycmd = NULL;
#endif
+ cli_opts.bind_address = NULL;
#ifndef DISABLE_ZLIB
opts.compress_mode = DROPBEAR_COMPRESS_ON;
#endif
@@ -314,8 +315,8 @@ void cli_getopts(int argc, char ** argv) {
exit(EXIT_SUCCESS);
break;
case 'b':
- next = &dummy;
- /* FALLTHROUGH */
+ next = &cli_opts.bind_address;
+ break;
default:
fprintf(stderr,
"WARNING: Ignoring unknown option -%c\n", c);
diff --git a/cli-tcpfwd.c b/cli-tcpfwd.c
index 78f61f7..b9ea91e 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);
+ channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel, NULL);
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
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;
}
diff --git a/netio.h b/netio.h
index 090df3d..4e627cb 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);
+ connect_callback cb, void *cb_data, char* bind_address);
/* Sets up for select() */
void set_connect_fds(fd_set *writefd);
diff --git a/runopts.h b/runopts.h
index 47c12f0..5fa8c61 100644
--- a/runopts.h
+++ b/runopts.h
@@ -167,6 +167,7 @@ typedef struct cli_runopts {
#if DROPBEAR_CLI_PROXYCMD
char *proxycmd;
#endif
+ char *bind_address;
} cli_runopts;
extern cli_runopts cli_opts;
diff --git a/svr-tcpfwd.c b/svr-tcpfwd.c
index c592afb..fc3f46e 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);
+ channel->conn_pending = connect_remote(desthost, portstring, channel_connect_done, channel, NULL);
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;