From bf4d97617c92530ab67923aaba802333ee258352 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Thu, 18 Oct 2012 00:11:56 +0100 Subject: [PATCH] Dispatch to methods handling address-family specifics. This is a fairly invasive change to the program. Rather than carry around an address family type and switch on it throughout, carry around a pointer to a vtable containing methods. Methods needed by the system- specific machinery are properly integrated. --- Makefile.am | 1 + addr.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ linux.c | 78 ++++++++++++-------------------- policy.c | 92 ++++++++++++++------------------------ yaid.c | 144 ++++++++++++++++++++---------------------------------------- yaid.h | 84 +++++++++++++++++++++++++++-------- 6 files changed, 312 insertions(+), 223 deletions(-) create mode 100644 addr.c diff --git a/Makefile.am b/Makefile.am index 2c3f17b..ef046fb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,6 +41,7 @@ EXTRA_yaid_SOURCES = yaid_LDADD = $(mLib_LIBS) yaid_SOURCES += yaid.c +yaid_SOURCES += addr.c yaid_SOURCES += policy.c yaid_LDADD += $(SYS).$(OBJEXT) diff --git a/addr.c b/addr.c new file mode 100644 index 0000000..25211df --- /dev/null +++ b/addr.c @@ -0,0 +1,136 @@ +/* -*-c-*- + * + * Address-type specific functionality + * + * (c) 2012 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Yet Another Ident Daemon (YAID). + * + * YAID is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * YAID is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with YAID; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include "yaid.h" + +/*----- IPv4 addresses ----------------------------------------------------*/ + +static int addreq_ipv4(const union addr *a, const union addr *b) + { return a->ipv4.s_addr == b->ipv4.s_addr; } + +static int match_addrpat_ipv4(const struct addrpat *ap, const union addr *a) +{ + unsigned m; + + if (!ap->len) return (1); + m = htonl((MASK32 << (32 - ap->len)) & MASK32); + return (((ap->addr.ipv4.s_addr ^ a->ipv4.s_addr) & m) == 0); +} + +static void socket_to_sockaddr_ipv4(const struct socket *s, + void *sa, size_t *ssz) +{ + struct sockaddr_in *sin = sa; + + sin->sin_family = AF_INET; + sin->sin_addr = s->addr.ipv4; + sin->sin_port = htons(s->port); + *ssz = sizeof(*sin); +} + +static void sockaddr_to_addr_ipv4(const void *sa, union addr *a) + { const struct sockaddr_in *sin = sa; a->ipv4 = sin->sin_addr; } + +static int init_listen_socket_ipv4(int fd) { return (0); } + +static const union addr any_ipv4 = { .ipv4.s_addr = INADDR_ANY }; + +/*----- IPv6 addresses ----------------------------------------------------*/ + +static int addreq_ipv6(const union addr *a, const union addr *b) + { return !memcmp(a->ipv6.s6_addr, b->ipv6.s6_addr, 16); } + +static int match_addrpat_ipv6(const struct addrpat *ap, const union addr *a) +{ + unsigned i = 0, m, n = ap->len; + + if (!n) return (1); + for (i = 0; n >= 8; i++, n -= 8) + if (ap->addr.ipv6.s6_addr[i] != a->ipv6.s6_addr[i]) return (0); + if (!n) return (1); + m = (MASK8 << (8 - n)) & MASK8; + return (((ap->addr.ipv6.s6_addr[i] ^ a->ipv6.s6_addr[i]) & m) == 0); +} + +static void socket_to_sockaddr_ipv6(const struct socket *s, + void *sa, size_t *ssz) +{ + struct sockaddr_in6 *sin6 = sa; + + sin6->sin6_family = AF_INET6; + sin6->sin6_addr = s->addr.ipv6; + sin6->sin6_port = htons(s->port); + sin6->sin6_flowinfo = 0; + sin6->sin6_scope_id = 0; + *ssz = sizeof(*sin6); +} + +static void sockaddr_to_addr_ipv6(const void *sa, union addr *a) + { const struct sockaddr_in6 *sin6 = sa; a->ipv6 = sin6->sin6_addr; } + +static int init_listen_socket_ipv6(int fd) +{ + int yes = 1; + + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) + return (-1); + return (0); +} + +static const union addr any_ipv6 = { .ipv6 = IN6ADDR_ANY_INIT }; + +/*----- General utilities -------------------------------------------------*/ + +int sockeq(const struct addrops *ao, + const struct socket *sa, const struct socket *sb) + { return (ao->addreq(&sa->addr, &sb->addr) && sa->port == sb->port); } + +void dputsock(dstr *d, const struct addrops *ao, const struct socket *s) +{ + char buf[ADDRLEN]; + + inet_ntop(ao->af, &s->addr, buf, sizeof(buf)); + if (!s->port || ao->af != AF_INET6) dstr_puts(d, buf); + else { dstr_putc(d, '['); dstr_puts(d, buf); dstr_putc(d, ']'); } + if (s->port) dstr_putf(d, ":%d", s->port); +} + +/*----- The operations table ----------------------------------------------*/ + +const struct addrops addroptab[] = { +#define DEFOPS(ty, TY, af, name, len) \ + { AF_##af, name, len, &any_##ty, &addrops_sys_##ty, \ + addreq_##ty, match_addrpat_##ty, \ + socket_to_sockaddr_##ty, sockaddr_to_addr_##ty, \ + init_listen_socket_##ty }, +ADDRTYPES(DEFOPS) + { 0 } +#undef DEFOPS +}; + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/linux.c b/linux.c index 91c03aa..252b69c 100644 --- a/linux.c +++ b/linux.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * Discover the owner of a connection + * Discover the owner of a connection (Linux version) * * (c) 2012 Straylight/Edgeware */ @@ -30,19 +30,19 @@ /*----- Static variables --------------------------------------------------*/ -const char *const errtok[] = { -#define DEFTOK(err, tok) tok, - ERROR(DEFTOK) -#undef DEFTOK +struct addrops_sys { + const char *procfile; + int (*parseaddr)(char **, union addr *); }; -static int parseaddr4(char **pp, union addr *a) +static int parseaddr_ipv4(char **pp, union addr *a) { a->ipv4.s_addr = strtoul(*pp, pp, 16); return (0); } -static int addreq4(const union addr *a, const union addr *aa) - { return a->ipv4.s_addr == aa->ipv4.s_addr; } +const struct addrops_sys addrops_sys_ipv4 = { + "/proc/net/tcp", parseaddr_ipv4 +}; -static int parseaddr6(char **pp, union addr *a) +static int parseaddr_ipv6(char **pp, union addr *a) { int i, j; unsigned long y; @@ -65,27 +65,13 @@ static int parseaddr6(char **pp, union addr *a) return (0); } -static int addreq6(const union addr *a, const union addr *b) - { return !memcmp(a->ipv6.s6_addr, b->ipv6.s6_addr, 16); } - -static const struct addrfamily { - int af; - const char *procfile; - int (*parseaddr)(char **pp, union addr *a); - int (*addreq)(const union addr *a, const union addr *aa); -} addrfamilytab[] = { - { AF_INET, "/proc/net/tcp", parseaddr4, addreq4 }, - { AF_INET6, "/proc/net/tcp6", parseaddr6, addreq6 }, - { -1 } +const struct addrops_sys addrops_sys_ipv6 = { + "/proc/net/tcp6", parseaddr_ipv6 }; /*----- Main code ---------------------------------------------------------*/ -static int sockeq(const struct addrfamily *af, - const struct socket *sa, const struct socket *sb) - { return (af->addreq(&sa->addr, &sb->addr) && sa->port == sb->port); } - -static int get_default_gw(int af, union addr *a) +int get_default_gw(int af, union addr *a) { int fd; char buf[32768]; @@ -152,7 +138,6 @@ done: void identify(struct query *q) { - const struct addrfamily *af; FILE *fp = 0; dstr d = DSTR_INIT; char *p, *pp; @@ -170,19 +155,13 @@ void identify(struct query *q) enum { LOC, REM, ST, UID, NFIELD }; int f, ff[NFIELD]; - for (af = addrfamilytab; af->af >= 0; af++) - if (af->af == q->af) goto found_af; - logmsg(q, LOG_ERR, "unexpected address family `%d'", q->af); - goto err_unk; -found_af:; - - if (get_default_gw(q->af, &s[0].addr) && - af->addreq(&s[0].addr, &q->s[R].addr)) + if (get_default_gw(q->ao->af, &s[0].addr) && + q->ao->addreq(&s[0].addr, &q->s[R].addr)) gwp = 1; - if ((fp = fopen(af->procfile, "r")) == 0) { + if ((fp = fopen(q->ao->sys->procfile, "r")) == 0) { logmsg(q, LOG_ERR, "failed to open `%s' for reading: %s", - af->procfile, strerror(errno)); + q->ao->sys->procfile, strerror(errno)); goto err_unk; } @@ -194,7 +173,8 @@ found_af:; if (dstr_putline(&d, fp) == EOF) { logmsg(q, LOG_ERR, "failed to read header line from `%s': %s", - af->procfile, ferror(fp) ? strerror(errno) : "unexpected EOF"); + q->ao->sys->procfile, + ferror(fp) ? strerror(errno) : "unexpected EOF"); goto err_unk; } @@ -218,7 +198,7 @@ found_af:; for (i = 0; i < NFIELD; i++) { if (ff[i] < 0) { logmsg(q, LOG_ERR, "failed to find required fields in `%s'", - af->procfile); + q->ao->sys->procfile); goto err_unk; } } @@ -239,10 +219,10 @@ found_af:; continue; compare: - if (af->parseaddr(&p, &s[0].addr)) goto next_row; + if (q->ao->sys->parseaddr(&p, &s[0].addr)) goto next_row; if (*p != ':') break; p++; s[0].port = strtoul(p, 0, 16); - if (!sockeq(af, &q->s[i], &s[0]) && + if (!sockeq(q->ao, &q->s[i], &s[0]) && (i != R || !gwp || q->s[R].port != s[0].port)) goto next_row; } @@ -260,7 +240,7 @@ found_af:; goto err_unk; } - if (q->af == AF_INET) { + if (q->ao->af == AF_INET) { fclose(fp); if ((fp = fopen("/proc/net/ip_conntrack", "r")) == 0) { if (errno == ENOENT) @@ -309,13 +289,13 @@ found_af:; { dstr dd = DSTR_INIT; dstr_putf(&dd, "%sestab ", (fl & F_ESTAB) ? " " : "!"); - dputsock(&dd, af->af, &s[0]); + dputsock(&dd, q->ao, &s[0]); dstr_puts(&dd, "<->"); - dputsock(&dd, af->af, &s[1]); + dputsock(&dd, q->ao, &s[1]); dstr_puts(&dd, " | "); - dputsock(&dd, af->af, &s[2]); + dputsock(&dd, q->ao, &s[2]); dstr_puts(&dd, "<->"); - dputsock(&dd, af->af, &s[3]); + dputsock(&dd, q->ao, &s[3]); printf("parsed: %s\n", dd.buf); dstr_destroy(&dd); } @@ -324,12 +304,12 @@ found_af:; if (!(fl & F_ESTAB)) continue; for (i = 0; i < 4; i++) - if (sockeq(af, &s[i], &q->s[L])) goto found_local; + if (sockeq(q->ao, &s[i], &q->s[L])) goto found_local; continue; putchar('.'); found_local: - if (!sockeq(af, &s[i^1], &s[i^2]) || - !sockeq(af, &s[i^1], &q->s[R])) + if (!sockeq(q->ao, &s[i^1], &s[i^2]) || + !sockeq(q->ao, &s[i^1], &q->s[R])) continue; q->resp = R_NAT; q->u.nat = s[i^3]; diff --git a/policy.c b/policy.c index 398cd23..80e2bfd 100644 --- a/policy.c +++ b/policy.c @@ -28,10 +28,6 @@ #include "yaid.h" -/*----- Data structures ---------------------------------------------------*/ - -/*----- Static variables --------------------------------------------------*/ - /*----- Main code ---------------------------------------------------------*/ /* syntax: addrpat portpat addrpar portpat policy @@ -57,12 +53,17 @@ static void free_action(struct action *a) void free_policy(struct policy *p) { free_action(&p->act); } -static void print_addrpat(int af, const struct addrpat *ap) +static void print_addrpat(const struct addrops *ao, const struct addrpat *ap) { char buf[ADDRLEN]; - if (ap->len == 0) putchar('*'); - else printf("%s/%u", inet_ntop(af, &ap->addr, buf, sizeof(buf)), ap->len); + if (ap->len == 0) + putchar('*'); + else { + printf("%s/%u", + inet_ntop(ao->af, &ap->addr, buf, sizeof(buf)), + ap->len); + } } static void print_portpat(const struct portpat *pp) @@ -72,8 +73,8 @@ static void print_portpat(const struct portpat *pp) else printf("%u-%u", pp->lo, pp->hi); } -static void print_sockpat(int af, const struct sockpat *sp) - { print_addrpat(af, &sp->addr); putchar(' '); print_portpat(&sp->port); } +static void print_sockpat(const struct addrops *ao, const struct sockpat *sp) + { print_addrpat(ao, &sp->addr); putchar(' '); print_portpat(&sp->port); } static const char *const acttab[] = { #define DEFACT(tag, name) name, @@ -101,50 +102,26 @@ static void print_action(const struct action *act) void print_policy(const struct policy *p) { - print_sockpat(p->af, &p->sp[L]); putchar(' '); - print_sockpat(p->af, &p->sp[R]); putchar(' '); + print_sockpat(p->ao, &p->sp[L]); putchar(' '); + print_sockpat(p->ao, &p->sp[R]); putchar(' '); print_action(&p->act); putchar('\n'); } -static int match_addrpat(int af, const struct addrpat *ap, - const union addr *a) -{ - if (!ap->len) - return (1); - switch (af) { - case AF_INET: { - unsigned mask = htonl((MASK32 << (32 - ap->len)) & MASK32); - return (((ap->addr.ipv4.s_addr ^ a->ipv4.s_addr) & mask) == 0); - } - case AF_INET6: { - unsigned i, m, n = ap->len; - for (i = 0; n >= 8; i++, n -= 8) { - if (ap->addr.ipv6.s6_addr[i] != a->ipv6.s6_addr[i]) - return (0); - } - if (!n) return (1); - m = (MASK8 << (8 - n)) & MASK8; - return (((ap->addr.ipv6.s6_addr[i] ^ a->ipv6.s6_addr[i]) & m) == 0); - } - } - return (0); -} - static int match_portpat(const struct portpat *pp, unsigned port) { return (pp->lo <= port && port <= pp->hi); } -static int match_sockpat(int af, const struct sockpat *sp, - const struct socket *s) +static int match_sockpat(const struct addrops *ao, + const struct sockpat *sp, const struct socket *s) { - return (match_addrpat(af, &sp->addr, &s->addr) && + return (ao->match_addrpat(&sp->addr, &s->addr) && match_portpat(&sp->port, s->port)); } int match_policy(const struct policy *p, const struct query *q) { - return ((!p->af || p->af == q->af) && - match_sockpat(p->af, &p->sp[L], &q->s[L]) && - match_sockpat(p->af, &p->sp[R], &q->s[R])); + return ((!p->ao || p->ao == q->ao) && + match_sockpat(q->ao, &p->sp[L], &q->s[L]) && + match_sockpat(q->ao, &p->sp[R], &q->s[R])); } static void nextline(FILE *fp) @@ -255,12 +232,12 @@ static int parse_action(FILE *fp, struct action *act) return (0); } -static int parse_sockpat(FILE *fp, int *afp, struct sockpat *sp) +static int parse_sockpat(FILE *fp, const struct addrops **aop, + struct sockpat *sp) { char buf[64]; int t; - int af; - int alen; + const struct addrops *ao; long n; char *delim; @@ -268,21 +245,18 @@ static int parse_sockpat(FILE *fp, int *afp, struct sockpat *sp) if (strcmp(buf, "*") == 0) sp->addr.len = 0; else { - if (strchr(buf, ':')) { - af = AF_INET6; - alen = 128; - } else { - af = AF_INET; - alen = 32; - } - if (!*afp) *afp = af; - else if (*afp != af) return (T_ERROR); + if (strchr(buf, ':')) + ao = &addroptab[ADDR_IPV6]; + else + ao = &addroptab[ADDR_IPV4]; + if (!*aop) *aop = ao; + else if (*aop != ao) return (T_ERROR); delim = strchr(buf, '/'); if (delim) *delim++ = 0; - if (!inet_pton(af, buf, &sp->addr.addr)) return (T_ERROR); - if (!delim) n = alen; + if (!inet_pton(ao->af, buf, &sp->addr.addr)) return (T_ERROR); + if (!delim) n = ao->len; else n = strtol(delim, 0, 10); - if (n < 0 || n > alen) return (T_ERROR); + if (n < 0 || n > ao->len) return (T_ERROR); sp->addr.len = n; } @@ -311,11 +285,11 @@ int parse_policy(FILE *fp, struct policy *p) { int t; - p->af = 0; + p->ao = 0; free_policy(p); - if ((t = parse_sockpat(fp, &p->af, &p->sp[L])) != 0) goto fail; - if ((t = parse_sockpat(fp, &p->af, &p->sp[R])) != 0) goto err; + if ((t = parse_sockpat(fp, &p->ao, &p->sp[L])) != 0) goto fail; + if ((t = parse_sockpat(fp, &p->ao, &p->sp[R])) != 0) goto err; if ((t = parse_action(fp, &p->act)) != 0) goto err; return (0); diff --git a/yaid.c b/yaid.c index 4bb44fd..f70c2a3 100644 --- a/yaid.c +++ b/yaid.c @@ -31,8 +31,7 @@ /*----- Data structures ---------------------------------------------------*/ struct listen { - int af; - const char *proto; + const struct addrops *ao; sel_file f; }; @@ -76,48 +75,6 @@ static int randfd; /*----- Main code ---------------------------------------------------------*/ -static void socket_to_sockaddr(int af, const struct socket *s, - struct sockaddr *sa, size_t *ssz) -{ - sa->sa_family = af; - switch (af) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - sin->sin_addr = s->addr.ipv4; - sin->sin_port = htons(s->port); - *ssz = sizeof(*sin); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - sin6->sin6_addr = s->addr.ipv6; - sin6->sin6_port = htons(s->port); - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = 0; - *ssz = sizeof(*sin6); - } break; - default: abort(); - } -} - -static void sockaddr_to_addr(const struct sockaddr *sa, union addr *a) -{ - switch (sa->sa_family) { - case AF_INET: a->ipv4 = ((struct sockaddr_in *)sa)->sin_addr; break; - case AF_INET6: a->ipv6 = ((struct sockaddr_in6 *)sa)->sin6_addr; break; - default: abort(); - } -} - -static void dputsock(dstr *d, int af, const struct socket *s) -{ - char buf[ADDRLEN]; - - inet_ntop(af, &s->addr, buf, sizeof(buf)); - if (!s->port || af != AF_INET6) dstr_puts(d, buf); - else { dstr_putc(d, '['); dstr_puts(d, buf); dstr_putc(d, ']'); } - if (s->port) dstr_putf(d, ":%d", s->port); -} - void logmsg(const struct query *q, int prio, const char *msg, ...) { va_list ap; @@ -125,9 +82,9 @@ void logmsg(const struct query *q, int prio, const char *msg, ...) va_start(ap, msg); if (q) { - dputsock(&d, q->af, &q->s[L]); + dputsock(&d, q->ao, &q->s[L]); dstr_puts(&d, " <-> "); - dputsock(&d, q->af, &q->s[R]); + dputsock(&d, q->ao, &q->s[R]); dstr_puts(&d, ": "); } dstr_vputf(&d, msg, &ap); @@ -251,6 +208,12 @@ static void reply(struct client *c, const char *ty, const char *msg) c->q.s[L].port, c->q.s[R].port, ty, msg); } +const char *const errtok[] = { +#define DEFTOK(err, tok) tok, + ERROR(DEFTOK) +#undef DEFTOK +}; + static void reply_error(struct client *c, unsigned err) { assert(err < E_LIMIT); @@ -358,7 +321,7 @@ static void proxy_connected(int fd, void *p) if (fd < 0) { logmsg(&px->c->q, LOG_ERR, "failed to make %s proxy connection to %s: %s", - px->c->l->proto, px->nat, strerror(errno)); + px->c->l->ao->name, px->nat, strerror(errno)); reply_error(px->c, E_UNKNOWN); cancel_proxy(px); return; @@ -380,33 +343,31 @@ static void proxy_query(struct client *c) struct sockaddr_storage ss; size_t ssz; struct proxy *px; - int o; int fd; px = xmalloc(sizeof(*px)); - inet_ntop(c->q.af, &c->q.u.nat.addr, px->nat, sizeof(px->nat)); + inet_ntop(c->q.ao->af, &c->q.u.nat.addr, px->nat, sizeof(px->nat)); - if ((fd = socket(c->q.af, SOCK_STREAM, 0)) < 0) { + if ((fd = socket(c->q.ao->af, SOCK_STREAM, 0)) < 0) { logmsg(&c->q, LOG_ERR, "failed to make %s socket for proxy: %s", - c->l->proto, strerror(errno)); + c->l->ao->name, strerror(errno)); goto err_0; } - if ((o = fcntl(fd, F_GETFL)) < 0 || - fcntl(fd, F_SETFL, o | O_NONBLOCK)) { + if (fdflags(fd, O_NONBLOCK, O_NONBLOCK, 0, 0)) { logmsg(&c->q, LOG_ERR, "failed to set %s proxy socket nonblocking: %s", - c->l->proto, strerror(errno)); + c->l->ao->name, strerror(errno)); goto err_1; } s = c->q.u.nat; s.port = 113; - socket_to_sockaddr(c->q.af, &s, (struct sockaddr *)&ss, &ssz); + c->l->ao->socket_to_sockaddr(&s, &ss, &ssz); selbuf_disable(&c->b); if (conn_init(&px->cn, &sel, fd, (struct sockaddr *)&ss, ssz, proxy_connected, px)) { logmsg(&c->q, LOG_ERR, "failed to make %s proxy connection to %s: %s", - c->l->proto, px->nat, strerror(errno)); + c->l->ao->name, px->nat, strerror(errno)); goto err_2; } @@ -582,28 +543,28 @@ static void accept_client(int fd, unsigned mode, void *p) if ((sk = accept(fd, (struct sockaddr *)&ssr, &ssz)) < 0) { if (errno != EAGAIN && errno == EWOULDBLOCK) { logmsg(0, LOG_ERR, "failed to accept incoming %s connection: %s", - l->proto, strerror(errno)); + l->ao->name, strerror(errno)); } return; } c = xmalloc(sizeof(*c)); c->l = l; - c->q.af = l->af; - sockaddr_to_addr((struct sockaddr *)&ssr, &c->q.s[R].addr); + c->q.ao = l->ao; + l->ao->sockaddr_to_addr(&ssr, &c->q.s[R].addr); ssz = sizeof(ssl); if (getsockname(sk, (struct sockaddr *)&ssl, &ssz)) { logmsg(0, LOG_ERR, "failed to read local address for incoming %s connection: %s", - l->proto, strerror(errno)); + l->ao->name, strerror(errno)); close(sk); xfree(c); return; } - sockaddr_to_addr((struct sockaddr *)&ssl, &c->q.s[L].addr); + l->ao->sockaddr_to_addr(&ssl, &c->q.s[L].addr); c->q.s[L].port = c->q.s[R].port = 0; - /* logmsg(&c->q, LOG_INFO, "accepted %s connection", l->proto); */ + /* logmsg(&c->q, LOG_INFO, "accepted %s connection", l->ao->name); */ selbuf_init(&c->b, &sel, sk, client_line, c); selbuf_setsize(&c->b, 1024); @@ -612,53 +573,41 @@ static void accept_client(int fd, unsigned mode, void *p) init_writebuf(&c->wb, sk, done_client_write, c); } -static int make_listening_socket(int af, int port, const char *proto) +static int make_listening_socket(const struct addrops *ao, int port) { int fd; - int o; + int yes = 1; + struct socket s; struct sockaddr_storage ss; struct listen *l; size_t ssz; - if ((fd = socket(af, SOCK_STREAM, 0)) < 0) { + if ((fd = socket(ao->af, SOCK_STREAM, 0)) < 0) { if (errno == EAFNOSUPPORT) return (-1); die(1, "failed to create %s listening socket: %s", - proto, strerror(errno)); + ao->name, strerror(errno)); } - o = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &o, sizeof(o)); - ss.ss_family = af; - switch (af) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)&ss; - sin->sin_addr.s_addr = INADDR_ANY; - sin->sin_port = htons(port); - ssz = sizeof(*sin); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; - o = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &o, sizeof(o)); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr = in6addr_any; - sin6->sin6_scope_id = 0; - sin6->sin6_flowinfo = 0; - ssz = sizeof(*sin6); - } break; - default: - abort(); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + s.addr = *ao->any; + s.port = port; + ao->socket_to_sockaddr(&s, &ss, &ssz); + if (ao->init_listen_socket(fd)) { + die(1, "failed to initialize %s listening socket: %s", + ao->name, strerror(errno)); + } + if (bind(fd, (struct sockaddr *)&ss, ssz)) { + die(1, "failed to bind %s listening socket: %s", + ao->name, strerror(errno)); } - if (bind(fd, (struct sockaddr *)&ss, ssz)) - die(1, "failed to bind %s listening socket: %s", proto, strerror(errno)); - if ((o = fcntl(fd, F_GETFL)) < 0 || - fcntl(fd, F_SETFL, o | O_NONBLOCK)) { + if (fdflags(fd, O_NONBLOCK, O_NONBLOCK, 0, 0)) { die(1, "failed to set %s listening socket nonblocking: %s", - proto, strerror(errno)); + ao->name, strerror(errno)); } if (listen(fd, 5)) - die(1, "failed to listen for %s: %s", proto, strerror(errno)); + die(1, "failed to listen for %s: %s", ao->name, strerror(errno)); l = xmalloc(sizeof(*l)); - l->af = af; - l->proto = proto; + l->ao = ao; sel_initfile(&sel, &l->f, fd, SEL_READ, accept_client, l); sel_addfile(&l->f); @@ -668,6 +617,8 @@ static int make_listening_socket(int af, int port, const char *proto) int main(int argc, char *argv[]) { int port = 113; + const struct addrops *ao; + int any = 0; ego(argv[0]); @@ -685,8 +636,9 @@ int main(int argc, char *argv[]) } sel_init(&sel); - if (make_listening_socket(AF_INET, port, "IPv4") && - make_listening_socket(AF_INET6, port, "IPv6")) + for (ao = addroptab; ao->name; ao++) + if (!make_listening_socket(ao, port)) any = 1; + if (!any) die(1, "no IP protocols supported"); for (;;) diff --git a/yaid.h b/yaid.h index e0d13c1..85ad397 100644 --- a/yaid.h +++ b/yaid.h @@ -33,6 +33,8 @@ /*----- Header files ------------------------------------------------------*/ +#include "config.h" + #include #include #include @@ -52,21 +54,31 @@ #include #include -#include -#include - #include #include #include #include #include +#include #include #include #include #include #include +/*----- System specifics --------------------------------------------------*/ + +#define SYS_UNDEF 0 +#define SYS_LINUX 1 + +#if SYS == SYS_LINUX +# include +# include +#else +# error "Unsupported operating system: sorry. Patches welcome!" +#endif + /*----- Data structures ---------------------------------------------------*/ #define ADDRLEN 64 @@ -81,6 +93,50 @@ struct socket { unsigned port; }; +struct addrpat { + unsigned len; + union addr addr; +}; + +struct portpat { + unsigned lo, hi; +}; + +struct sockpat { + struct addrpat addr; + struct portpat port; +}; + +#define ADDRTYPES(_) \ + _(ipv4, IPV4, INET, "IPv4", 32) \ + _(ipv6, IPV6, INET6, "IPv6", 128) + +struct addrops { + int af; + const char *name; + unsigned len; + const union addr *any; + const struct addrops_sys *sys; + int (*addreq)(const union addr *, const union addr *); + int (*match_addrpat)(const struct addrpat *, const union addr *); + void (*socket_to_sockaddr)(const struct socket *s, void *, size_t *); + void (*sockaddr_to_addr)(const void *, union addr *); + int (*init_listen_socket)(int); +}; + +enum { +#define DEFADDR(ty, TY, af, name, len) ADDR_##TY, + ADDRTYPES(DEFADDR) +#undef DEFADDR + ADDR_LIMIT +}; + +extern const struct addrops addroptab[]; +#define OPS_SYS(ty, TY, af, name, len) \ + extern const struct addrops_sys addrops_sys_##ty; +ADDRTYPES(OPS_SYS) +#undef OPS_SYS + enum { L, R, NDIR }; #define RESPONSE(_) \ @@ -110,7 +166,7 @@ enum { }; struct query { - int af; + const struct addrops *ao; struct socket s[NDIR]; unsigned resp; union { @@ -131,20 +187,6 @@ enum { T_ERROR }; -struct addrpat { - unsigned len; - union addr addr; -}; - -struct portpat { - unsigned lo, hi; -}; - -struct sockpat { - struct addrpat addr; - struct portpat port; -}; - #define ACTIONS(_) \ _(USER, "user") \ _(TOKEN, "token") \ @@ -169,7 +211,7 @@ struct action { }; struct policy { - int af; + const struct addrops *ao; struct sockpat sp[NDIR]; struct action act; }; @@ -189,6 +231,10 @@ DA_DECL(policy_v, struct policy); /*----- Functions provided ------------------------------------------------*/ +int sockeq(const struct addrops *ao, + const struct socket *sa, const struct socket *sb); +void dputsock(dstr *d, const struct addrops *ao, const struct socket *s); + void logmsg(const struct query *q, int prio, const char *msg, ...); void identify(struct query *q); -- 2.11.0