X-Git-Url: https://git.distorted.org.uk/~mdw/preload-hacks/blobdiff_plain/0a6ab6a1d1582739baebed08932cb89878c38a65..7be80f86f3c9a5793f218143888fb2be734ae749:/noip.c diff --git a/noip.c b/noip.c index 423822d..085b0be 100644 --- a/noip.c +++ b/noip.c @@ -89,6 +89,14 @@ typedef struct aclnode { unsigned short minport, maxport; } aclnode; +/* Implicit bind records */ +typedef struct impbind { + struct impbind *next; + int af, how; + ipaddr minaddr, maxaddr, bindaddr; +} impbind; +enum { EXPLICIT, SAME }; + /* A type for an address range */ typedef struct addrrange { int type; @@ -116,6 +124,7 @@ static unsigned minautoport = 16384, maxautoport = 65536; /* Access control lists */ static aclnode *bind_real, **bind_tail = &bind_real; static aclnode *connect_real, **connect_tail = &connect_real; +static impbind *impbinds, **impbind_tail = &impbinds; /*----- Import the real versions of functions -----------------------------*/ @@ -309,6 +318,23 @@ static void ipaddr_from_sockaddr(ipaddr *a, const struct sockaddr *sa) } } +/* Store the address A in SA. */ +static void ipaddr_to_sockaddr(struct sockaddr *sa, const ipaddr *a) +{ + switch (sa->sa_family) { + case AF_INET: + SIN(sa)->sin_addr = a->v4; + break; + case AF_INET6: + SIN6(sa)->sin6_addr = a->v6; + SIN6(sa)->sin6_scope_id = 0; + SIN6(sa)->sin6_flowinfo = 0; + break; + default: + abort(); + } +} + /* Copy a whole socket address about. */ static void copy_sockaddr(struct sockaddr *sa_dst, const struct sockaddr *sa_src) @@ -825,6 +851,58 @@ static int fixup_real_ip_socket(int sk, int af_hint, int *tmp) return (0); } +/* We found the real address SA, with length LEN; if it's a Unix-domain + * address corresponding to a fake socket, convert it to cover up the + * deception. Whatever happens, put the result at FAKE and store its length + * at FAKELEN. + */ +static void return_fake_name(struct sockaddr *sa, socklen_t len, + struct sockaddr *fake, socklen_t *fakelen) +{ + address addr; + socklen_t alen; + + if (sa->sa_family == AF_UNIX && + !decode_inet_addr(&addr.sa, 0, SUN(sa), len)) { + sa = &addr.sa; + len = family_socklen(addr.sa.sa_family); + } + alen = len; + if (len > *fakelen) len = *fakelen; + if (len > 0) memcpy(fake, sa, len); + *fakelen = alen; +} + +/*----- Implicit binding --------------------------------------------------*/ + +#ifdef DEBUG + +static void dump_impbind(const impbind *i) +{ + char buf[ADDRBUFSZ]; + + fprintf(stderr, "noip(%d): ", getpid()); + dump_addrrange(i->af, &i->minaddr, &i->maxaddr); + switch (i->how) { + case SAME: fprintf(stderr, " "); break; + case EXPLICIT: + fprintf(stderr, " %s", inet_ntop(i->af, &i->bindaddr, + buf, sizeof(buf))); + break; + default: abort(); + } + fputc('\n', stderr); +} + +static void dump_impbind_list(void) +{ + const impbind *i; + + for (i = impbinds; i; i = i->next) dump_impbind(i); +} + +#endif + /* The socket SK is about to be used to communicate with the remote address * SA. Assign it a local address so that getpeername(2) does something * useful. @@ -834,6 +912,8 @@ static int do_implicit_bind(int sk, const struct sockaddr **sa, { address addr; socklen_t mylen = sizeof(*sun); + const impbind *i; + Dpid; if (acl_allows_p(connect_real, *sa)) { if (fixup_real_ip_socket(sk, (*sa)->sa_family, 0)) return (-1); @@ -842,7 +922,20 @@ static int do_implicit_bind(int sk, const struct sockaddr **sa, if (sun->sun_family == AF_UNIX) { if (mylen < sizeof(*sun)) ((char *)sun)[mylen] = 0; if (!sun->sun_path[0]) { + D( fprintf(stderr, "noip(%d): checking impbind list...\n", pid); ) + for (i = impbinds; i; i = i->next) { + D( dump_impbind(i); ) + if ((*sa)->sa_family == i->af && + 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); + goto found; + } + } + D( fprintf(stderr, "noip(%d): no match; using wildcard\n", pid); ) wildcard_address((*sa)->sa_family, &addr.sa); + found: encode_inet_addr(sun, &addr.sa, WANT_FRESH); if (real_bind(sk, SA(sun), SUN_LEN(sun))) return (-1); } @@ -854,28 +947,6 @@ static int do_implicit_bind(int sk, const struct sockaddr **sa, return (0); } -/* We found the real address SA, with length LEN; if it's a Unix-domain - * address corresponding to a fake socket, convert it to cover up the - * deception. Whatever happens, put the result at FAKE and store its length - * at FAKELEN. - */ -static void return_fake_name(struct sockaddr *sa, socklen_t len, - struct sockaddr *fake, socklen_t *fakelen) -{ - address addr; - socklen_t alen; - - if (sa->sa_family == AF_UNIX && - !decode_inet_addr(&addr.sa, 0, SUN(sa), len)) { - sa = &addr.sa; - len = family_socklen(addr.sa.sa_family); - } - alen = len; - if (len > *fakelen) len = *fakelen; - if (len > 0) memcpy(fake, sa, len); - *fakelen = alen; -} - /*----- Configuration -----------------------------------------------------*/ /* Return the process owner's home directory. */ @@ -1159,6 +1230,82 @@ static void parse_acl_env(const char *var, aclnode ***tail) } } +struct add_impbind_ctx { + int af, how; + ipaddr addr; +}; + +static void add_impbind(int af, const ipaddr *min, const ipaddr *max, + void *p) +{ + struct add_impbind_ctx *ctx = p; + impbind *i; + + if (ctx->af && af != ctx->af) return; + NEW(i); + i->af = af; + i->how = ctx->how; + i->minaddr = *min; i->maxaddr = *max; + switch (ctx->how) { + case EXPLICIT: i->bindaddr = ctx->addr; + case SAME: break; + default: abort(); + } + *impbind_tail = i; impbind_tail = &i->next; +} + +/* Parse an implicit-bind line. An implicit-bind entry has the form + * ADDR-RANGE {ADDR | same} + */ +static void parse_impbind_line(char **pp) +{ + struct add_impbind_ctx ctx; + char *p = *pp, *q; + addrrange r; + int del; + + for (;;) { + if (parse_addrrange(&p, &r)) goto bad; + SKIPSPC; + if (KWMATCHP("same")) { + ctx.how = SAME; + ctx.af = 0; + } else { + ctx.how = EXPLICIT; + parse_nextaddr(&p, &q, &del); + ctx.af = guess_address_family(q); + if (inet_pton(ctx.af, q, &ctx.addr) < 0) goto bad; + RESCAN(del); + } + foreach_addrrange(&r, add_impbind, &ctx); + SKIPSPC; + if (*p != ',') break; + if (*p) p++; + } + if (*p) goto bad; + *pp = p; + return; + +bad: + D( fprintf(stderr, "noip(%d): bad implicit-bind spec (ignored)\n", + getpid()); ) + return; +} + +/* Parse implicit-bind instructions from an environment variable VAR, + * attaching it to the list. + */ +static void parse_impbind_env(const char *var) +{ + char *p, *q; + + if ((p = getenv(var)) != 0) { + p = q = xstrdup(p); + parse_impbind_line(&q); + free(p); + } +} + /* Parse the autoports configuration directive. Syntax is MIN - MAX. */ static void parse_autoports(char **pp) { @@ -1192,6 +1339,7 @@ static void readconfig(void) parse_acl_env("NOIP_REALBIND_BEFORE", &bind_tail); parse_acl_env("NOIP_REALCONNECT_BEFORE", &connect_tail); + parse_impbind_env("NOIP_IMPBIND_BEFORE"); if ((p = getenv("NOIP_AUTOPORTS")) != 0) { p = q = xstrdup(p); parse_autoports(&q); @@ -1223,22 +1371,27 @@ static void readconfig(void) parse_acl_line(&p, &bind_tail); else if (strcmp(cmd, "realconnect") == 0) parse_acl_line(&p, &connect_tail); + else if (strcmp(cmd, "impbind") == 0) + parse_impbind_line(&p); else if (strcmp(cmd, "autoports") == 0) parse_autoports(&p); else if (strcmp(cmd, "debug") == 0) debug = *p ? atoi(p) : 1; else - D( fprintf(stderr, "noip: bad config command %s\n", cmd); ) + D( fprintf(stderr, "noip(%d): bad config command %s\n", pid, cmd); ) } fclose(fp); done: parse_acl_env("NOIP_REALBIND", &bind_tail); parse_acl_env("NOIP_REALCONNECT", &connect_tail); + parse_impbind_env("NOIP_IMPBIND"); parse_acl_env("NOIP_REALBIND_AFTER", &bind_tail); parse_acl_env("NOIP_REALCONNECT_AFTER", &connect_tail); + parse_impbind_env("NOIP_IMPBIND_AFTER"); *bind_tail = 0; *connect_tail = 0; + *impbind_tail = 0; if (!sockdir) sockdir = getenv("NOIP_SOCKETDIR"); if (!sockdir) { snprintf(buf, sizeof(buf), "%s/noip-%s", tmpdir(), user()); @@ -1250,7 +1403,9 @@ done: fprintf(stderr, "noip(%d): realbind acl:\n", pid); dump_acl(bind_real); fprintf(stderr, "noip(%d): realconnect acl:\n", pid); - dump_acl(connect_real); ) + dump_acl(connect_real); + fprintf(stderr, "noip(%d): impbind list:\n", pid); + dump_impbind_list(); ) } /*----- Overridden system calls -------------------------------------------*/