summaryrefslogtreecommitdiffhomepage
path: root/netio.c
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2018-01-26 00:32:39 +0800
committerMatt Johnston <matt@ucc.asn.au>2018-01-26 00:32:39 +0800
commitb65354d2375affd3032c94c372b0cc74cb4acedc (patch)
treeffad8dc3321a7f3b60bef90a7d27ff504222711f /netio.c
parent917722257d11ea7a33990c170542aeff2b6061b1 (diff)
parente4ac7ea1ca910e0d245232a8ab16415f252b006b (diff)
Merge branch 'houseofkodai-cli_bind_address_connect'
Diffstat (limited to 'netio.c')
-rw-r--r--netio.c52
1 files changed, 51 insertions, 1 deletions
diff --git a/netio.c b/netio.c
index 2f37e70..04413e1 100644
--- a/netio.c
+++ b/netio.c
@@ -19,6 +19,7 @@ struct dropbear_progress_connection {
int sock;
char* errstring;
+ char *bind_address, *bind_port;
};
/* Deallocate a progress connection. Removes from the pending list if iter!=NULL.
@@ -30,6 +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);
+ m_free(c->bind_address);
+ m_free(c->bind_port);
m_free(c);
if (iter) {
@@ -51,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
@@ -66,6 +70,44 @@ static void connect_try_next(struct dropbear_progress_connection *c) {
continue;
}
+ 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_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;
+ }
+ }
+
ses.maxfd = MAX(ses.maxfd, c->sock);
set_sock_nodelay(c->sock);
setnonblocking(c->sock);
@@ -130,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)
+ connect_callback cb, void* cb_data,
+ const char* bind_address, const char* bind_port)
{
struct dropbear_progress_connection *c = NULL;
int err;
@@ -160,6 +203,13 @@ struct dropbear_progress_connection *connect_remote(const char* remotehost, cons
} else {
c->res_iter = c->res;
}
+
+ if (bind_address) {
+ c->bind_address = m_strdup(bind_address);
+ }
+ if (bind_port) {
+ c->bind_port = m_strdup(bind_port);
+ }
return c;
}