X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/preload-hacks/blobdiff_plain/6ec34720b0d2effe661c9dd4da2ef47a4e5030e3..54ef96bf3ee587718974b094f64fbff1301cc997:/noip.c diff --git a/noip.c b/noip.c index 0063ee9..345f325 100644 --- a/noip.c +++ b/noip.c @@ -57,9 +57,19 @@ #include #include +#ifndef SUN_LEN +# define SUN_LEN (sun) \ + (strlen((sun)->sun_path) + offsetof(struct sockaddr_un, sun_path)) +#endif + /*----- Data structures ---------------------------------------------------*/ -enum { UNUSED, STALE, USED }; /* Unix socket status values */ +/* Unix socket status values. */ +#define UNUSED 0u /* No sign of anyone using it */ +#define STALE 1u /* Socket exists, but is abandoned */ +#define USED 16u /* Socket is in active use */ +#define LISTEN 2u /* Socket has an active listener */ + enum { DENY, ALLOW }; /* ACL verdicts */ static int address_families[] = { AF_INET, AF_INET6, -1 }; @@ -676,6 +686,7 @@ static int unix_socket_status(struct sockaddr_un *sun, int quickp) FILE *fp = 0; size_t len, n; int rc; + unsigned long f; char buf[256]; /* If we can't find the socket node, then it's definitely not in use. If @@ -700,15 +711,19 @@ static int unix_socket_status(struct sockaddr_un *sun, int quickp) goto done; if (!fgets(buf, sizeof(buf), fp)) goto done; /* skip header */ len = strlen(sun->sun_path); + rc = 0; while (fgets(buf, sizeof(buf), fp)) { n = strlen(buf); if (n >= len + 2 && buf[n - len - 2] == ' ' && buf[n - 1] == '\n' && - memcmp(buf + n - len - 1, sun->sun_path, len) == 0) - goto done; + memcmp(buf + n - len - 1, sun->sun_path, len) == 0) { + rc |= USED; + if (sscanf(buf, "%*s %*x %*x %lx", &f) < 0 || (f&0x00010000)) + rc |= LISTEN; + } } if (ferror(fp)) goto done; - rc = STALE; + if (!rc) rc = STALE; done: if (fp) fclose(fp); @@ -728,9 +743,9 @@ static int encode_single_inet_addr(const struct sockaddr *sa, snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s", sockdir, present_sockaddr(sa, 0, buf, sizeof(buf))); - if ((rc = unix_socket_status(sun, quickp)) == USED) return (USED); - else if (rc == STALE) unlink(sun->sun_path); - return (UNUSED); + rc = unix_socket_status(sun, quickp); + if (rc == STALE) unlink(sun->sun_path); + return (rc); } /* Convert the IP address SA to a Unix-domain address SUN. Fail if the @@ -749,7 +764,7 @@ static int encode_unused_inet_addr(struct sockaddr *sa, * desperate. If the socket is in use, we fail here. (This could get * racy. Let's not worry about that for now.) */ - if (encode_single_inet_addr(sa, sun, !desperatep) == USED) + if (encode_single_inet_addr(sa, sun, !desperatep)&USED) return (-1); /* Next, check the corresponding wildcard address, so as to avoid @@ -757,7 +772,7 @@ static int encode_unused_inet_addr(struct sockaddr *sa, */ wildcard_address(sa->sa_family, &waddr.sa); port_to_sockaddr(&waddr.sa, port); - if (encode_single_inet_addr(&waddr.sa, &wsun, !desperatep) == USED) + if (encode_single_inet_addr(&waddr.sa, &wsun, !desperatep)&USED) return (-1); /* We're not done yet. If this is an IPv4 address, then /also/ check (a) @@ -766,16 +781,16 @@ static int encode_unused_inet_addr(struct sockaddr *sa, */ if (sa->sa_family == AF_INET) { map_ipv4_sockaddr(&maddr.sin6, SIN(&sa)); - if (encode_single_inet_addr(&maddr.sa, &wsun, !desperatep) == USED) + if (encode_single_inet_addr(&maddr.sa, &wsun, !desperatep)&USED) return (-1); map_ipv4_sockaddr(&maddr.sin6, &waddr.sin); - if (encode_single_inet_addr(&maddr.sa, &wsun, !desperatep) == USED) + if (encode_single_inet_addr(&maddr.sa, &wsun, !desperatep)&USED) return (-1); wildcard_address(AF_INET6, &waddr.sa); port_to_sockaddr(&waddr.sa, port); - if (encode_single_inet_addr(&waddr.sa, &wsun, !desperatep) == USED) + if (encode_single_inet_addr(&waddr.sa, &wsun, !desperatep)&USED) return (-1); } @@ -790,6 +805,7 @@ static int encode_unused_inet_addr(struct sockaddr *sa, * Returns zero on success; -1 on failure. */ #define ENCF_FRESH 1u +#define ENCF_REUSEADDR 2u static int encode_inet_addr(struct sockaddr_un *sun, const struct sockaddr *sa, unsigned f) @@ -799,6 +815,7 @@ static int encode_inet_addr(struct sockaddr_un *sun, address addr; struct sockaddr_in6 sin6; int port = port_from_sockaddr(sa); + int rc; char buf[ADDRBUFSZ]; D( fprintf(stderr, "noip(%d): encode %s (%s)", getpid(), @@ -813,8 +830,9 @@ static int encode_inet_addr(struct sockaddr_un *sun, /* Try the address as given. If it's in use, or we don't necessarily * want an existing socket, then we're done. */ - if (encode_single_inet_addr(sa, sun, 0) == USED || (f&ENCF_FRESH)) - goto found; + rc = encode_single_inet_addr(sa, sun, 0); + if ((f&ENCF_REUSEADDR) && !(rc&LISTEN)) unlink(sun->sun_path); + if ((rc&USED) || (f&ENCF_FRESH)) goto found; /* We're looking for a socket which already exists. This is * unfortunately difficult, because we must deal both with wildcards and @@ -836,19 +854,19 @@ static int encode_inet_addr(struct sockaddr_un *sun, if (sa->sa_family == AF_INET) { map_ipv4_sockaddr(&addr.sin6, SIN(sa)); - if (encode_single_inet_addr(&addr.sa, sun, 0) == USED) goto found; + if (encode_single_inet_addr(&addr.sa, sun, 0)&USED) goto found; } wildcard_address(sa->sa_family, &addr.sa); port_to_sockaddr(&addr.sa, port); - if (encode_single_inet_addr(&addr.sa, sun, 0) == USED) goto found; + if (encode_single_inet_addr(&addr.sa, sun, 0)&USED) goto found; if (sa->sa_family == AF_INET) { map_ipv4_sockaddr(&sin6, &addr.sin); - if (encode_single_inet_addr(SA(&sin6), sun, 0) == USED) goto found; + if (encode_single_inet_addr(SA(&sin6), sun, 0)&USED) goto found; wildcard_address(AF_INET6, &addr.sa); port_to_sockaddr(&addr.sa, port); - if (encode_single_inet_addr(&addr.sa, sun, 0) == USED) goto found; + if (encode_single_inet_addr(&addr.sa, sun, 0)&USED) goto found; } /* Well, this isn't going to work (unless a miraculous race is lost), but @@ -1109,7 +1127,11 @@ static int do_implicit_bind(int sk, const struct sockaddr *sa, unsigned f) sockaddr_in_range_p(sa, &i->minaddr, &i->maxaddr)) { D( fprintf(stderr, "noip(%d): match!\n", pid); ) addr.sa.sa_family = sa->sa_family; - ipaddr_to_sockaddr(&addr.sa, &i->bindaddr); + switch (i->how) { + case EXPLICIT: ipaddr_to_sockaddr(&addr.sa, &i->bindaddr); break; + case SAME: copy_sockaddr(&addr.sa, sa); break; + } + port_to_sockaddr(&addr.sa, 0); goto found; } } @@ -1712,6 +1734,9 @@ int bind(int sk, const struct sockaddr *sa, socklen_t len) { struct sockaddr_un sun; int rc; + unsigned f; + int reusep; + socklen_t n; Dpid; D({ char buf[ADDRBUFSZ]; @@ -1727,7 +1752,11 @@ int bind(int sk, const struct sockaddr *sa, socklen_t len) if (fixup_real_ip_socket(sk, sa->sa_family, 0)) return (-1); } else { - encode_inet_addr(&sun, sa, ENCF_FRESH); + f = ENCF_FRESH; + n = sizeof(reusep); + if (!getsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &reusep, &n) && reusep) + f |= ENCF_REUSEADDR; + encode_inet_addr(&sun, sa, f); sa = SA(&sun); len = SUN_LEN(&sun); } @@ -1945,7 +1974,7 @@ int getpeername(int sk, struct sockaddr *sa, socklen_t *len) D( fprintf(stderr, "noip(%d): ... GETPEERNAME", pid); ) } D( dump_addrresult(rc, sa, *len); ) - return (0); + return (rc); } int getsockopt(int sk, int lev, int opt, void *p, socklen_t *len)