summaryrefslogtreecommitdiffhomepage
path: root/netio.c
diff options
context:
space:
mode:
authorhouseofkodai <karthik@houseofkodai.in>2018-01-25 19:51:41 +0530
committerMatt Johnston <matt@ucc.asn.au>2018-01-25 22:21:41 +0800
commit917722257d11ea7a33990c170542aeff2b6061b1 (patch)
tree0825c8163b8ec62ad32039d7e97e9960302e631a /netio.c
parent3d61b6eab69a9a2453e4fb807159f28c9490312a (diff)
Server chosen tcpfwd ports (#43)
Server chosen tcpfwd ports
Diffstat (limited to 'netio.c')
-rw-r--r--netio.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/netio.c b/netio.c
index 24bb1d2..2f37e70 100644
--- a/netio.c
+++ b/netio.c
@@ -348,6 +348,37 @@ void set_sock_priority(int sock, enum dropbear_prio prio) {
}
+/* from openssh/canohost.c avoid premature-optimization */
+int get_sock_port(int sock) {
+ struct sockaddr_storage from;
+ socklen_t fromlen;
+ char strport[NI_MAXSERV];
+ int r;
+
+ /* Get IP address of client. */
+ fromlen = sizeof(from);
+ memset(&from, 0, sizeof(from));
+ if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
+ TRACE(("getsockname failed: %d", errno))
+ return 0;
+ }
+
+ /* Work around Linux IPv6 weirdness */
+ if (from.ss_family == AF_INET6)
+ fromlen = sizeof(struct sockaddr_in6);
+
+ /* Non-inet sockets don't have a port number. */
+ if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
+ return 0;
+
+ /* Return port number. */
+ if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
+ strport, sizeof(strport), NI_NUMERICSERV)) != 0) {
+ TRACE(("netio.c/get_sock_port/getnameinfo NI_NUMERICSERV failed: %d", r))
+ }
+ return atoi(strport);
+}
+
/* Listen on address:port.
* Special cases are address of "" listening on everything,
* and address of NULL listening on localhost only.
@@ -400,11 +431,29 @@ int dropbear_listen(const char* address, const char* port,
return -1;
}
+ /*
+ * when listening on server-assigned-port 0
+ * the assigned ports may differ for address families (v4/v6)
+ * causing problems for tcpip-forward
+ * caller can do a get_socket_address to discover assigned-port
+ * hence, use same port for all address families
+ */
+ u_int16_t *allocated_lport_p = 0;
+ int allocated_lport = 0;
nsock = 0;
for (res = res0; res != NULL && nsock < sockcount;
res = res->ai_next) {
+ if (allocated_lport > 0) {
+ if (AF_INET == res->ai_family) {
+ allocated_lport_p = &((struct sockaddr_in *)res->ai_addr)->sin_port;
+ } else if (AF_INET6 == res->ai_family) {
+ allocated_lport_p = &((struct sockaddr_in6 *)res->ai_addr)->sin6_port;
+ }
+ *allocated_lport_p = htons(allocated_lport);
+ }
+
/* Get a socket */
socks[nsock] = socket(res->ai_family, res->ai_socktype,
res->ai_protocol);
@@ -451,6 +500,10 @@ int dropbear_listen(const char* address, const char* port,
continue;
}
+ if (0 == allocated_lport) {
+ allocated_lport = get_sock_port(sock);
+ }
+
*maxfd = MAX(*maxfd, sock);
nsock++;