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

Reply via email to