From 224a8c55e09a455feddbaf41f44a60683d72f37f Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Tue, 25 Jul 2023 21:50:22 +0000 Subject: WIP bindtodevice --- netio.c | 19 ++++++++++++++++++- netio.h | 2 +- runopts.h | 1 + svr-main.c | 2 +- svr-runopts.c | 26 +++++++++++++++++++++++++- svr-session.c | 1 + tcp-accept.c | 2 +- 7 files changed, 48 insertions(+), 5 deletions(-) diff --git a/netio.c b/netio.c index 0d69d3a..50d1e23 100644 --- a/netio.c +++ b/netio.c @@ -350,6 +350,18 @@ void set_sock_nodelay(int sock) { setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val)); } +int set_sock_bindtodevice(int sock, const char* device) { +#ifdef SO_BINDTODEVICE + if (device && setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)) < 0) { + TRACE(("set_sock_bindtodevice(%s) failed for socket %d: %s", device, sock ,strerror(errno))) + } + return 0; +#else + TRACE(("set_sock_bindtodevice not supported")) + return -1; +#endif /* SO_BINDTODEVICE */ +} + #if DROPBEAR_SERVER_TCP_FAST_OPEN void set_listen_fast_open(int sock) { int qlen = MAX(MAX_UNAUTH_PER_IP, 5); @@ -451,7 +463,7 @@ int get_sock_port(int sock) { * Returns the number of sockets bound on success, or -1 on failure. On * failure, if errstring wasn't NULL, it'll be a newly malloced error * string.*/ -int dropbear_listen(const char* address, const char* port, +int dropbear_listen(const char* address, const char* port, const char* device, int *socks, unsigned int sockcount, char **errstring, int *maxfd) { struct addrinfo hints, *res = NULL, *res0 = NULL; @@ -551,6 +563,11 @@ int dropbear_listen(const char* address, const char* port, #endif set_sock_nodelay(sock); + if (device && set_sock_bindtodevice(sock, device) < 0) { + close(sock); + continue; + } + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { err = errno; close(sock); diff --git a/netio.h b/netio.h index d61ef5e..c006a1c 100644 --- a/netio.h +++ b/netio.h @@ -19,7 +19,7 @@ void get_socket_address(int fd, char **local_host, char **local_port, char **remote_host, char **remote_port, int host_lookup); void getaddrstring(struct sockaddr_storage* addr, char **ret_host, char **ret_port, int host_lookup); -int dropbear_listen(const char* address, const char* port, +int dropbear_listen(const char* address, const char* port, const char *device, int *socks, unsigned int sockcount, char **errstring, int *maxfd); struct dropbear_progress_connection; diff --git a/runopts.h b/runopts.h index af60877..9299711 100644 --- a/runopts.h +++ b/runopts.h @@ -77,6 +77,7 @@ typedef struct svr_runopts { char *ports[DROPBEAR_MAX_PORTS]; unsigned int portcount; char *addresses[DROPBEAR_MAX_PORTS]; + char *devices[DROPBEAR_MAX_PORTS]; int inetdmode; diff --git a/svr-main.c b/svr-main.c index 52ac9ff..b411799 100644 --- a/svr-main.c +++ b/svr-main.c @@ -417,7 +417,7 @@ static size_t listensockets(int *socks, size_t sockcount, int *maxfd) { TRACE(("listening on '%s:%s'", svr_opts.addresses[i], svr_opts.ports[i])) - nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], &socks[sockpos], + nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], svr_opts.devices[i], &socks[sockpos], sockcount - sockpos, &errstring, maxfd); diff --git a/svr-runopts.c b/svr-runopts.c index 36ea26b..af966fb 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -351,6 +351,7 @@ void svr_getopts(int argc, char ** argv) { if (svr_opts.portcount == 0) { svr_opts.ports[0] = m_strdup(DROPBEAR_DEFPORT); svr_opts.addresses[0] = m_strdup(DROPBEAR_DEFADDRESS); + svr_opts.devices[0] = NULL; svr_opts.portcount = 1; } @@ -437,6 +438,7 @@ void svr_getopts(int argc, char ** argv) { static void addportandaddress(const char* spec) { char *spec_copy = NULL, *myspec = NULL, *port = NULL, *address = NULL; + char *device = NULL; if (svr_opts.portcount < DROPBEAR_MAX_PORTS) { @@ -444,7 +446,8 @@ static void addportandaddress(const char* spec) { spec_copy = m_strdup(spec); myspec = spec_copy; - if (myspec[0] == '[') { + if ((myspec = strchr(myspec, '['))) { + myspec[0] = '\0'; myspec++; port = strchr(myspec, ']'); if (!port) { @@ -457,9 +460,26 @@ static void addportandaddress(const char* spec) { /* Missing port -> exit */ dropbear_exit("Missing port"); } + + device = spec_copy; + if (device[strlen(device)-1] == ':') + device[strlen(device)-1] = '\0'; } else { + myspec = spec_copy; + /* search for ':', that separates address and port */ port = strrchr(myspec, ':'); + + if (port) { + device = strchr(myspec, ':'); + if (port == device) { + device = NULL; + } else if (device) /* always true */ { + device[0] = '\0'; + myspec = device + 1; + device = spec_copy; + } + } } if (!port) { @@ -483,6 +503,10 @@ static void addportandaddress(const char* spec) { } svr_opts.ports[svr_opts.portcount] = m_strdup(port); svr_opts.addresses[svr_opts.portcount] = m_strdup(address); + if (device) + svr_opts.devices[svr_opts.portcount] = m_strdup(device); + else + svr_opts.devices[svr_opts.portcount] = NULL; svr_opts.portcount++; m_free(spec_copy); } diff --git a/svr-session.c b/svr-session.c index 6898828..3d4b465 100644 --- a/svr-session.c +++ b/svr-session.c @@ -299,6 +299,7 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) { for (i = 0; i < DROPBEAR_MAX_PORTS; i++) { m_free(svr_opts.addresses[i]); m_free(svr_opts.ports[i]); + m_free(svr_opts.devices[i]); } diff --git a/tcp-accept.c b/tcp-accept.c index 6578d71..3911c7c 100644 --- a/tcp-accept.c +++ b/tcp-accept.c @@ -123,7 +123,7 @@ int listen_tcpfwd(struct TCPListener* tcpinfo, struct Listener **ret_listener) { /* first we try to bind, so don't need to do so much cleanup on failure */ snprintf(portstring, sizeof(portstring), "%u", tcpinfo->listenport); - nsocks = dropbear_listen(tcpinfo->listenaddr, portstring, socks, + nsocks = dropbear_listen(tcpinfo->listenaddr, portstring, NULL, socks, DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd); if (nsocks < 0) { dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring); -- cgit v1.2.3