From f6e0ea86fb3c3acddcbeddf625953aa1526daf35 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Mon, 2 May 2016 22:35:42 +0100 Subject: [PATCH] noip.c (encode_inet_addr): Avoid collisions with wildcard addresses. If the caller is wanting to `encode' a currently floating socket (i.e., no explicit port number has been set and we're meant to pick one), then make sure we pick a port number which doesn't collide with either the chosen address /or/ the address-family wildcard address. Otherwise, we can get into the situation where process A listens on a floating socket with a wildcard address, tells process B which port was allocated, and then process B binds to localhost, tries to connect to A, and is stymied because B actually allocated the same port number itself. Really we ought to seed the RNG separately for each process. --- noip.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/noip.c b/noip.c index ee86680..de7cf89 100644 --- a/noip.c +++ b/noip.c @@ -624,6 +624,34 @@ done: return (rc); } +/* Convert the IP address SA to a Unix-domain address SUN. Fail if the + * address seems already taken. If DESPARATEP then try cleaning up stale old + * sockets. + */ +static int encode_unused_inet_addr(struct sockaddr *sa, + struct sockaddr_un *sun, + int desperatep) +{ + address waddr; + struct sockaddr_un wsun; + int rc; + char buf[ADDRBUFSZ]; + + snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s", sockdir, + present_sockaddr(sa, 0, buf, sizeof(buf))); + if ((rc = unix_socket_status(sun, !desperatep)) == USED) return (-1); + else if (rc == STALE) unlink(sun->sun_path); + + wildcard_address(sa->sa_family, &waddr.sa); + port_to_sockaddr(&waddr.sa, port_from_sockaddr(sa)); + snprintf(wsun.sun_path, sizeof(wsun.sun_path), "%s/%s", sockdir, + present_sockaddr(&waddr.sa, 0, buf, sizeof(buf))); + if ((rc = unix_socket_status(&wsun, !desperatep)) == USED) return (-1); + else if (rc == STALE) unlink(wsun.sun_path); + + return (0); +} + /* Encode the Internet address SA as a Unix-domain address SUN. If WANT is * WANT_FRESH, and SA's port number is zero, then we pick an arbitrary local * port. Otherwise we pick the port given. There's an unpleasant hack to @@ -660,20 +688,12 @@ static int encode_inet_addr(struct sockaddr_un *sun, copy_sockaddr(&addr.sa, sa); for (i = 0; i < 10; i++) { port_to_sockaddr(&addr.sa, randrange(minautoport, maxautoport)); - snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s", sockdir, - present_sockaddr(&addr.sa, 0, buf, sizeof(buf))); - if (unix_socket_status(sun, 1) == UNUSED) goto found; + if (!encode_unused_inet_addr(&addr.sa, sun, 0)) goto found; } for (desperatep = 0; desperatep < 2; desperatep++) { for (i = minautoport; i <= maxautoport; i++) { port_to_sockaddr(&addr.sa, i); - snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s", sockdir, - present_sockaddr(&addr.sa, 0, buf, sizeof(buf))); - rc = unix_socket_status(sun, !desperatep); - switch (rc) { - case STALE: unlink(sun->sun_path); - case UNUSED: goto found; - } + if (!encode_unused_inet_addr(&addr.sa, sun, 0)) goto found; } } errno = EADDRINUSE; -- 2.11.0