Module Name: src Committed By: christos Date: Tue Jan 27 19:40:37 UTC 2015
Modified Files: src/external/bsd/blacklist/bin: Makefile blacklistctl.c blacklistd.8 blacklistd.c conf.c conf.h internal.c internal.h run.c run.h state.c state.h support.c src/external/bsd/blacklist/etc: blacklistd.conf src/external/bsd/blacklist/libexec: blacklistd-helper Added Files: src/external/bsd/blacklist/bin: blacklistd.conf.5 Log Message: - separate man page for blacklistd and blacklistd.conf, requested by wiz@ - allow separate configurations for local and remote addresses, implementing effectively whitelists, requested by dh@ - allow the mask of the filter to be specified, requested by dh@ - the db file format has been changed to accommodate these changes, and needs to be removed. To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.11 src/external/bsd/blacklist/bin/Makefile cvs rdiff -u -r1.15 -r1.16 src/external/bsd/blacklist/bin/blacklistctl.c \ src/external/bsd/blacklist/bin/conf.c cvs rdiff -u -r1.8 -r1.9 src/external/bsd/blacklist/bin/blacklistd.8 cvs rdiff -u -r1.29 -r1.30 src/external/bsd/blacklist/bin/blacklistd.c cvs rdiff -u -r0 -r1.1 src/external/bsd/blacklist/bin/blacklistd.conf.5 cvs rdiff -u -r1.5 -r1.6 src/external/bsd/blacklist/bin/conf.h \ src/external/bsd/blacklist/bin/support.c cvs rdiff -u -r1.4 -r1.5 src/external/bsd/blacklist/bin/internal.c \ src/external/bsd/blacklist/bin/run.h \ src/external/bsd/blacklist/bin/state.h cvs rdiff -u -r1.11 -r1.12 src/external/bsd/blacklist/bin/internal.h \ src/external/bsd/blacklist/bin/run.c cvs rdiff -u -r1.14 -r1.15 src/external/bsd/blacklist/bin/state.c cvs rdiff -u -r1.2 -r1.3 src/external/bsd/blacklist/etc/blacklistd.conf cvs rdiff -u -r1.1 -r1.2 src/external/bsd/blacklist/libexec/blacklistd-helper Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/external/bsd/blacklist/bin/Makefile diff -u src/external/bsd/blacklist/bin/Makefile:1.10 src/external/bsd/blacklist/bin/Makefile:1.11 --- src/external/bsd/blacklist/bin/Makefile:1.10 Thu Jan 22 12:49:41 2015 +++ src/external/bsd/blacklist/bin/Makefile Tue Jan 27 14:40:36 2015 @@ -1,11 +1,10 @@ -# $NetBSD: Makefile,v 1.10 2015/01/22 17:49:41 christos Exp $ +# $NetBSD: Makefile,v 1.11 2015/01/27 19:40:36 christos Exp $ BINDIR=/sbin PROGS=blacklistd blacklistctl -MAN.blacklistd=blacklistd.8 +MAN.blacklistd=blacklistd.8 blacklistd.conf.5 MAN.blacklistctl=blacklistctl.8 -MLINKS=blacklistd.8 blacklistd.conf.5 SRCS.blacklistd = blacklistd.c conf.c run.c state.c support.c internal.c SRCS.blacklistctl = blacklistctl.c conf.c state.c support.c internal.c DBG=-g Index: src/external/bsd/blacklist/bin/blacklistctl.c diff -u src/external/bsd/blacklist/bin/blacklistctl.c:1.15 src/external/bsd/blacklist/bin/blacklistctl.c:1.16 --- src/external/bsd/blacklist/bin/blacklistctl.c:1.15 Sun Jan 25 21:31:52 2015 +++ src/external/bsd/blacklist/bin/blacklistctl.c Tue Jan 27 14:40:36 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: blacklistctl.c,v 1.15 2015/01/26 02:31:52 christos Exp $ */ +/* $NetBSD: blacklistctl.c,v 1.16 2015/01/27 19:40:36 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -33,7 +33,7 @@ #endif #include <sys/cdefs.h> -__RCSID("$NetBSD: blacklistctl.c,v 1.15 2015/01/26 02:31:52 christos Exp $"); +__RCSID("$NetBSD: blacklistctl.c,v 1.16 2015/01/27 19:40:36 christos Exp $"); #include <stdio.h> #include <time.h> @@ -70,7 +70,6 @@ main(int argc, char *argv[]) const char *dbname = _PATH_BLSTATE; DB *db; struct conf c; - struct sockaddr_storage ss; struct dbinfo dbi; unsigned int i; struct timespec ts; @@ -118,9 +117,9 @@ main(int argc, char *argv[]) clock_gettime(CLOCK_REALTIME, &ts); wide = wide ? 8 * 4 + 7 : 4 * 3 + 3; if (!noheader) - printf("%*.*s:port\tid\tnfail\t%s\n", wide, wide, + printf("%*.*s/ma:port\tid\tnfail\t%s\n", wide, wide, "address", remain ? "remaining time" : "last access"); - for (i = 1; state_iterate(db, &ss, &c, &dbi, i) != 0; i = 0) { + for (i = 1; state_iterate(db, &c, &dbi, i) != 0; i = 0) { char buf[BUFSIZ]; if (!all) { if (blocked) { @@ -131,8 +130,8 @@ main(int argc, char *argv[]) continue; } } - sockaddr_snprintf(buf, sizeof(buf), "%a", (void *)&ss); - printf("%*.*s:%d\t", wide, wide, buf, c.c_port); + sockaddr_snprintf(buf, sizeof(buf), "%a", (void *)&c.c_ss); + printf("%*.*s/%d:%d\t", wide, wide, buf, c.c_lmask, c.c_port); if (remain) fmtydhms(buf, sizeof(buf), c.c_duration - (ts.tv_sec - dbi.last)); Index: src/external/bsd/blacklist/bin/conf.c diff -u src/external/bsd/blacklist/bin/conf.c:1.15 src/external/bsd/blacklist/bin/conf.c:1.16 --- src/external/bsd/blacklist/bin/conf.c:1.15 Sun Jan 25 16:06:04 2015 +++ src/external/bsd/blacklist/bin/conf.c Tue Jan 27 14:40:36 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: conf.c,v 1.15 2015/01/25 21:06:04 christos Exp $ */ +/* $NetBSD: conf.c,v 1.16 2015/01/27 19:40:36 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -33,7 +33,7 @@ #endif #include <sys/cdefs.h> -__RCSID("$NetBSD: conf.c,v 1.15 2015/01/25 21:06:04 christos Exp $"); +__RCSID("$NetBSD: conf.c,v 1.16 2015/01/27 19:40:36 christos Exp $"); #include <stdio.h> #include <string.h> @@ -82,7 +82,6 @@ advance(char **p) *p = ep; } - static int getnum(const char *f, size_t l, void *r, const char *p) { @@ -103,13 +102,47 @@ getnum(const char *f, size_t l, void *r, } static int -getsecs(const char *f, size_t l, void *r, const char *p) +getnfail(const char *f, size_t l, bool local, struct conf *c, const char *p) +{ + if (strcmp(p, "*") == 0) { + c->c_nfail = -1; + return 0; + } + if (strcmp(p, "=") == 0) { + if (local) + goto out; + c->c_nfail = -2; + return 0; + } + if (getnum(NULL, 0, &c->c_nfail, p) == 0) + return 0; + + (*lfun)(LOG_ERR, "%s: %s, %zu: Bad nfail [%s]", __func__, f, l, p); + return -1; +out: + (*lfun)(LOG_ERR, "%s: %s, %zu: `=' nfail not allowed in local config", + __func__, f, l); + return -1; +} + +static int +getsecs(const char *f, size_t l, bool local, struct conf *c, const char *p) { int e; char *ep; intmax_t tot, im; tot = 0; + if (strcmp(p, "*") == 0) { + c->c_duration = -1; + return 0; + } + if (strcmp(p, "=") == 0) { + if (local) + goto out; + c->c_duration = -2; + return 0; + } again: im = strtoi(p, &ep, 0, 0, INT_MAX, &e); @@ -137,7 +170,7 @@ again: tot = im; if (e == 0) { - *(int *)r = (int)tot; + c->c_duration = (int)tot; return 0; } @@ -145,10 +178,13 @@ again: return -1; (*lfun)(LOG_ERR, "%s: %s, %zu: Bad number [%s]", __func__, f, l, p); return -1; +out: + (*lfun)(LOG_ERR, "%s: %s, %zu: `=' duration not allowed in local" + " config", __func__, f, l); + return -1; } - static int getport(const char *f, size_t l, void *r, const char *p) { @@ -172,16 +208,69 @@ getport(const char *f, size_t l, void *r } static int -gethostport(const char *f, size_t l, void *v, const char *p) +getmask(const char *f, size_t l, bool local __unused, const char **p, int def) +{ + char *d; + int e; + intmax_t im; + const char *s = *p; + + if ((d = strchr(s, ':')) != NULL) { + *d++ = '\0'; + *p = d; + } + if ((d = strchr(s, '/')) == NULL) + return def; + + *d++ = '\0'; + if (strcmp(d, "=") == 0) { + if (local) + goto out; + return -2; + } + if (strcmp(d, "*") == 0) + return def; + + im = strtoi(d, NULL, 0, 0, def, &e); + if (e == 0) + return (int)im; + + (*lfun)(LOG_ERR, "%s: %s, %zu: Bad mask [%s]", __func__, f, l, d); + return -1; +out: + (*lfun)(LOG_ERR, "%s: %s, %zu: `=' name not allowed in local" + " config", __func__, f, l); + return -1; +} + +static int +gethostport(const char *f, size_t l, bool local, struct conf *c, const char *p) { char *d; // XXX: Ok to write to string. in_port_t *port = NULL; - struct conf *c = v; + const char *pstr; - if ((d = strstr(p, "]:")) != NULL) { - struct sockaddr_in6 *sin6 = (void *)&c->c_ss; + if (strcmp(p, "*") == 0) { + c->c_port = -1; + c->c_lmask = -1; + return 0; + } + + if ((d = strchr(p, ']')) != NULL) { *d++ = '\0'; + pstr = d; p++; + } else + pstr = p; + + if ((c->c_lmask = getmask(f, l, local, &pstr, 256)) == -1) + goto out; + + if (c->c_lmask == 256) + c->c_lmask = -1; + + if (d) { + struct sockaddr_in6 *sin6 = (void *)&c->c_ss; if (debug) (*lfun)(LOG_DEBUG, "%s: host6 %s", __func__, p); if (strcmp(p, "*") != 0) { @@ -193,15 +282,20 @@ gethostport(const char *f, size_t l, voi #endif port = &sin6->sin6_port; } - p = ++d; - } else if ((d = strrchr(p, ':')) != NULL) { + } else if (pstr != p || strchr(p, '.') || conf_is_interface(p)) { + if (pstr == p) + pstr = "*"; struct sockaddr_in *sin = (void *)&c->c_ss; struct sockaddr_if *sif = (void *)&c->c_ss; - *d++ = '\0'; if (debug) (*lfun)(LOG_DEBUG, "%s: host4 %s", __func__, p); if (strcmp(p, "*") != 0) { if (conf_is_interface(p)) { + if (debug) + (*lfun)(LOG_DEBUG, "%s: interface %s", + __func__, p); + if (c->c_lmask != -1) + goto out1; sif->sif_family = AF_MAX; strlcpy(sif->sif_name, p, sizeof(sif->sif_name)); @@ -215,38 +309,46 @@ gethostport(const char *f, size_t l, voi #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin->sin_len = sizeof(*sin); #endif - port = &sif->sif_port; + port = &sin->sin_port; } else goto out; } - p = d; } - if (strcmp(p, "*") == 0) + if (strcmp(pstr, "*") == 0) c->c_port = -1; - else if (getport(f, l, &c->c_port, p) == -1) + else if (getport(f, l, &c->c_port, pstr) == -1) return -1; if (port && c->c_port != -1) *port = htons((in_port_t)c->c_port); return 0; out: - (*lfun)(LOG_ERR, "%s: %s, %zu: Bad address [%s]", __func__, f, l, p); + (*lfun)(LOG_ERR, "%s: %s, %zu: Bad address [%s]", __func__, f, l, pstr); + return -1; +out1: + (*lfun)(LOG_ERR, "%s: %s, %zu: Can't specify mask %d with " + "interface [%s]", __func__, f, l, c->c_lmask, p); return -1; } static int -getproto(const char *f, size_t l, void *r, const char *p) +getproto(const char *f, size_t l, bool local __unused, struct conf *c, + const char *p) { + if (strcmp(p, "*") == 0) { + c->c_proto = -1; + return 0; + } if (strcmp(p, "stream") == 0) { - *(int *)r = IPPROTO_TCP; + c->c_proto = IPPROTO_TCP; return 0; } if (strcmp(p, "dgram") == 0) { - *(int *)r = IPPROTO_UDP; + c->c_proto = IPPROTO_UDP; return 0; } - if (getnum(NULL, 0, r, p) == 0) + if (getnum(NULL, 0, &c->c_proto, p) == 0) return 0; (*lfun)(LOG_ERR, "%s: %s, %zu: Bad protocol [%s]", __func__, f, l, p); @@ -254,13 +356,19 @@ getproto(const char *f, size_t l, void * } static int -getfamily(const char *f, size_t l, void *r, const char *p) +getfamily(const char *f, size_t l, bool local __unused, struct conf *c, + const char *p) { + if (strcmp(p, "*") == 0) { + c->c_family = -1; + return 0; + } + if (strncmp(p, "tcp", 3) == 0 || strncmp(p, "udp", 3) == 0) { - *(int *)r = p[3] == '6' ? AF_INET6 : AF_INET; + c->c_family = p[3] == '6' ? AF_INET6 : AF_INET; return 0; } - if (getnum(NULL, 0, r, p) == 0) + if (getnum(NULL, 0, &c->c_family, p) == 0) return 0; (*lfun)(LOG_ERR, "%s: %s, %zu: Bad family [%s]", __func__, f, l, p); @@ -268,51 +376,70 @@ getfamily(const char *f, size_t l, void } static int -getuid(const char *f, size_t l, void *r, const char *p) +getuid(const char *f, size_t l, bool local __unused, struct conf *c, + const char *p) { struct passwd *pw; + if (strcmp(p, "*") == 0) { + c->c_uid = -1; + return 0; + } + if ((pw = getpwnam(p)) != NULL) { - *(int *)r = (int)pw->pw_uid; + c->c_uid = (int)pw->pw_uid; return 0; } - if (getnum(NULL, 0, r, p) == 0) + if (getnum(NULL, 0, &c->c_uid, p) == 0) return 0; (*lfun)(LOG_ERR, "%s: %s, %zu: Bad user [%s]", __func__, f, l, p); return -1; } + static int -getname(const char *f __unused, size_t l __unused, void *r, const char *p) +getname(const char *f, size_t l, bool local, struct conf *c, + const char *p) { - snprintf(r, CONFNAMESZ, "%s%s", *p == '-' ? rulename : "", p); + if ((c->c_rmask = getmask(f, l, local, &p, 256)) == -1) + return -1; + if (c->c_rmask == 256) + c->c_rmask = local ? -1 : -2; + + if (strcmp(p, "*") == 0) { + strlcpy(c->c_name, rulename, CONFNAMESZ); + return 0; + } + if (strcmp(p, "=") == 0) { + if (local) + goto out; + c->c_name[0] = '\0'; + return 0; + } + + snprintf(c->c_name, CONFNAMESZ, "%s%s", *p == '-' ? rulename : "", p); return 0; +out: + (*lfun)(LOG_ERR, "%s: %s, %zu: `=' name not allowed in local" + " config", __func__, f, l); + return -1; } static int -getvalue(const char *f, size_t l, void *r, char **p, - int (*fun)(const char *, size_t, void *, const char *)) +getvalue(const char *f, size_t l, bool local, void *r, char **p, + int (*fun)(const char *, size_t, bool, struct conf *, const char *)) { char *ep = *p; advance(p); - if (strcmp(ep, "*") == 0) { - if (fun == gethostport) - ((struct conf *)r)->c_port = -1; - else if (fun == getname) - strlcpy(r, rulename, CONFNAMESZ); - else - *(int *)r = -1; - return 0; - } - return (*fun)(f, l, r, ep); + return (*fun)(f, l, local, r, ep); } static int -conf_parseline(const char *f, size_t l, char *p, struct conf *c) +conf_parseline(const char *f, size_t l, char *p, struct conf *c, bool local) { int e; @@ -320,19 +447,19 @@ conf_parseline(const char *f, size_t l, p++; memset(c, 0, sizeof(*c)); - e = getvalue(f, l, c, &p, gethostport); + e = getvalue(f, l, local, c, &p, gethostport); if (e) return -1; - e = getvalue(f, l, &c->c_proto, &p, getproto); + e = getvalue(f, l, local, c, &p, getproto); if (e) return -1; - e = getvalue(f, l, &c->c_family, &p, getfamily); + e = getvalue(f, l, local, c, &p, getfamily); if (e) return -1; - e = getvalue(f, l, &c->c_uid, &p, getuid); + e = getvalue(f, l, local, c, &p, getuid); if (e) return -1; - e = getvalue(f, l, &c->c_name, &p, getname); + e = getvalue(f, l, local, c, &p, getname); if (e) return -1; - e = getvalue(f, l, &c->c_nfail, &p, getnum); + e = getvalue(f, l, local, c, &p, getnfail); if (e) return -1; - e = getvalue(f, l, &c->c_duration, &p, getsecs); + e = getvalue(f, l, local, c, &p, getsecs); if (e) return -1; return 0; @@ -349,9 +476,11 @@ conf_sort(const void *v1, const void *v2 else if ((a)->f < (b)->f) return 1 CMP(c1, c2, c_ss.ss_family); + CMP(c1, c2, c_lmask); CMP(c1, c2, c_port); CMP(c1, c2, c_proto); CMP(c1, c2, c_family); + CMP(c1, c2, c_rmask); CMP(c1, c2, c_uid); #undef CMP return 0; @@ -362,21 +491,180 @@ conf_is_interface(const char *name) { const struct ifaddrs *ifa; - for (ifa = ifas; ifas; ifa = ifa->ifa_next) + for (ifa = ifas; ifa; ifa = ifa->ifa_next) if (strcmp(ifa->ifa_name, name) == 0) return 1; return 0; } +#define MASK(m) ((uint32_t)~((1 << (32 - (m))) - 1)) + +static int +conf_amask_eq(const void *v1, const void *v2, size_t len, int mask) +{ + const uint32_t *a1 = v1; + const uint32_t *a2 = v2; + uint32_t m; + + len >>= 2; + switch (mask) { + case -1: + return memcmp(v1, v2, len) == 0; + case -2: + + (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__, + mask); + abort(); + default: + break; + } + + for (size_t i = 0; i < len; i++) { + if (mask > 32) { + m = (uint32_t)~0; + mask -= 32; + } else if (mask) { + m = MASK(mask); + mask = 0; + } else + return 1; + if ((a1[i] & m) != (a2[i] & m)) + return 0; + } + return 1; +} + +/* + * Apply the mask to the given address + */ +static void +conf_apply_mask(void *v, size_t len, int mask) +{ + uint32_t *a = v; + uint32_t m; + + switch (mask) { + case -1: + return; + case -2: + (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__, + mask); + abort(); + default: + break; + } + len >>= 2; + + for (size_t i = 0; i < len; i++) { + if (mask > 32) { + m = (uint32_t)~0; + mask -= 32; + } else if (mask) { + m = MASK(mask); + mask = 0; + } + a[i] &= m; + } +} + +/* + * apply the mask and the port to the address given + */ +static void +conf_addr_set(struct conf *c, const struct sockaddr_storage *ss) +{ + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + in_port_t *port; + void *addr; + size_t alen; + + c->c_lmask = c->c_rmask; + c->c_ss = *ss; + + if (c->c_ss.ss_family != c->c_family) { + (*lfun)(LOG_CRIT, "%s: Internal error: mismatched family " + "%u != %u", __func__, c->c_ss.ss_family, c->c_family); + abort(); + } + + switch (c->c_ss.ss_family) { + case AF_INET: + sin = (void *)&c->c_ss; + port = &sin->sin_port; + addr = &sin->sin_addr; + alen = sizeof(sin->sin_addr); + break; + case AF_INET6: + sin6 = (void *)&c->c_ss; + port = &sin6->sin6_port; + addr = &sin6->sin6_addr; + alen = sizeof(sin6->sin6_addr); + break; + default: + (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u", + __func__, c->c_ss.ss_family); + abort(); + } + + *port = htons(c->c_port); + conf_apply_mask(addr, alen, c->c_lmask); + if (c->c_lmask == -1) + c->c_lmask = (int)(alen * 8); + if (debug) { + char buf[128]; + sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&c->c_ss); + (*lfun)(LOG_DEBUG, "Applied address %s", buf); + } +} + +/* + * Compared two addresses for equality applying the mask + */ +static int +conf_inet_eq(const void *v1, const void *v2, int mask) +{ + const struct sockaddr *sa1 = v1; + const struct sockaddr *sa2 = v2; + size_t size; + + if (sa1->sa_family != sa2->sa_family) + return 0; + + switch (sa1->sa_family) { + case AF_INET: { + const struct sockaddr_in *s1 = v1; + const struct sockaddr_in *s2 = v2; + size = sizeof(s1->sin_addr); + v1 = &s1->sin_addr; + v2 = &s2->sin_addr; + break; + } + + case AF_INET6: { + const struct sockaddr_in6 *s1 = v1; + const struct sockaddr_in6 *s2 = v2; + size = sizeof(s1->sin6_addr); + v1 = &s1->sin6_addr; + v2 = &s2->sin6_addr; + break; + } + + default: + (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u", + __func__, sa1->sa_family); + abort(); + } + + return conf_amask_eq(v1, v2, size, mask); +} + static int conf_addr_in_interface(const struct sockaddr_storage *s1, - const struct sockaddr_storage *s2) + const struct sockaddr_storage *s2, int mask) { const char *name = SIF_NAME(s2); const struct ifaddrs *ifa; - socklen_t slen; - const struct sockaddr_in *sin = (const void *)s1; - const struct sockaddr_in6 *sin6 = (const void *)s1; for (ifa = ifas; ifa; ifa = ifa->ifa_next) { if ((ifa->ifa_flags & IFF_UP) == 0) @@ -388,24 +676,17 @@ conf_addr_in_interface(const struct sock if (s1->ss_family != ifa->ifa_addr->sa_family) continue; - const void *v = ifa->ifa_addr; - const void *p1, *p2; + bool eq; switch (s1->ss_family) { case AF_INET: - p1 = &sin->sin_addr; - p2 = &((const struct sockaddr_in *)v)->sin_addr; - slen = sizeof(sin->sin_addr); - break; case AF_INET6: - p1 = &sin6->sin6_addr; - p2 = &((const struct sockaddr_in6 *)v)->sin6_addr; - slen = sizeof(sin6->sin6_addr); + eq = conf_inet_eq(ifa->ifa_addr, s1, mask); break; default: (*lfun)(LOG_ERR, "Bad family %u", s1->ss_family); continue; } - if (memcmp(p1, p2, slen) == 0) + if (eq) return 1; } return 0; @@ -413,20 +694,20 @@ conf_addr_in_interface(const struct sock static int conf_addr_eq(const struct sockaddr_storage *s1, - const struct sockaddr_storage *s2) + const struct sockaddr_storage *s2, int mask) { switch (s2->ss_family) { case 0: return 1; case AF_MAX: - return conf_addr_in_interface(s1, s2); + return conf_addr_in_interface(s1, s2, mask); + case AF_INET: + case AF_INET6: + return conf_inet_eq(s1, s2, mask); default: - if (memcmp(s1, s2, sizeof(*s2))) { - if (debug > 1) - (*lfun)(LOG_DEBUG, "%s: c_ss fail", __func__); - return 0; - } - return 1; + (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u", + __func__, s1->ss_family); + abort(); } } @@ -434,14 +715,14 @@ static int conf_eq(const struct conf *c1, const struct conf *c2) { - if (!conf_addr_eq(&c1->c_ss, &c2->c_ss)) + if (!conf_addr_eq(&c1->c_ss, &c2->c_ss, c2->c_lmask)) return 0; #define CMP(a, b, f) \ if ((a)->f != (b)->f && (b)->f != -1) { \ if (debug > 1) \ - (*lfun)(LOG_DEBUG, "%s: %s fail", __func__, \ - __STRING(f)); \ + (*lfun)(LOG_DEBUG, "%s: %s fail %d != %d", __func__, \ + __STRING(f), (a)->f, (b)->f); \ return 0; \ } CMP(c1, c2, c_port); @@ -455,14 +736,19 @@ conf_eq(const struct conf *c1, const str static const char * conf_num(char *b, size_t l, int n) { - if (n == -1) + switch (n) { + case -1: return "*"; - snprintf(b, l, "%d", n); - return b; + case -2: + return "="; + default: + snprintf(b, l, "%d", n); + return b; + } } static const char * -conf_name(const char *n) { +fmtname(const char *n) { size_t l = strlen(rulename); if (l == 0) return "*"; @@ -471,73 +757,285 @@ conf_name(const char *n) { return n + l; else return "*"; - } else + } else if (!*n) + return "="; + else return n; } +static void +fmtport(char *b, size_t l, int port) +{ + char buf[128]; + + if (port == -1) + return; + + if (b[0] == '\0' || strcmp(b, "*") == 0) + snprintf(b, l, "%d", port); + else { + snprintf(buf, sizeof(buf), ":%d", port); + strlcat(b, buf, l); + } +} + +static const char * +fmtmask(char *b, size_t l, int fam, int mask) +{ + char buf[128]; + + switch (mask) { + case -1: + return ""; + case -2: + if (strcmp(b, "=") == 0) + return ""; + else { + strlcat(b, "/=", l); + return b; + } + default: + break; + } + + switch (fam) { + case AF_INET: + if (mask == 32) + return ""; + break; + case AF_INET6: + if (mask == 128) + return ""; + break; + default: + break; + } + + snprintf(buf, sizeof(buf), "/%d", mask); + strlcat(b, buf, l); + return b; +} + +static const char * +conf_namemask(char *b, size_t l, const struct conf *c) +{ + strlcpy(b, fmtname(c->c_name), l); + fmtmask(b, l, c->c_family, c->c_rmask); + return b; +} + const char * conf_print(char *buf, size_t len, const char *pref, const char *delim, const struct conf *c) { - char hb[128], b[5][64]; + char ha[128], hb[32], b[5][64]; int sp; #define N(n, v) conf_num(b[n], sizeof(b[n]), (v)) switch (c->c_ss.ss_family) { case 0: - if (c->c_port == -1) - snprintf(hb, sizeof(hb), "*"); - else - snprintf(hb, sizeof(hb), "%d", c->c_port); + snprintf(ha, sizeof(ha), "*"); break; case AF_MAX: - if (c->c_port == -1) - snprintf(hb, sizeof(hb), "%s:*", SIF_NAME(&c->c_ss)); - else - snprintf(hb, sizeof(hb), "%s:%d", SIF_NAME(&c->c_ss), - c->c_port); + snprintf(ha, sizeof(ha), "%s", SIF_NAME(&c->c_ss)); break; default: - if (c->c_port == -1) - sockaddr_snprintf(hb, sizeof(hb), "%a:*", - (const void *)&c->c_ss); - else - sockaddr_snprintf(hb, sizeof(hb), "%a:%p", - (const void *)&c->c_ss); + sockaddr_snprintf(ha, sizeof(ha), "%a", (const void *)&c->c_ss); break; } + + fmtmask(ha, sizeof(ha), c->c_family, c->c_lmask); + fmtport(ha, sizeof(ha), c->c_port); sp = *delim == '\t' ? 20 : -1; + hb[0] = '\0'; if (*delim) snprintf(buf, len, "%s%*.*s%s%s%s" "%s%s%s%s" "%s%s" "%s%s%s", - pref, sp, sp, hb, delim, N(0, c->c_proto), delim, + pref, sp, sp, ha, delim, N(0, c->c_proto), delim, N(1, c->c_family), delim, N(2, c->c_uid), delim, - conf_name(c->c_name), delim, + conf_namemask(hb, sizeof(hb), c), delim, N(3, c->c_nfail), delim, N(4, c->c_duration)); else snprintf(buf, len, "%starget=%s, proto=%s, family=%s, " "uid=%s, name=%s, nfail=%s, duration=%s", pref, - hb, N(0, c->c_proto), N(1, c->c_family), N(2, c->c_uid), - conf_name(c->c_name), N(3, c->c_nfail), - N(4, c->c_duration)); + ha, N(0, c->c_proto), N(1, c->c_family), N(2, c->c_uid), + conf_namemask(hb, sizeof(hb), c), + N(3, c->c_nfail), N(4, c->c_duration)); return buf; } +/* + * Apply the local config match to the result + */ +static void +conf_apply(struct conf *c, const struct conf *sc) +{ + char buf[BUFSIZ]; + + if (debug) { + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "merge:\t", "", sc)); + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "to:\t", "", c)); + } + memcpy(c->c_name, sc->c_name, CONFNAMESZ); + c->c_rmask = sc->c_rmask; + c->c_nfail = sc->c_nfail; + c->c_duration = sc->c_duration; + + if (debug) + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "result:\t", "", c)); +} + +/* + * Merge a remote configuration to the result + */ +static void +conf_merge(struct conf *c, const struct conf *sc) +{ + char buf[BUFSIZ]; + + if (debug) { + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "merge:\t", "", sc)); + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "to:\t", "", c)); + } + + if (sc->c_name[0]) + memcpy(c->c_name, sc->c_name, CONFNAMESZ); + if (sc->c_rmask != -2) + c->c_lmask = c->c_rmask = sc->c_rmask; + if (sc->c_nfail != -2) + c->c_nfail = sc->c_nfail; + if (sc->c_duration != -2) + c->c_duration = sc->c_duration; + if (debug) + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "result:\t", "", c)); +} + +static void +confset_init(struct confset *cs) +{ + cs->cs_c = NULL; + cs->cs_n = 0; + cs->cs_m = 0; +} + +static int +confset_grow(struct confset *cs) +{ + void *tc; + + cs->cs_m += 10; + tc = realloc(cs->cs_c, cs->cs_m * sizeof(*cs->cs_c)); + if (tc == NULL) { + (*lfun)(LOG_ERR, "%s: Can't grow confset (%m)", __func__); + return -1; + } + cs->cs_c = tc; + return 0; +} + +static struct conf * +confset_get(struct confset *cs) +{ + return &cs->cs_c[cs->cs_n]; +} + +static bool +confset_full(const struct confset *cs) +{ + return cs->cs_n == cs->cs_m; +} + +static void +confset_sort(struct confset *cs) +{ + qsort(cs->cs_c, cs->cs_n, sizeof(*cs->cs_c), conf_sort); +} + +static void +confset_add(struct confset *cs) +{ + cs->cs_n++; +} + +static void +confset_free(struct confset *cs) +{ + free(cs->cs_c); + confset_init(cs); +} + +static void +confset_replace(struct confset *dc, struct confset *sc) +{ + struct confset tc; + tc = *dc; + *dc = *sc; + confset_init(sc); + confset_free(&tc); +} + +static void +confset_list(const struct confset *cs, const char *msg, const char *where) +{ + char buf[BUFSIZ]; + + (*lfun)(LOG_DEBUG, "[%s]", msg); + (*lfun)(LOG_DEBUG, "%20.20s\ttype\tproto\towner\tname\tnfail\tduration", + where); + for (size_t i = 0; i < cs->cs_n; i++) + (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), "", "\t", + &cs->cs_c[i])); +} + +/* + * Match a configuration against the given list and apply the function + * to it, returning the matched entry number. + */ +static size_t +confset_match(const struct confset *cs, struct conf *c, + void (*fun)(struct conf *, const struct conf *)) +{ + char buf[BUFSIZ]; + size_t i; + + for (i = 0; i < cs->cs_n; i++) { + if (debug) + (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), + "check:\t", "", &cs->cs_c[i])); + if (conf_eq(c, &cs->cs_c[i])) { + if (debug) + (*lfun)(LOG_DEBUG, "%s", + conf_print(buf, sizeof(buf), + "found:\t", "", &cs->cs_c[i])); + (*fun)(c, &cs->cs_c[i]); + break; + } + } + return i; +} + const struct conf * -conf_find(int fd, uid_t uid, struct conf *cr) +conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss, + struct conf *cr) { int proto; socklen_t slen; - struct sockaddr_storage ss; + struct sockaddr_storage lss; size_t i; char buf[BUFSIZ]; memset(cr, 0, sizeof(*cr)); - slen = sizeof(ss); - memset(&ss, 0, slen); - if (getsockname(fd, (void *)&ss, &slen) == -1) { + slen = sizeof(lss); + memset(&lss, 0, slen); + if (getsockname(fd, (void *)&lss, &slen) == -1) { (*lfun)(LOG_ERR, "getsockname failed (%m)"); return NULL; } @@ -549,7 +1047,7 @@ conf_find(int fd, uid_t uid, struct conf } if (debug) { - sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&ss); + sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&lss); (*lfun)(LOG_DEBUG, "listening socket: %s", buf); } @@ -565,21 +1063,24 @@ conf_find(int fd, uid_t uid, struct conf return NULL; } - switch (ss.ss_family) { + switch (lss.ss_family) { case AF_INET: - cr->c_port = ntohs(((struct sockaddr_in *)&ss)->sin_port); + cr->c_port = ntohs(((struct sockaddr_in *)&lss)->sin_port); break; case AF_INET6: - cr->c_port = ntohs(((struct sockaddr_in6 *)&ss)->sin6_port); + cr->c_port = ntohs(((struct sockaddr_in6 *)&lss)->sin6_port); break; default: - (*lfun)(LOG_ERR, "unsupported family %d", ss.ss_family); + (*lfun)(LOG_ERR, "unsupported family %d", lss.ss_family); return NULL; } - cr->c_ss = ss; + cr->c_ss = lss; + cr->c_lmask = -1; cr->c_uid = (int)uid; - cr->c_family = ss.ss_family; + cr->c_family = lss.ss_family; + cr->c_name[0] = '\0'; + cr->c_rmask = -1; cr->c_nfail = -1; cr->c_duration = -1; @@ -587,34 +1088,29 @@ conf_find(int fd, uid_t uid, struct conf (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), "look:\t", "", cr)); - for (i = 0; i < nconf; i++) { + /* match the local config */ + i = confset_match(&lconf, cr, conf_apply); + if (i == lconf.cs_n) { if (debug) - (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), - "check:\t", "", &conf[i])); - if (conf_eq(cr, &conf[i])) { - if (debug) - (*lfun)(LOG_DEBUG, "%s", - conf_print(buf, sizeof(buf), - "found:\t", "", &conf[i])); - cr->c_ss = conf[i].c_ss; - memcpy(cr->c_name, conf[i].c_name, CONFNAMESZ); - cr->c_nfail = conf[i].c_nfail; - cr->c_duration = conf[i].c_duration; - return cr; - } + (*lfun)(LOG_DEBUG, "not found"); + return NULL; } - if (debug) - (*lfun)(LOG_DEBUG, "not found"); - return NULL; + + conf_addr_set(cr, rss); + /* match the remote config */ + confset_match(&rconf, cr, conf_merge); + + return cr; } + void conf_parse(const char *f) { FILE *fp; char *line; - size_t lineno, len, nc, mc; - struct conf *c, *tc; + size_t lineno, len; + struct confset lc, rc, *cs; if ((fp = fopen(f, "r")) == NULL) { (*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__, f); @@ -622,46 +1118,47 @@ conf_parse(const char *f) } lineno = 1; - nc = mc = 0; - c = NULL; + + confset_init(&rc); + confset_init(&lc); + cs = &lc; for (; (line = fparseln(fp, &len, &lineno, NULL, 0)) != NULL; free(line)) { -#ifdef __APPLE__ if (!*line) continue; - if (debug > 4) - (*lfun)(LOG_DEBUG, "%s, %zu: [%s]", f, lineno, line); -#endif - if (nc == mc) { - mc += 10; - tc = realloc(c, mc * sizeof(*c)); - if (tc == NULL) { - free(c); + if (strcmp(line, "[local]") == 0) { + cs = &lc; + continue; + } + if (strcmp(line, "[remote]") == 0) { + cs = &rc; + continue; + } + + if (confset_full(cs)) { + if (confset_grow(cs) == -1) { + confset_free(&lc); + confset_free(&rc); fclose(fp); return; } - c = tc; } - if (conf_parseline(f, lineno, line, &c[nc]) == -1) + if (conf_parseline(f, lineno, line, confset_get(cs), + cs == &lc) == -1) continue; - nc++; + confset_add(cs); } + fclose(fp); - qsort(c, nc, sizeof(*c), conf_sort); + confset_sort(&lc); + confset_sort(&rc); - tc = conf; - nconf = nc; - conf = c; - free(tc); + confset_replace(&rconf, &rc); + confset_replace(&lconf, &lc); if (debug) { - char buf[BUFSIZ]; - (*lfun)(LOG_DEBUG, - "%20.20s\ttype\tproto\towner\tname\tnfail\tduration", - "target"); - for (nc = 0; nc < nconf; nc++) - (*lfun)(LOG_DEBUG, "%s", - conf_print(buf, sizeof(buf), "", "\t", &c[nc])); + confset_list(&lconf, "local", "target"); + confset_list(&rconf, "remote", "source"); } } Index: src/external/bsd/blacklist/bin/blacklistd.8 diff -u src/external/bsd/blacklist/bin/blacklistd.8:1.8 src/external/bsd/blacklist/bin/blacklistd.8:1.9 --- src/external/bsd/blacklist/bin/blacklistd.8:1.8 Sun Jan 25 18:07:16 2015 +++ src/external/bsd/blacklist/bin/blacklistd.8 Tue Jan 27 14:40:36 2015 @@ -1,4 +1,4 @@ -.\" $NetBSD: blacklistd.8,v 1.8 2015/01/25 23:07:16 wiz Exp $ +.\" $NetBSD: blacklistd.8,v 1.9 2015/01/27 19:40:36 christos Exp $ .\" .\" Copyright (c) 2015 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -32,7 +32,6 @@ .Os .Sh NAME .Nm blacklistd , -.Nm blacklistd.conf .Nd block and release ports on demand to avoid DoS abuse .Sh SYNOPSIS .Nm @@ -40,8 +39,9 @@ .Op Fl C Ar controlprog .Op Fl c Ar configfile .Op Fl D Ar dbfile -.Op Fl r Ar rulename .Op Fl P Ar sockpathsfile +.Op Fl r Ar rulename +.Op Fl s Ar sockpath .Op Fl t Ar timeout .Sh DESCRIPTION .Nm @@ -51,7 +51,10 @@ that listens to a sockets at paths speci .Ar sockpathsfile for notifications from other daemons about successful or failed connection attempts. -If no such file is specified, then it only listens to the default socket +If no such file is specified, then it only listens to the socket path +specified by +.Ar sockspath +or if that is not specified to .Pa /var/run/blsock . Each notification contains an (action, port, protocol, address, owner) tuple that identifies the remote connection and the action. @@ -69,7 +72,7 @@ control script .Ar controlprog is invoked with arguments: .Bd -literal -offset indent -control add <rulename> <proto> <port> <address> +control add <rulename> <proto> <address> <mask> <port> .Ed .Pp and should invoke a packet filter command to block the connection @@ -87,7 +90,7 @@ If the action is .Dq remove Then the same control script is invoked as: .Bd -literal -offset indent -control rem <rulename> <proto> <port> <address> <id> +control add <rulename> <proto> <address> <mask> <port> .Ed .Pp where @@ -116,31 +119,6 @@ seconds (default .Dv 15 ) and removes entries and block rules using the control program as necessary. .Pp -The configuration file contains one tuple per line, and is similar to -.Xr inetd.conf 5 . -There must be an entry for each field of the configuration file, with -entries for each field separated by a tab or a space. -Comments are denoted by a -.Dq # -at the beginning of a line. -There must be an entry for each field; entries can be numeric or symbolic, -where appropriate -.Dv ( service , -.Dv user ) -and can be -.Dq * -for all fields. -The fields of the configuration file are as follows: -.Bd -literal -offset indent -[address|interface:]service -socket-type -protocol -user -rulename -nfail -duration -.Ed -.Pp Normally, .Nm disassociates itself from the terminal and writes messages to Index: src/external/bsd/blacklist/bin/blacklistd.c diff -u src/external/bsd/blacklist/bin/blacklistd.c:1.29 src/external/bsd/blacklist/bin/blacklistd.c:1.30 --- src/external/bsd/blacklist/bin/blacklistd.c:1.29 Sun Jan 25 15:59:39 2015 +++ src/external/bsd/blacklist/bin/blacklistd.c Tue Jan 27 14:40:36 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: blacklistd.c,v 1.29 2015/01/25 20:59:39 christos Exp $ */ +/* $NetBSD: blacklistd.c,v 1.30 2015/01/27 19:40:36 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -32,7 +32,7 @@ #include "config.h" #endif #include <sys/cdefs.h> -__RCSID("$NetBSD: blacklistd.c,v 1.29 2015/01/25 20:59:39 christos Exp $"); +__RCSID("$NetBSD: blacklistd.c,v 1.30 2015/01/27 19:40:36 christos Exp $"); #include <sys/types.h> #include <sys/socket.h> @@ -71,7 +71,7 @@ __RCSID("$NetBSD: blacklistd.c,v 1.29 20 static const char *configfile = _PATH_BLCONF; static DB *state; static const char *dbfile = _PATH_BLSTATE; -static sig_atomic_t rconf; +static sig_atomic_t readconf; static sig_atomic_t done; static int vflag; @@ -90,7 +90,7 @@ sigusr2(int n __unused) static void sighup(int n __unused) { - rconf++; + readconf++; } static void @@ -106,7 +106,7 @@ usage(int c) warnx("Unknown option `%c'", (char)c); fprintf(stderr, "Usage: %s [-vdf] [-c <config>] [-r <rulename>] " "[-P <sockpathsfile>] [-C <controlprog>] [-D <dbfile>] " - "[-t <timeout>]\n", getprogname()); + "[-s <sockpath>] [-t <timeout>]\n", getprogname()); exit(EXIT_FAILURE); } @@ -193,13 +193,13 @@ process(bl_t bl) (unsigned long)bi->bi_gid); } - if (conf_find(bi->bi_fd, bi->bi_uid, &c) == NULL) { + if (conf_find(bi->bi_fd, bi->bi_uid, &rss, &c) == NULL) { (*lfun)(LOG_DEBUG, "no rule matched"); goto out; } - if (state_get(state, &rss, &c, &dbi) == -1) + if (state_get(state, &c, &dbi) == -1) goto out; if (debug) { @@ -224,15 +224,14 @@ process(bl_t bl) (*lfun)(LOG_ERR, "rule exists %s", dbi.id); } if (c.c_nfail != -1 && dbi.count >= c.c_nfail) { - int res = run_change("add", &c, &rss, - dbi.id, sizeof(dbi.id)); + int res = run_change("add", &c, dbi.id, sizeof(dbi.id)); if (res == -1) goto out; sockaddr_snprintf(rbuf, sizeof(rbuf), "%a", (void *)&rss); (*lfun)(LOG_INFO, - "blocked %s at port %d for %d seconds", - rbuf, c.c_port, c.c_duration); + "blocked %s/%d:%d for %d seconds", + rbuf, c.c_lmask, c.c_port, c.c_duration); } break; @@ -244,7 +243,7 @@ process(bl_t bl) default: (*lfun)(LOG_ERR, "unknown message %d", bi->bi_type); } - if (state_put(state, &rss, &c, &dbi) == -1) + if (state_put(state, &c, &dbi) == -1) goto out; out: close(bi->bi_fd); @@ -280,7 +279,7 @@ update(void) return; } - for (n = 0, f = 1; state_iterate(state, &ss, &c, &dbi, f) == 1; + for (n = 0, f = 1; state_iterate(state, &c, &dbi, f) == 1; f = 0, n++) { time_t when = c.c_duration + dbi.last; @@ -297,13 +296,13 @@ update(void) if (c.c_duration == -1 || when >= ts.tv_sec) continue; if (dbi.id[0]) { - run_change("rem", &c, &ss, dbi.id, 0); + run_change("rem", &c, dbi.id, 0); sockaddr_snprintf(buf, sizeof(buf), "%a", (void *)&ss); syslog(LOG_INFO, - "released %s at port %d after %d seconds", - buf, c.c_port, c.c_duration); + "released %s/%d:%d after %d seconds", + buf, c.c_lmask, c.c_port, c.c_duration); } - state_del(state, &ss, &c); + state_del(state, &c); } } @@ -334,15 +333,16 @@ int main(int argc, char *argv[]) { int c, tout, flags, reset; - const char *spath; + const char *spath, *blsock; setprogname(argv[0]); spath = NULL; + blsock = _PATH_BLSOCK; reset = 0; tout = 0; flags = O_RDWR|O_EXCL|O_CLOEXEC; - while ((c = getopt(argc, argv, "C:c:D:dfr:P:t:v")) != -1) { + while ((c = getopt(argc, argv, "C:c:D:dfr:P:s:t:v")) != -1) { switch (c) { case 'C': controlprog = optarg; @@ -359,11 +359,14 @@ main(int argc, char *argv[]) case 'f': reset++; break; + case 'P': + spath = optarg; + break; case 'r': rulename = optarg; break; - case 'P': - spath = optarg; + case 's': + blsock = optarg; break; case 't': tout = atoi(optarg) * 1000; @@ -401,8 +404,10 @@ main(int argc, char *argv[]) update_interfaces(); conf_parse(configfile); if (reset) { - for (size_t i = 0; i < nconf; i++) - run_flush(&conf[i]); + for (size_t i = 0; i < rconf.cs_n; i++) + run_flush(&rconf.cs_c[i]); + for (size_t i = 0; i < lconf.cs_n; i++) + run_flush(&lconf.cs_c[i]); flags |= O_TRUNC; } @@ -412,7 +417,7 @@ main(int argc, char *argv[]) size_t maxfd = 0; if (spath == NULL) - addfd(&pfd, &bl, &nfd, &maxfd, _PATH_BLSOCK); + addfd(&pfd, &bl, &nfd, &maxfd, blsock); else { FILE *fp = fopen(spath, "r"); char *line; @@ -438,8 +443,8 @@ main(int argc, char *argv[]) } for (size_t t = 0; !done; t++) { - if (rconf) { - rconf = 0; + if (readconf) { + readconf = 0; conf_parse(configfile); } switch (poll(pfd, (nfds_t)nfd, tout)) { Index: src/external/bsd/blacklist/bin/conf.h diff -u src/external/bsd/blacklist/bin/conf.h:1.5 src/external/bsd/blacklist/bin/conf.h:1.6 --- src/external/bsd/blacklist/bin/conf.h:1.5 Wed Jan 21 14:24:03 2015 +++ src/external/bsd/blacklist/bin/conf.h Tue Jan 27 14:40:36 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: conf.h,v 1.5 2015/01/21 19:24:03 christos Exp $ */ +/* $NetBSD: conf.h,v 1.6 2015/01/27 19:40:36 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -31,24 +31,35 @@ #ifndef _CONF_H #define _CONF_H +#include <sys/socket.h> + struct conf { struct sockaddr_storage c_ss; + int c_lmask; int c_port; int c_proto; int c_family; int c_uid; int c_nfail; char c_name[128]; + int c_rmask; int c_duration; }; +struct confset { + struct conf *cs_c; + size_t cs_n; + size_t cs_m; +}; + #define CONFNAMESZ sizeof(((struct conf *)0)->c_name) __BEGIN_DECLS const char *conf_print(char *, size_t, const char *, const char *, const struct conf *); void conf_parse(const char *); -const struct conf *conf_find(int, uid_t, struct conf *); +const struct conf *conf_find(int, uid_t, const struct sockaddr_storage *, + struct conf *); __END_DECLS #endif /* _CONF_H */ Index: src/external/bsd/blacklist/bin/support.c diff -u src/external/bsd/blacklist/bin/support.c:1.5 src/external/bsd/blacklist/bin/support.c:1.6 --- src/external/bsd/blacklist/bin/support.c:1.5 Sat Jan 24 01:05:08 2015 +++ src/external/bsd/blacklist/bin/support.c Tue Jan 27 14:40:37 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: support.c,v 1.5 2015/01/24 06:05:08 christos Exp $ */ +/* $NetBSD: support.c,v 1.6 2015/01/27 19:40:37 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -33,7 +33,7 @@ #endif #include <sys/cdefs.h> -__RCSID("$NetBSD: support.c,v 1.5 2015/01/24 06:05:08 christos Exp $"); +__RCSID("$NetBSD: support.c,v 1.6 2015/01/27 19:40:37 christos Exp $"); #include <time.h> #include <string.h> @@ -70,7 +70,7 @@ vdlog(int level __unused, const char *fm { char buf[BUFSIZ]; - fprintf(stderr, "%s: ", getprogname()); +// fprintf(stderr, "%s: ", getprogname()); vfprintf(stderr, expandm(buf, sizeof(buf), fmt), ap); fprintf(stderr, "\n"); } Index: src/external/bsd/blacklist/bin/internal.c diff -u src/external/bsd/blacklist/bin/internal.c:1.4 src/external/bsd/blacklist/bin/internal.c:1.5 --- src/external/bsd/blacklist/bin/internal.c:1.4 Sun Jan 25 15:59:39 2015 +++ src/external/bsd/blacklist/bin/internal.c Tue Jan 27 14:40:37 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: internal.c,v 1.4 2015/01/25 20:59:39 christos Exp $ */ +/* $NetBSD: internal.c,v 1.5 2015/01/27 19:40:37 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -33,16 +33,16 @@ #endif #include <sys/cdefs.h> -__RCSID("$NetBSD: internal.c,v 1.4 2015/01/25 20:59:39 christos Exp $"); +__RCSID("$NetBSD: internal.c,v 1.5 2015/01/27 19:40:37 christos Exp $"); #include <stdio.h> #include <syslog.h> +#include "conf.h" #include "internal.h" int debug; const char *rulename = "blacklistd"; const char *controlprog = _PATH_BLCONTROL; -struct conf *conf; +struct confset lconf, rconf; struct ifaddrs *ifas; -size_t nconf; void (*lfun)(int, const char *, ...) = syslog; Index: src/external/bsd/blacklist/bin/run.h diff -u src/external/bsd/blacklist/bin/run.h:1.4 src/external/bsd/blacklist/bin/run.h:1.5 --- src/external/bsd/blacklist/bin/run.h:1.4 Wed Jan 21 23:13:04 2015 +++ src/external/bsd/blacklist/bin/run.h Tue Jan 27 14:40:37 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: run.h,v 1.4 2015/01/22 04:13:04 christos Exp $ */ +/* $NetBSD: run.h,v 1.5 2015/01/27 19:40:37 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -35,8 +35,7 @@ __BEGIN_DECLS struct conf; void run_flush(const struct conf *); struct sockaddr_storage; -int run_change(const char *, const struct conf *, - const struct sockaddr_storage *, char *, size_t); +int run_change(const char *, const struct conf *, char *, size_t); __END_DECLS #endif /* _RUN_H */ Index: src/external/bsd/blacklist/bin/state.h diff -u src/external/bsd/blacklist/bin/state.h:1.4 src/external/bsd/blacklist/bin/state.h:1.5 --- src/external/bsd/blacklist/bin/state.h:1.4 Sat Jan 24 02:46:20 2015 +++ src/external/bsd/blacklist/bin/state.h Tue Jan 27 14:40:37 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: state.h,v 1.4 2015/01/24 07:46:20 christos Exp $ */ +/* $NetBSD: state.h,v 1.5 2015/01/27 19:40:37 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -52,13 +52,10 @@ struct conf; DB *state_open(const char *, int, mode_t); int state_close(DB *); -int state_get(DB *, const struct sockaddr_storage *, const struct conf *, - struct dbinfo *); -int state_put(DB *, const struct sockaddr_storage *, const struct conf *, - const struct dbinfo *); -int state_del(DB *, const struct sockaddr_storage *, const struct conf *); -int state_iterate(DB *, struct sockaddr_storage *, struct conf *, - struct dbinfo *, unsigned int); +int state_get(DB *, const struct conf *, struct dbinfo *); +int state_put(DB *, const struct conf *, const struct dbinfo *); +int state_del(DB *, const struct conf *); +int state_iterate(DB *, struct conf *, struct dbinfo *, unsigned int); int state_sync(DB *); __END_DECLS Index: src/external/bsd/blacklist/bin/internal.h diff -u src/external/bsd/blacklist/bin/internal.h:1.11 src/external/bsd/blacklist/bin/internal.h:1.12 --- src/external/bsd/blacklist/bin/internal.h:1.11 Sun Jan 25 15:59:39 2015 +++ src/external/bsd/blacklist/bin/internal.h Tue Jan 27 14:40:37 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: internal.h,v 1.11 2015/01/25 20:59:39 christos Exp $ */ +/* $NetBSD: internal.h,v 1.12 2015/01/27 19:40:37 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -41,13 +41,13 @@ #define _PATH_BLSTATE "/var/db/blacklistd.db" #endif -extern struct conf *conf; -extern size_t nconf; +extern struct confset rconf, lconf; extern int debug; extern const char *rulename; extern const char *controlprog; extern struct ifaddrs *ifas; -void (*lfun)(int, const char *, ...); +void (*lfun)(int, const char *, ...) + __attribute__((__format__(__printf__, 2, 3))); #endif /* _INTERNAL_H */ Index: src/external/bsd/blacklist/bin/run.c diff -u src/external/bsd/blacklist/bin/run.c:1.11 src/external/bsd/blacklist/bin/run.c:1.12 --- src/external/bsd/blacklist/bin/run.c:1.11 Thu Jan 22 12:49:41 2015 +++ src/external/bsd/blacklist/bin/run.c Tue Jan 27 14:40:37 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: run.c,v 1.11 2015/01/22 17:49:41 christos Exp $ */ +/* $NetBSD: run.c,v 1.12 2015/01/27 19:40:37 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -33,7 +33,7 @@ #endif #include <sys/cdefs.h> -__RCSID("$NetBSD: run.c,v 1.11 2015/01/22 17:49:41 christos Exp $"); +__RCSID("$NetBSD: run.c,v 1.12 2015/01/27 19:40:37 christos Exp $"); #include <stdio.h> #ifdef HAVE_UTIL_H @@ -109,11 +109,10 @@ run_flush(const struct conf *c) } int -run_change(const char *how, const struct conf *c, - const struct sockaddr_storage *ss, char *id, size_t len) +run_change(const char *how, const struct conf *c, char *id, size_t len) { const char *prname; - char poname[64], adname[128], *rv; + char poname[64], adname[128], maskname[32], *rv; size_t off; switch (c->c_proto) { @@ -129,9 +128,10 @@ run_change(const char *how, const struct } snprintf(poname, sizeof(poname), "%d", c->c_port); - sockaddr_snprintf(adname, sizeof(adname), "%a", (const void *)ss); + snprintf(maskname, sizeof(maskname), "%d", c->c_lmask); + sockaddr_snprintf(adname, sizeof(adname), "%a", (const void *)&c->c_ss); - rv = run(how, c->c_name, prname, adname, poname, id, NULL); + rv = run(how, c->c_name, prname, adname, maskname, poname, id, NULL); if (rv == NULL) return -1; if (len != 0) { Index: src/external/bsd/blacklist/bin/state.c diff -u src/external/bsd/blacklist/bin/state.c:1.14 src/external/bsd/blacklist/bin/state.c:1.15 --- src/external/bsd/blacklist/bin/state.c:1.14 Sun Jan 25 15:50:30 2015 +++ src/external/bsd/blacklist/bin/state.c Tue Jan 27 14:40:37 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: state.c,v 1.14 2015/01/25 20:50:30 christos Exp $ */ +/* $NetBSD: state.c,v 1.15 2015/01/27 19:40:37 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -33,7 +33,7 @@ #endif #include <sys/cdefs.h> -__RCSID("$NetBSD: state.c,v 1.14 2015/01/25 20:50:30 christos Exp $"); +__RCSID("$NetBSD: state.c,v 1.15 2015/01/27 19:40:37 christos Exp $"); #include <sys/types.h> #include <sys/socket.h> @@ -88,13 +88,18 @@ state_open(const char *dbname, int flags return db; } -struct dbkey { - struct conf c; - struct sockaddr_storage ss; -}; +static int +state_sizecheck(const DBT *t) +{ + if (sizeof(struct conf) == t->size) + return 0; + (*lfun)(LOG_ERR, "Key size mismatch %zu != %zu", sizeof(struct conf), + t->size); + return -1; +} static void -dumpkey(const struct dbkey *k) +dumpkey(const struct conf *k) { char buf[10240]; size_t z; @@ -112,46 +117,17 @@ dumpkey(const struct dbkey *k) (*lfun)(LOG_DEBUG, "%s", buf); } -static void -makekey(struct dbkey *k, const struct sockaddr_storage *ss, - const struct conf *c) -{ - in_port_t port; - - memset(k, 0, sizeof(*k)); - port = htons((in_port_t)c->c_port); - k->c = *c; - k->ss = *ss; - switch (k->ss.ss_family) { - case AF_INET6: - ((struct sockaddr_in6 *)&k->ss)->sin6_port = port; - break; - case AF_INET: - ((struct sockaddr_in *)&k->ss)->sin_port = port; - break; - default: - (*lfun)(LOG_ERR, "%s: bad family %d", __func__, - k->ss.ss_family); - break; - } - if (debug > 1) - dumpkey(k); -} - int -state_del(DB *db, const struct sockaddr_storage *ss, const struct conf *c) +state_del(DB *db, const struct conf *c) { - struct dbkey key; int rv; DBT k; if (db == NULL) return -1; - makekey(&key, ss, c); - - k.data = &key; - k.size = sizeof(key); + k.data = __UNCONST(c); + k.size = sizeof(*c); switch (rv = (*db->del)(db, &k, 0)) { case 0: @@ -168,20 +144,16 @@ state_del(DB *db, const struct sockaddr_ } int -state_get(DB *db, const struct sockaddr_storage *ss, const struct conf *c, - struct dbinfo *dbi) +state_get(DB *db, const struct conf *c, struct dbinfo *dbi) { - struct dbkey key; int rv; DBT k, v; if (db == NULL) return -1; - makekey(&key, ss, c); - - k.data = &key; - k.size = sizeof(key); + k.data = __UNCONST(c); + k.size = sizeof(*c); switch (rv = (*db->get)(db, &k, &v, 0)) { case 0: @@ -200,20 +172,16 @@ state_get(DB *db, const struct sockaddr_ } int -state_put(DB *db, const struct sockaddr_storage *ss, const struct conf *c, - const struct dbinfo *dbi) +state_put(DB *db, const struct conf *c, const struct dbinfo *dbi) { - struct dbkey key; int rv; DBT k, v; if (db == NULL) return -1; - makekey(&key, ss, c); - - k.data = &key; - k.size = sizeof(key); + k.data = __UNCONST(c); + k.size = sizeof(*c); v.data = __UNCONST(dbi); v.size = sizeof(*dbi); @@ -234,10 +202,8 @@ state_put(DB *db, const struct sockaddr_ } int -state_iterate(DB *db, struct sockaddr_storage *ss, struct conf *c, - struct dbinfo *dbi, unsigned int first) +state_iterate(DB *db, struct conf *c, struct dbinfo *dbi, unsigned int first) { - struct dbkey *kp; int rv; DBT k, v; @@ -248,11 +214,11 @@ state_iterate(DB *db, struct sockaddr_st switch (rv = (*db->seq)(db, &k, &v, first)) { case 0: - kp = k.data; - *ss = kp->ss; - *c = kp->c; + if (state_sizecheck(&k) == -1) + return -1; + memcpy(c, k.data, sizeof(*c)); if (debug > 2) - dumpkey(kp); + dumpkey(c); memcpy(dbi, v.data, sizeof(*dbi)); if (debug > 1) (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); Index: src/external/bsd/blacklist/etc/blacklistd.conf diff -u src/external/bsd/blacklist/etc/blacklistd.conf:1.2 src/external/bsd/blacklist/etc/blacklistd.conf:1.3 --- src/external/bsd/blacklist/etc/blacklistd.conf:1.2 Fri Jan 23 17:34:00 2015 +++ src/external/bsd/blacklist/etc/blacklistd.conf Tue Jan 27 14:40:37 2015 @@ -1,12 +1,18 @@ # Blacklist rule -# Port type protocol owner name nfail disable -ssh stream tcp * * 3 6h -ssh stream tcp6 * * 3 6h -ftp stream tcp * * 3 6h -ftp stream tcp6 * * 3 6h -domain stream tcp named * 3 12h -domain dgram udp named * 3 12h -domain stream tcp6 named * 3 12h -domain dgram udp6 named * 3 12h -6161 stream tcp6 christos * 2 10m -* * * * * 3 60 +# adr/mask:port type proto owner name nfail disable +[local] +ssh stream tcp * * 3 6h +ssh stream tcp6 * * 3 6h +ftp stream tcp * * 3 6h +ftp stream tcp6 * * 3 6h +domain stream tcp named * 3 12h +domain dgram udp named * 3 12h +domain stream tcp6 named * 3 12h +domain dgram udp6 named * 3 12h +6161 stream tcp6 christos * 2 10m +* * * * * 3 60 + +# adr/mask:port type proto owner name nfail disable +bge0 stream tcp * =/24 = = +129.168.0.0/16 * * * = * * +default stream tcp * = = = Index: src/external/bsd/blacklist/libexec/blacklistd-helper diff -u src/external/bsd/blacklist/libexec/blacklistd-helper:1.1 src/external/bsd/blacklist/libexec/blacklistd-helper:1.2 --- src/external/bsd/blacklist/libexec/blacklistd-helper:1.1 Thu Jan 22 12:49:41 2015 +++ src/external/bsd/blacklist/libexec/blacklistd-helper Tue Jan 27 14:40:37 2015 @@ -1,19 +1,33 @@ #!/bin/sh echo "run $@" 1>&2 - +set -x # $1 command # $2 rulename # $3 protocol -# $4 address to -# $5 port -# $6 id +# $4 address +# $5 mask +# $6 proto +# $7 id case "$1" in add) - exec /sbin/npfctl rule $2 add block in final proto $3 from $4 to any port $5 + # GRR! +# case $4 in +# *:*) +# case $5 in +# 128) addr=$4;; +# *) addr=$4/$5;; +# esac;; +# *) +# case $5 in +# 32) addr=$4;; +# *) addr=$4/$5;; +# esac;; +# esac + exec /sbin/npfctl rule $2 add block in final proto $3 from $4/$5 to any port $6 ;; rem) - exec /sbin/npfctl rule $2 rem-id $6 + exec /sbin/npfctl rule $2 rem-id $7 ;; flush) exec /sbin/npfctl rule $2 flush Added files: Index: src/external/bsd/blacklist/bin/blacklistd.conf.5 diff -u /dev/null src/external/bsd/blacklist/bin/blacklistd.conf.5:1.1 --- /dev/null Tue Jan 27 14:40:37 2015 +++ src/external/bsd/blacklist/bin/blacklistd.conf.5 Tue Jan 27 14:40:36 2015 @@ -0,0 +1,222 @@ +.\" $NetBSD: blacklistd.conf.5,v 1.1 2015/01/27 19:40:36 christos Exp $ +.\" +.\" Copyright (c) 2015 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Christos Zoulas. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd January 25, 2015 +.Dt BLACKLISTD.CONF 5 +.Os +.Sh NAME +.Nm blacklistd.conf +.Nd configuration file format for blacklistd +.Sh DESCRIPTION +The +.Nm +files contains configuration lines for +.Xr blacklistd 8 . +It contains one entry per line, and is similar to +.Xr inetd.conf 5 . +There must be an entry for each field of the configuration file, with +entries for each field separated by a tab or a space. +Comments are denoted by a +.Dq # +at the beginning of a line. +.Pp +There are two kinds of configuration lines, +.Va local +and +.Va remote . +By default, configuration lines are +.Va local , +i.e. the address specified refers to the addresses on the local machine. +To switch to between +.Va local +and +.Va remote +configuration lines you can specify the stanzas: +.Dq [local] +and +.Dq [remote] . +.Pp +On +.Va local +and +.Va remote +lines +.Dq * +means use the default, or wildcard match. +In addition, for +.Va remote +lines +.Dq = +means use the values from the matched +.Va local +configuration line. +.Pp +The first four fields, +.Va location , +.Va type , +.Va proto , +and +.Va owner +are used to match the +.Va local +or +.Va remote +addresses whereas, the last 3 fields +.Va name , +.Va nfail , +and +.Va disable +are used to modify the filtering action. +.Pp +The first field denotes the +.Va location +as an address, mask, and port. +The syntax for the +.Va location +is: +.Bd -literal -offset indent: + [<address>|<interface>][/<mask>][:<port>] +.Ed +.Pp +The +.Dv address +can be an IPv4 address in numeric format, an IPv6 address +in numeric format and enclosed by square brackets, or an interface name. +Mask modifiers are not allowed on interfaces because interfaces +have multiple address in different protocols where the mask has a different +size. +.Pp +The +.Dv mask +is always numeric, but the +.Dv port +can be either numeric or symbolic. +.Pp +The second field is the socket +.Va type : +.Dv stream , +.Dv dgram , +or numeric. +The third field is the +.Va prococol : +.Dv tcp , +.Dv udp , +.Dv tcp6 , +.Dv udp6 , +or numeric. +The fourth file is the effective user ( +.Va owner ) +of the daemon process reporting the event, +either as a username or a userid. +.Pp +The rest of the fields are controlling the behavior of the filter. +.Pp +The +.Va name +field, is the name of the packet filter rule to be used. +If the +.Va name +starts with a +.Dq - , +then the default rulename is prepended to the given name. +If the +.Dv name +contains a +.Dq / , +the remaining portion of the name is interpreted as the mask to be +applied to the address specified in the rule, so one can block whole +subnets for a single rule violation. +.Pp +The +.Va nfail +field contains the number of failed attempts before access is blocked, +defaulting to +.Dq * +meaning never, and the last field +.Va disable +specifies the amount of time since the last access that the blocking +rule should be active, defaulting to +.Dq * +meaning forever. +The default unit for +.Va disable +is seconds, but one can specify suffixes for different units, such as +.Dq m +for minutes +.Dq h +for hours and +.Dq d +for days. +.Pp +Matching is done first by checking the +.Va local +rules one by one, from the most specific to the least specific. +If a match is found, then the +.Va remote +rules are applied, and if a match is found the +.Va name , +.Va nfail , +and +.Va disable +fields can be altered by the +.Va remote +rule that matched. +.Pp +The +.Va remote +rules can be used for whitelisting specific addresses, changing the mask +size, or the rule that the packet filter uses, the number of failed attempts, +or the blocked duration. +.Sh FILES +.Bl -tag -width /etc/blacklistd.conf -compact +.It Pa /etc/blacklistd.conf +Configuration file. +.El +.Sh EXAMPLES +.Bd -literal -offset +# Block ssh, after 3 attempts for 6 hours on the bnx0 interface +[local] +# location type proto owner name nfail duration +bnx0:ssh * * * * 3 6h +[remote] +# Never block 1.2.3.4 +1.2.3.4:ssh * * * * * * +# For addresses coming from 8.8.0.0/16 block class C networks instead +# individual hosts, but keep the rest of the blocking parameters the same. +8.8.0.0/16:ssh * * * /24 = = +.Ed +.Sh SEE ALSO +.Xr blacklistd 8 , +.Xr blacklistctl 8 +.Sh HISTORY +.Nm +appeared in +.Nx 8 . +.Sh AUTHORS +.An Christos Zoulas