X-Git-Url: https://git.distorted.org.uk/~mdw/preload-hacks/blobdiff_plain/a62e4eceee7363106e4b205e6446a1f476b69495..refs/tags/1.2.2:/noip.c diff --git a/noip.c b/noip.c index 2d5e932..aca7b75 100644 --- a/noip.c +++ b/noip.c @@ -59,7 +59,12 @@ /*----- 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 +681,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 +706,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 +738,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 +759,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 +767,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 +776,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 +800,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 +810,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 +825,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 +849,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 @@ -1712,6 +1725,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 +1743,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); } @@ -1812,14 +1832,14 @@ ssize_t recvfrom(int sk, void *buf, size_t len, int flags, D( fprintf(stderr, " -> null addr; pass through"); ) n = real_recvfrom(sk, buf, len, flags, 0, 0); } else { - PRESERVING_ERRNO({ - n = real_recvfrom(sk, buf, len, flags, SA(sabuf), &mylen); - if (n >= 0) { - D( fprintf(stderr, " -> converting...\n"); ) + n = real_recvfrom(sk, buf, len, flags, SA(sabuf), &mylen); + if (n >= 0) { + D( fprintf(stderr, " -> converting...\n"); ) + PRESERVING_ERRNO({ return_fake_peer(sk, SA(sabuf), mylen, from, fromlen); - D( fprintf(stderr, "noip(%d): ... RECVFROM", pid); ) - } - }); + }); + D( fprintf(stderr, "noip(%d): ... RECVFROM", pid); ) + } } D( dump_addrresult(n, from, fromlen ? *fromlen : 0); ) return (n); @@ -1874,18 +1894,18 @@ ssize_t recvmsg(int sk, struct msghdr *msg, int flags) D( fprintf(stderr, " -> null addr; pass through"); ) return (real_recvmsg(sk, msg, flags)); } else { - PRESERVING_ERRNO({ - msg->msg_name = sabuf; - msg->msg_namelen = sizeof(sabuf); - n = real_recvmsg(sk, msg, flags); - if (n >= 0) { - D( fprintf(stderr, " -> converting...\n"); ) + msg->msg_name = sabuf; + msg->msg_namelen = sizeof(sabuf); + n = real_recvmsg(sk, msg, flags); + if (n >= 0) { + D( fprintf(stderr, " -> converting...\n"); ) + PRESERVING_ERRNO({ return_fake_peer(sk, SA(sabuf), msg->msg_namelen, sa, &len); - D( fprintf(stderr, "noip(%d): ... RECVMSG", pid); ) - } - msg->msg_name = sa; - msg->msg_namelen = len; - }); + }); + } + D( fprintf(stderr, "noip(%d): ... RECVMSG", pid); ) + msg->msg_name = sa; + msg->msg_namelen = len; } D( dump_addrresult(n, sa, len); ) return (n); @@ -1945,7 +1965,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)