diff options
author | houseofkodai <karthik@houseofkodai.in> | 2018-01-25 19:51:41 +0530 |
---|---|---|
committer | Matt Johnston <matt@ucc.asn.au> | 2018-01-25 22:21:41 +0800 |
commit | 917722257d11ea7a33990c170542aeff2b6061b1 (patch) | |
tree | 0825c8163b8ec62ad32039d7e97e9960302e631a /netio.c | |
parent | 3d61b6eab69a9a2453e4fb807159f28c9490312a (diff) |
Server chosen tcpfwd ports (#43)
Server chosen tcpfwd ports
Diffstat (limited to 'netio.c')
-rw-r--r-- | netio.c | 53 |
1 files changed, 53 insertions, 0 deletions
@@ -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++; |