yaid_LDADD = $(mLib_LIBS)
yaid_SOURCES += yaid.c
+yaid_SOURCES += addr.c
yaid_SOURCES += policy.c
yaid_LDADD += $(SYS).$(OBJEXT)
--- /dev/null
+/* -*-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 -------------------------------------------------*/
/* -*-c-*-
*
- * Discover the owner of a connection
+ * Discover the owner of a connection (Linux version)
*
* (c) 2012 Straylight/Edgeware
*/
/*----- 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;
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];
void identify(struct query *q)
{
- const struct addrfamily *af;
FILE *fp = 0;
dstr d = DSTR_INIT;
char *p, *pp;
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;
}
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;
}
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;
}
}
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;
}
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)
{
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);
}
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];
#include "yaid.h"
-/*----- Data structures ---------------------------------------------------*/
-
-/*----- Static variables --------------------------------------------------*/
-
/*----- Main code ---------------------------------------------------------*/
/* syntax: addrpat portpat addrpar portpat policy
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)
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,
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)
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;
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;
}
{
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);
/*----- Data structures ---------------------------------------------------*/
struct listen {
- int af;
- const char *proto;
+ const struct addrops *ao;
sel_file f;
};
/*----- 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;
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);
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);
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;
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;
}
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);
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);
int main(int argc, char *argv[])
{
int port = 113;
+ const struct addrops *ao;
+ int any = 0;
ego(argv[0]);
}
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 (;;)
/*----- Header files ------------------------------------------------------*/
+#include "config.h"
+
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
#include <syslog.h>
#include <mLib/bits.h>
#include <mLib/conn.h>
#include <mLib/darray.h>
#include <mLib/dstr.h>
+#include <mLib/fdflags.h>
#include <mLib/fwatch.h>
#include <mLib/quis.h>
#include <mLib/report.h>
#include <mLib/sel.h>
#include <mLib/selbuf.h>
+/*----- System specifics --------------------------------------------------*/
+
+#define SYS_UNDEF 0
+#define SYS_LINUX 1
+
+#if SYS == SYS_LINUX
+# include <linux/netlink.h>
+# include <linux/rtnetlink.h>
+#else
+# error "Unsupported operating system: sorry. Patches welcome!"
+#endif
+
/*----- Data structures ---------------------------------------------------*/
#define ADDRLEN 64
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(_) \
};
struct query {
- int af;
+ const struct addrops *ao;
struct socket s[NDIR];
unsigned resp;
union {
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") \
};
struct policy {
- int af;
+ const struct addrops *ao;
struct sockpat sp[NDIR];
struct action act;
};
/*----- 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);