summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--netio.c19
-rw-r--r--netio.h2
-rw-r--r--runopts.h1
-rw-r--r--svr-main.c2
-rw-r--r--svr-runopts.c26
-rw-r--r--svr-session.c1
-rw-r--r--tcp-accept.c2
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);