Index: head/contrib/blacklist/bin/blacklistctl.c =================================================================== --- head/contrib/blacklist/bin/blacklistctl.c (revision 354398) +++ head/contrib/blacklist/bin/blacklistctl.c (revision 354399) @@ -1,151 +1,168 @@ -/* $NetBSD: blacklistctl.c,v 1.21 2016/11/02 03:15:07 jnemeth Exp $ */ +/* $NetBSD: blacklistctl.c,v 1.23 2018/05/24 19:21:01 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include -__RCSID("$NetBSD: blacklistctl.c,v 1.21 2016/11/02 03:15:07 jnemeth Exp $"); +__RCSID("$NetBSD: blacklistctl.c,v 1.23 2018/05/24 19:21:01 christos Exp $"); #include #include #ifdef HAVE_LIBUTIL_H #include #endif #ifdef HAVE_UTIL_H #include #endif #include #include #include #include #include #include #include #include "conf.h" #include "state.h" #include "internal.h" #include "support.h" static __dead void usage(int c) { if (c == 0) warnx("Missing/unknown command"); else warnx("Unknown option `%c'", (char)c); fprintf(stderr, "Usage: %s dump [-abdnrw]\n", getprogname()); exit(EXIT_FAILURE); } +static const char * +star(char *buf, size_t len, int val) +{ + if (val == -1) + return "*"; + snprintf(buf, len, "%d", val); + return buf; +} + int main(int argc, char *argv[]) { const char *dbname = _PATH_BLSTATE; DB *db; struct conf c; struct dbinfo dbi; unsigned int i; struct timespec ts; int all, blocked, remain, wide, noheader; int o; noheader = wide = blocked = all = remain = 0; lfun = dlog; if (argc == 1 || strcmp(argv[1], "dump") != 0) usage(0); argc--; argv++; while ((o = getopt(argc, argv, "abD:dnrw")) != -1) switch (o) { case 'a': all = 1; blocked = 0; break; case 'b': blocked = 1; break; case 'D': dbname = optarg; break; case 'd': debug++; break; case 'n': noheader = 1; break; case 'r': remain = 1; break; case 'w': wide = 1; break; default: usage(o); break; } db = state_open(dbname, O_RDONLY, 0); if (db == NULL) err(EXIT_FAILURE, "Can't open `%s'", dbname); clock_gettime(CLOCK_REALTIME, &ts); wide = wide ? 8 * 4 + 7 : 4 * 3 + 3; if (!noheader) printf("%*.*s/ma:port\tid\tnfail\t%s\n", wide, wide, "address", remain ? "remaining time" : "last access"); for (i = 1; state_iterate(db, &c, &dbi, i) != 0; i = 0) { char buf[BUFSIZ]; + char mbuf[64], pbuf[64]; if (!all) { if (blocked) { - if (dbi.count < c.c_nfail) + if (c.c_nfail == -1 || dbi.count < c.c_nfail) continue; } else { if (dbi.count >= c.c_nfail) continue; } } 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)); - else - fmttime(buf, sizeof(buf), dbi.last); - printf("%s\t%d/%d\t%-s\n", dbi.id, dbi.count, c.c_nfail, buf); + printf("%*.*s/%s:%s\t", wide, wide, buf, + star(mbuf, sizeof(mbuf), c.c_lmask), + star(pbuf, sizeof(pbuf), c.c_port)); + if (c.c_duration == -1) { + strlcpy(buf, "never", sizeof(buf)); + } else { + if (remain) + fmtydhms(buf, sizeof(buf), + c.c_duration - (ts.tv_sec - dbi.last)); + else + fmttime(buf, sizeof(buf), dbi.last); + } + printf("%s\t%d/%s\t%-s\n", dbi.id, dbi.count, + star(mbuf, sizeof(mbuf), c.c_nfail), buf); } state_close(db); return EXIT_SUCCESS; } Index: head/contrib/blacklist/bin/blacklistd.c =================================================================== --- head/contrib/blacklist/bin/blacklistd.c (revision 354398) +++ head/contrib/blacklist/bin/blacklistd.c (revision 354399) @@ -1,579 +1,582 @@ -/* $NetBSD: blacklistd.c,v 1.37 2017/02/18 00:26:16 christos Exp $ */ +/* $NetBSD: blacklistd.c,v 1.38 2019/02/27 02:20:18 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include -__RCSID("$NetBSD: blacklistd.c,v 1.37 2017/02/18 00:26:16 christos Exp $"); +__RCSID("$NetBSD: blacklistd.c,v 1.38 2019/02/27 02:20:18 christos Exp $"); #include #include #include #ifdef HAVE_LIBUTIL_H #include #endif #ifdef HAVE_UTIL_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bl.h" #include "internal.h" #include "conf.h" #include "run.h" #include "state.h" #include "support.h" static const char *configfile = _PATH_BLCONF; static DB *state; static const char *dbfile = _PATH_BLSTATE; static sig_atomic_t readconf; static sig_atomic_t done; static int vflag; static void sigusr1(int n __unused) { debug++; } static void sigusr2(int n __unused) { debug--; } static void sighup(int n __unused) { readconf++; } static void sigdone(int n __unused) { done++; } static __dead void usage(int c) { if (c) warnx("Unknown option `%c'", (char)c); fprintf(stderr, "Usage: %s [-vdfr] [-c ] [-R ] " "[-P ] [-C ] [-D ] " "[-s ] [-t ]\n", getprogname()); exit(EXIT_FAILURE); } static int getremoteaddress(bl_info_t *bi, struct sockaddr_storage *rss, socklen_t *rsl) { *rsl = sizeof(*rss); memset(rss, 0, *rsl); if (getpeername(bi->bi_fd, (void *)rss, rsl) != -1) return 0; if (errno != ENOTCONN) { (*lfun)(LOG_ERR, "getpeername failed (%m)"); return -1; } if (bi->bi_slen == 0) { (*lfun)(LOG_ERR, "unconnected socket with no peer in message"); return -1; } switch (bi->bi_ss.ss_family) { case AF_INET: *rsl = sizeof(struct sockaddr_in); break; case AF_INET6: *rsl = sizeof(struct sockaddr_in6); break; default: (*lfun)(LOG_ERR, "bad client passed socket family %u", (unsigned)bi->bi_ss.ss_family); return -1; } if (*rsl != bi->bi_slen) { (*lfun)(LOG_ERR, "bad client passed socket length %u != %u", (unsigned)*rsl, (unsigned)bi->bi_slen); return -1; } memcpy(rss, &bi->bi_ss, *rsl); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN if (*rsl != rss->ss_len) { (*lfun)(LOG_ERR, "bad client passed socket internal length %u != %u", (unsigned)*rsl, (unsigned)rss->ss_len); return -1; } #endif return 0; } static void process(bl_t bl) { struct sockaddr_storage rss; socklen_t rsl; char rbuf[BUFSIZ]; bl_info_t *bi; struct conf c; struct dbinfo dbi; struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { (*lfun)(LOG_ERR, "clock_gettime failed (%m)"); return; } if ((bi = bl_recv(bl)) == NULL) { (*lfun)(LOG_ERR, "no message (%m)"); return; } if (getremoteaddress(bi, &rss, &rsl) == -1) goto out; if (debug) { sockaddr_snprintf(rbuf, sizeof(rbuf), "%a:%p", (void *)&rss); (*lfun)(LOG_DEBUG, "processing type=%d fd=%d remote=%s msg=%s" " uid=%lu gid=%lu", bi->bi_type, bi->bi_fd, rbuf, bi->bi_msg, (unsigned long)bi->bi_uid, (unsigned long)bi->bi_gid); } if (conf_find(bi->bi_fd, bi->bi_uid, &rss, &c) == NULL) { (*lfun)(LOG_DEBUG, "no rule matched"); goto out; } if (state_get(state, &c, &dbi) == -1) goto out; if (debug) { char b1[128], b2[128]; (*lfun)(LOG_DEBUG, "%s: initial db state for %s: count=%d/%d " "last=%s now=%s", __func__, rbuf, dbi.count, c.c_nfail, fmttime(b1, sizeof(b1), dbi.last), fmttime(b2, sizeof(b2), ts.tv_sec)); } switch (bi->bi_type) { case BL_ABUSE: /* * If the application has signaled abusive behavior, * set the number of fails to be one less than the * configured limit. Fallthrough to the normal BL_ADD * processing, which will increment the failure count * to the threshhold, and block the abusive address. */ if (c.c_nfail != -1) dbi.count = c.c_nfail - 1; /*FALLTHROUGH*/ case BL_ADD: dbi.count++; dbi.last = ts.tv_sec; if (dbi.id[0]) { /* * We should not be getting this since the rule * should have blocked the address. A possible * explanation is that someone removed that rule, * and another would be that we got another attempt * before we added the rule. In anycase, we remove * and re-add the rule because we don't want to add * it twice, because then we'd lose track of it. */ (*lfun)(LOG_DEBUG, "rule exists %s", dbi.id); (void)run_change("rem", &c, dbi.id, 0); dbi.id[0] = '\0'; } if (c.c_nfail != -1 && dbi.count >= c.c_nfail) { 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/%d:%d for %d seconds", rbuf, c.c_lmask, c.c_port, c.c_duration); } break; case BL_DELETE: if (dbi.last == 0) goto out; dbi.count = 0; dbi.last = 0; break; case BL_BADUSER: /* ignore for now */ break; default: (*lfun)(LOG_ERR, "unknown message %d", bi->bi_type); } state_put(state, &c, &dbi); out: close(bi->bi_fd); if (debug) { char b1[128], b2[128]; (*lfun)(LOG_DEBUG, "%s: final db state for %s: count=%d/%d " "last=%s now=%s", __func__, rbuf, dbi.count, c.c_nfail, fmttime(b1, sizeof(b1), dbi.last), fmttime(b2, sizeof(b2), ts.tv_sec)); } } static void update_interfaces(void) { struct ifaddrs *oifas, *nifas; if (getifaddrs(&nifas) == -1) return; oifas = ifas; ifas = nifas; if (oifas) freeifaddrs(oifas); } static void update(void) { struct timespec ts; struct conf c; struct dbinfo dbi; unsigned int f, n; char buf[128]; void *ss = &c.c_ss; if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { (*lfun)(LOG_ERR, "clock_gettime failed (%m)"); return; } again: for (n = 0, f = 1; state_iterate(state, &c, &dbi, f) == 1; f = 0, n++) { time_t when = c.c_duration + dbi.last; if (debug > 1) { char b1[64], b2[64]; sockaddr_snprintf(buf, sizeof(buf), "%a:%p", ss); (*lfun)(LOG_DEBUG, "%s:[%u] %s count=%d duration=%d " "last=%s " "now=%s", __func__, n, buf, dbi.count, c.c_duration, fmttime(b1, sizeof(b1), dbi.last), fmttime(b2, sizeof(b2), ts.tv_sec)); } if (c.c_duration == -1 || when >= ts.tv_sec) continue; if (dbi.id[0]) { run_change("rem", &c, dbi.id, 0); sockaddr_snprintf(buf, sizeof(buf), "%a", ss); (*lfun)(LOG_INFO, "released %s/%d:%d after %d seconds", buf, c.c_lmask, c.c_port, c.c_duration); } state_del(state, &c); goto again; } } static void addfd(struct pollfd **pfdp, bl_t **blp, size_t *nfd, size_t *maxfd, const char *path) { bl_t bl = bl_create(true, path, vflag ? vdlog : vsyslog); if (bl == NULL || !bl_isconnected(bl)) exit(EXIT_FAILURE); if (*nfd >= *maxfd) { *maxfd += 10; *blp = realloc(*blp, sizeof(**blp) * *maxfd); if (*blp == NULL) err(EXIT_FAILURE, "malloc"); *pfdp = realloc(*pfdp, sizeof(**pfdp) * *maxfd); if (*pfdp == NULL) err(EXIT_FAILURE, "malloc"); } (*pfdp)[*nfd].fd = bl_getfd(bl); (*pfdp)[*nfd].events = POLLIN; (*blp)[*nfd] = bl; *nfd += 1; } static void uniqueadd(struct conf ***listp, size_t *nlist, size_t *mlist, struct conf *c) { struct conf **list = *listp; if (c->c_name[0] == '\0') return; for (size_t i = 0; i < *nlist; i++) { if (strcmp(list[i]->c_name, c->c_name) == 0) return; } if (*nlist == *mlist) { *mlist += 10; void *p = realloc(*listp, *mlist * sizeof(*list)); if (p == NULL) err(EXIT_FAILURE, "Can't allocate for rule list"); list = *listp = p; } list[(*nlist)++] = c; } static void rules_flush(void) { struct conf **list; size_t nlist, mlist; list = NULL; mlist = nlist = 0; for (size_t i = 0; i < rconf.cs_n; i++) uniqueadd(&list, &nlist, &mlist, &rconf.cs_c[i]); for (size_t i = 0; i < lconf.cs_n; i++) uniqueadd(&list, &nlist, &mlist, &lconf.cs_c[i]); for (size_t i = 0; i < nlist; i++) run_flush(list[i]); free(list); } static void rules_restore(void) { struct conf c; struct dbinfo dbi; unsigned int f; for (f = 1; state_iterate(state, &c, &dbi, f) == 1; f = 0) { if (dbi.id[0] == '\0') continue; - (void)run_change("rem", &c, dbi.id, 0); (void)run_change("add", &c, dbi.id, sizeof(dbi.id)); } } int main(int argc, char *argv[]) { int c, tout, flags, flush, restore, ret; const char *spath, **blsock; size_t nblsock, maxblsock; setprogname(argv[0]); spath = NULL; blsock = NULL; maxblsock = nblsock = 0; flush = 0; restore = 0; tout = 0; flags = O_RDWR|O_EXCL|O_CLOEXEC; while ((c = getopt(argc, argv, "C:c:D:dfP:rR:s:t:v")) != -1) { switch (c) { case 'C': controlprog = optarg; break; case 'c': configfile = optarg; break; case 'D': dbfile = optarg; break; case 'd': debug++; break; case 'f': flush++; break; case 'P': spath = optarg; break; case 'R': rulename = optarg; break; case 'r': restore++; break; case 's': if (nblsock >= maxblsock) { maxblsock += 10; void *p = realloc(blsock, sizeof(*blsock) * maxblsock); if (p == NULL) err(EXIT_FAILURE, "Can't allocate memory for %zu sockets", maxblsock); blsock = p; } blsock[nblsock++] = optarg; break; case 't': tout = atoi(optarg) * 1000; break; case 'v': vflag++; break; default: usage(c); } } argc -= optind; if (argc) usage(0); signal(SIGHUP, sighup); signal(SIGINT, sigdone); signal(SIGQUIT, sigdone); signal(SIGTERM, sigdone); signal(SIGUSR1, sigusr1); signal(SIGUSR2, sigusr2); openlog(getprogname(), LOG_PID, LOG_DAEMON); if (debug) { lfun = dlog; if (tout == 0) tout = 5000; } else { if (tout == 0) tout = 15000; } update_interfaces(); conf_parse(configfile); if (flush) { rules_flush(); - flags |= O_TRUNC; + if (!restore) + flags |= O_TRUNC; } struct pollfd *pfd = NULL; bl_t *bl = NULL; size_t nfd = 0; size_t maxfd = 0; for (size_t i = 0; i < nblsock; i++) addfd(&pfd, &bl, &nfd, &maxfd, blsock[i]); free(blsock); if (spath) { FILE *fp = fopen(spath, "r"); char *line; if (fp == NULL) err(EXIT_FAILURE, "Can't open `%s'", spath); for (; (line = fparseln(fp, NULL, NULL, NULL, 0)) != NULL; free(line)) addfd(&pfd, &bl, &nfd, &maxfd, line); fclose(fp); } if (nfd == 0) addfd(&pfd, &bl, &nfd, &maxfd, _PATH_BLSOCK); state = state_open(dbfile, flags, 0600); if (state == NULL) state = state_open(dbfile, flags | O_CREAT, 0600); if (state == NULL) return EXIT_FAILURE; - if (restore) + if (restore) { + if (!flush) + rules_flush(); rules_restore(); + } if (!debug) { if (daemon(0, 0) == -1) err(EXIT_FAILURE, "daemon failed"); if (pidfile(NULL) == -1) err(EXIT_FAILURE, "Can't create pidfile"); } for (size_t t = 0; !done; t++) { if (readconf) { readconf = 0; conf_parse(configfile); } ret = poll(pfd, (nfds_t)nfd, tout); if (debug) (*lfun)(LOG_DEBUG, "received %d from poll()", ret); switch (ret) { case -1: if (errno == EINTR) continue; (*lfun)(LOG_ERR, "poll (%m)"); return EXIT_FAILURE; case 0: state_sync(state); break; default: for (size_t i = 0; i < nfd; i++) if (pfd[i].revents & POLLIN) process(bl[i]); } if (t % 100 == 0) state_sync(state); if (t % 10000 == 0) update_interfaces(); update(); } state_close(state); return 0; } Index: head/contrib/blacklist/bin/blacklistd.conf.5 =================================================================== --- head/contrib/blacklist/bin/blacklistd.conf.5 (revision 354398) +++ head/contrib/blacklist/bin/blacklistd.conf.5 (revision 354399) @@ -1,227 +1,229 @@ -.\" $NetBSD: blacklistd.conf.5,v 1.5 2016/06/08 12:48:37 wiz Exp $ +.\" $NetBSD: blacklistd.conf.5,v 1.7 2017/06/07 13:50:57 wiz 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 June 7, 2016 +.Dd June 5, 2017 .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 +files contains configuration entries for +.Xr blacklistd 8 +in a fashion 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. +Only one entry per line is permitted. +Every entry must have all fields populated. +Each field can be 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 [
|][/][:] .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 +can have multiple addresses 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. +applied to the address specified in the rule, causing a single rule violation to +block the entire subnet for the configured prefix. .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. +rules individually, in the order of 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 +rules are applied. +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. +size, the rule that the packet filter uses, the number of failed attempts, +or the block duration. .Sh FILES .Bl -tag -width /etc/blacklistd.conf -compact .It Pa /etc/blacklistd.conf Configuration file. .El .Sh EXAMPLES -.Bd -literal -offset +.Bd -literal -offset 8n # 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 blacklistctl 8 , .Xr blacklistd 8 .Sh HISTORY .Nm first appeared in .Nx 7 . .Fx support for .Nm was implemented in .Fx 11 . .Sh AUTHORS .An Christos Zoulas Index: head/contrib/blacklist/bin/support.c =================================================================== --- head/contrib/blacklist/bin/support.c (revision 354398) +++ head/contrib/blacklist/bin/support.c (revision 354399) @@ -1,157 +1,161 @@ -/* $NetBSD: support.c,v 1.8 2016/04/04 15:52:56 christos Exp $ */ +/* $NetBSD: support.c,v 1.9 2018/09/18 22:12:19 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include -__RCSID("$NetBSD: support.c,v 1.8 2016/04/04 15:52:56 christos Exp $"); +__RCSID("$NetBSD: support.c,v 1.9 2018/09/18 22:12:19 christos Exp $"); #include #include #include #include #include #include #include #include "support.h" static __attribute__((__format_arg__(3))) const char * expandm(char *buf, size_t len, const char *fmt) { char *p; size_t r; if ((p = strstr(fmt, "%m")) == NULL) return fmt; r = (size_t)(p - fmt); if (r >= len) return fmt; strlcpy(buf, fmt, r + 1); strlcat(buf, strerror(errno), len); strlcat(buf, fmt + r + 2, len); return buf; } void vdlog(int level __unused, const char *fmt, va_list ap) { char buf[BUFSIZ]; // fprintf(stderr, "%s: ", getprogname()); vfprintf(stderr, expandm(buf, sizeof(buf), fmt), ap); fprintf(stderr, "\n"); } void dlog(int level, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vdlog(level, fmt, ap); va_end(ap); } const char * fmttime(char *b, size_t l, time_t t) { struct tm tm; if (localtime_r(&t, &tm) == NULL) snprintf(b, l, "*%jd*", (intmax_t)t); else strftime(b, l, "%Y/%m/%d %H:%M:%S", &tm); return b; } const char * fmtydhms(char *b, size_t l, time_t t) { time_t s, m, h, d, y; int z; size_t o; s = t % 60; t /= 60; + m = t % 60; t /= 60; - h = t % 60; + + h = t % 24; t /= 24; - d = t % 24; - t /= 356; + + d = t % 365; + t /= 365; + y = t; z = 0; o = 0; #define APPEND(a) \ if (a) { \ z = snprintf(b + o, l - o, "%jd%s", (intmax_t)a, __STRING(a)); \ if (z == -1) \ return b; \ o += (size_t)z; \ if (o >= l) \ return b; \ } APPEND(y) APPEND(d) APPEND(h) APPEND(m) APPEND(s) return b; } ssize_t blhexdump(char *buf, size_t len, const char *str, const void *b, size_t l) { size_t z, cz; int r; const unsigned char *p = b; const unsigned char *e = p + l; r = snprintf(buf, len, "%s: ", str); if (r == -1) return -1; if ((cz = z = (size_t)r) >= len) cz = len; while (p < e) { r = snprintf(buf + cz, len - cz, "%.2x", *p++); if (r == -1) return -1; if ((cz = (z += (size_t)r)) >= len) cz = len; } return (ssize_t)z; } Index: head/contrib/blacklist/diff/ssh.diff =================================================================== --- head/contrib/blacklist/diff/ssh.diff (revision 354398) +++ head/contrib/blacklist/diff/ssh.diff (revision 354399) @@ -1,231 +1,150 @@ --- /dev/null 2015-01-22 23:10:33.000000000 -0500 +++ dist/pfilter.c 2015-01-22 23:46:03.000000000 -0500 -@@ -0,0 +1,28 @@ +@@ -0,0 +1,32 @@ +#include "namespace.h" +#include "includes.h" +#include "ssh.h" +#include "packet.h" +#include "log.h" +#include "pfilter.h" +#include + +static struct blacklist *blstate; + +void +pfilter_init(void) +{ + blstate = blacklist_open(); +} + +void +pfilter_notify(int a) +{ + int fd; + if (blstate == NULL) + pfilter_init(); + if (blstate == NULL) + return; + // XXX: 3? + fd = packet_connection_is_on_socket() ? packet_get_connection_in() : 3; + (void)blacklist_r(blstate, a, fd, "ssh"); ++ if (a == 0) { ++ blacklist_close(blstate); ++ blstate = NULL; ++ } +} --- /dev/null 2015-01-20 21:14:44.000000000 -0500 +++ dist/pfilter.h 2015-01-20 20:16:20.000000000 -0500 @@ -0,0 +1,3 @@ + +void pfilter_notify(int); +void pfilter_init(void); Index: bin/sshd/Makefile =================================================================== RCS file: /cvsroot/src/crypto/external/bsd/openssh/bin/sshd/Makefile,v retrieving revision 1.10 diff -u -u -r1.10 Makefile --- bin/sshd/Makefile 19 Oct 2014 16:30:58 -0000 1.10 +++ bin/sshd/Makefile 22 Jan 2015 21:39:21 -0000 @@ -15,7 +15,7 @@ auth2-none.c auth2-passwd.c auth2-pubkey.c \ monitor_mm.c monitor.c monitor_wrap.c \ kexdhs.c kexgexs.c kexecdhs.c sftp-server.c sftp-common.c \ - roaming_common.c roaming_serv.c sandbox-rlimit.c + roaming_common.c roaming_serv.c sandbox-rlimit.c pfilter.c COPTS.auth-options.c= -Wno-pointer-sign COPTS.ldapauth.c= -Wno-format-nonliteral # XXX: should fix @@ -68,3 +68,6 @@ LDADD+= -lwrap DPADD+= ${LIBWRAP} + +LDADD+= -lblacklist +DPADD+= ${LIBBLACKLIST} -Index: dist/auth.c -=================================================================== -RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/auth.c,v -retrieving revision 1.10 -diff -u -u -r1.10 auth.c ---- dist/auth.c 19 Oct 2014 16:30:58 -0000 1.10 -+++ dist/auth.c 22 Jan 2015 21:39:22 -0000 -@@ -62,6 +62,7 @@ - #include "monitor_wrap.h" - #include "krl.h" - #include "compat.h" -+#include "pfilter.h" - - #ifdef HAVE_LOGIN_CAP - #include -@@ -362,6 +363,8 @@ - compat20 ? "ssh2" : "ssh1", - authctxt->info != NULL ? ": " : "", - authctxt->info != NULL ? authctxt->info : ""); -+ if (!authctxt->postponed) -+ pfilter_notify(!authenticated); - free(authctxt->info); - authctxt->info = NULL; - } -Index: dist/sshd.c -=================================================================== -RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/sshd.c,v -retrieving revision 1.15 -diff -u -u -r1.15 sshd.c ---- dist/sshd.c 28 Oct 2014 21:36:16 -0000 1.15 -+++ dist/sshd.c 22 Jan 2015 21:39:22 -0000 -@@ -109,6 +109,7 @@ - #include "roaming.h" - #include "ssh-sandbox.h" - #include "version.h" -+#include "pfilter.h" - - #ifdef LIBWRAP - #include -@@ -364,6 +365,7 @@ - killpg(0, SIGTERM); - } - -+ pfilter_notify(1); - /* Log error and exit. */ - sigdie("Timeout before authentication for %s", get_remote_ipaddr()); - } -@@ -1160,6 +1162,7 @@ - for (i = 0; i < options.max_startups; i++) - startup_pipes[i] = -1; - -+ pfilter_init(); - /* - * Stay listening for connections until the system crashes or - * the daemon is killed with a signal. -Index: auth1.c -=================================================================== -RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/auth1.c,v -retrieving revision 1.9 -diff -u -u -r1.9 auth1.c ---- auth1.c 19 Oct 2014 16:30:58 -0000 1.9 -+++ auth1.c 14 Feb 2015 15:40:51 -0000 -@@ -41,6 +41,7 @@ +diff -ru openssh-7.7p1/auth-pam.c dist/auth-pam.c +--- openssh-7.7p1/auth-pam.c 2018-04-02 01:38:28.000000000 -0400 ++++ dist/auth-pam.c 2018-05-23 11:56:22.206661484 -0400 +@@ -103,6 +103,7 @@ + #include "ssh-gss.h" #endif #include "monitor_wrap.h" - #include "buffer.h" +#include "pfilter.h" - /* import */ extern ServerOptions options; -@@ -445,6 +446,7 @@ - else { - debug("do_authentication: invalid user %s", user); - authctxt->pw = fakepw(); -+ pfilter_notify(1); - } + extern Buffer loginmsg; +@@ -526,6 +527,7 @@ + ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, &buffer); + else + ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer); ++ pfilter_notify(1); + buffer_free(&buffer); + pthread_exit(NULL); - /* Configuration may have changed as a result of Match */ -Index: auth2.c -=================================================================== -RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/auth2.c,v -retrieving revision 1.9 -diff -u -u -r1.9 auth2.c ---- auth2.c 19 Oct 2014 16:30:58 -0000 1.9 -+++ auth2.c 14 Feb 2015 15:40:51 -0000 -@@ -52,6 +52,7 @@ +@@ -804,6 +806,7 @@ + free(msg); + return (0); + } ++ pfilter_notify(1); + error("PAM: %s for %s%.100s from %.100s", msg, + sshpam_authctxt->valid ? "" : "illegal user ", + sshpam_authctxt->user, +diff -ru openssh-7.7p1/auth2.c dist/auth2.c +--- openssh-7.7p1/auth2.c 2018-04-02 01:38:28.000000000 -0400 ++++ dist/auth2.c 2018-05-23 11:57:31.022197317 -0400 +@@ -51,6 +51,7 @@ + #include "dispatch.h" #include "pathnames.h" #include "buffer.h" - #include "canohost.h" +#include "pfilter.h" #ifdef GSSAPI #include "ssh-gss.h" -@@ -256,6 +257,7 @@ +@@ -242,6 +243,7 @@ } else { - logit("input_userauth_request: invalid user %s", user); + /* Invalid user, fake password information */ authctxt->pw = fakepw(); + pfilter_notify(1); - } - #ifdef USE_PAM - if (options.use_pam) -Index: sshd.c -=================================================================== -RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/sshd.c,v -retrieving revision 1.16 -diff -u -r1.16 sshd.c ---- sshd.c 25 Jan 2015 15:52:44 -0000 1.16 -+++ sshd.c 14 Feb 2015 09:55:06 -0000 -@@ -628,6 +628,8 @@ - explicit_bzero(pw->pw_passwd, strlen(pw->pw_passwd)); - endpwent(); - -+ pfilter_init(); -+ - /* Change our root directory */ - if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) - fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, - -Index: auth-pam.c -=================================================================== -RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/auth-pam.c,v -retrieving revision 1.7 -diff -u -u -r1.7 auth-pam.c ---- auth-pam.c 3 Jul 2015 00:59:59 -0000 1.7 -+++ auth-pam.c 23 Jan 2016 00:01:16 -0000 -@@ -114,6 +114,7 @@ - #include "ssh-gss.h" + #ifdef SSH_AUDIT_EVENTS + PRIVSEP(audit_event(SSH_INVALID_USER)); #endif - #include "monitor_wrap.h" +Only in dist: pfilter.c +Only in dist: pfilter.h +diff -ru openssh-7.7p1/sshd.c dist/sshd.c +--- openssh-7.7p1/sshd.c 2018-04-02 01:38:28.000000000 -0400 ++++ dist/sshd.c 2018-05-23 11:59:39.573197347 -0400 +@@ -122,6 +122,7 @@ + #include "auth-options.h" + #include "version.h" + #include "ssherr.h" +#include "pfilter.h" - extern ServerOptions options; - extern Buffer loginmsg; -@@ -809,6 +810,7 @@ - free(msg); - return (0); - } -+ pfilter_notify(1); - error("PAM: %s for %s%.100s from %.100s", msg, - sshpam_authctxt->valid ? "" : "illegal user ", - sshpam_authctxt->user, -Index: auth.c -=================================================================== -RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/auth.c,v -retrieving revision 1.15 -diff -u -u -r1.15 auth.c ---- auth.c 21 Aug 2015 08:20:59 -0000 1.15 -+++ auth.c 23 Jan 2016 00:01:16 -0000 -@@ -656,6 +656,7 @@ + /* Re-exec fds */ + #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) +@@ -346,6 +347,7 @@ + static void + grace_alarm_handler(int sig) + { ++ pfilter_notify(1); + if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0) + kill(pmonitor->m_pid, SIGALRM); - pw = getpwnam(user); - if (pw == NULL) { -+ pfilter_notify(1); - logit("Invalid user %.100s from %.100s", - user, get_remote_ipaddr()); - return (NULL); -Index: auth1.c -=================================================================== -RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/auth1.c,v -retrieving revision 1.12 -diff -u -u -r1.12 auth1.c ---- auth1.c 3 Jul 2015 00:59:59 -0000 1.12 -+++ auth1.c 23 Jan 2016 00:01:16 -0000 -@@ -376,6 +376,7 @@ - char *msg; - size_t len; +@@ -1835,6 +1837,8 @@ + if (test_flag) + exit(0); -+ pfilter_notify(1); - error("Access denied for user %s by PAM account " - "configuration", authctxt->user); - len = buffer_len(&loginmsg); ++ pfilter_init(); ++ + /* + * Clear out any supplemental groups we may have inherited. This + * prevents inadvertent creation of files with bad modes (in the +@@ -2280,6 +2284,9 @@ + { + struct ssh *ssh = active_state; /* XXX */ + ++ if (i == 255) ++ pfilter_notify(1); ++ + if (the_authctxt) { + do_cleanup(ssh, the_authctxt); + if (use_privsep && privsep_is_preauth && Index: head/contrib/blacklist/lib/Makefile =================================================================== --- head/contrib/blacklist/lib/Makefile (revision 354398) +++ head/contrib/blacklist/lib/Makefile (revision 354399) @@ -1,19 +1,19 @@ -# $NetBSD: Makefile,v 1.6 2016/01/05 13:07:46 christos Exp $ +# $NetBSD: Makefile,v 1.7 2019/03/08 20:40:05 christos Exp $ .include USE_SHLIBDIR= yes CPPFLAGS+=-D_REENTRANT -LIBDPLIBS+=pthread ${NETBSDSRCDIR}/lib/libpthread +#LIBDPLIBS+=pthread ${NETBSDSRCDIR}/lib/libpthread LIB=blacklist SRCS=bl.c blacklist.c MAN=libblacklist.3 MLINKS+=libblacklist.3 blacklist_open.3 MLINKS+=libblacklist.3 blacklist_close.3 MLINKS+=libblacklist.3 blacklist.3 MLINKS+=libblacklist.3 blacklist_r.3 MLINKS+=libblacklist.3 blacklist_sa.3 MLINKS+=libblacklist.3 blacklist_sa_r.3 .include Index: head/contrib/blacklist/lib/libblacklist.3 =================================================================== --- head/contrib/blacklist/lib/libblacklist.3 (revision 354398) +++ head/contrib/blacklist/lib/libblacklist.3 (revision 354399) @@ -1,157 +1,157 @@ -.\" $NetBSD: libblacklist.3,v 1.7 2017/02/04 23:33:56 wiz Exp $ +.\" $NetBSD: libblacklist.3,v 1.8 2017/10/22 10:31:57 abhinav 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 May 5, 2017 .Dt LIBBLACKLIST 3 .Os .Sh NAME .Nm blacklist_open , .Nm blacklist_close , .Nm blacklist_r , .Nm blacklist , -.Nm blacklist_sa +.Nm blacklist_sa , .Nm blacklist_sa_r .Nd Blacklistd notification library .Sh LIBRARY .Lb libblacklist .Sh SYNOPSIS .In blacklist.h .Ft struct blacklist * .Fn blacklist_open "void" .Ft void .Fn blacklist_close "struct blacklist *cookie" .Ft int .Fn blacklist "int action" "int fd" "const char *msg" .Ft int .Fn blacklist_r "struct blacklist *cookie" "int action" "int fd" "const char *msg" .Ft int .Fn blacklist_sa "int action" "int fd" "const struct sockaddr *sa" "socklen_t salen" "const char *msg" .Ft int .Fn blacklist_sa_r "struct blacklist *cookie" "int action" "int fd" "const struct sockaddr *sa" "socklen_t salen" "const char *msg" .Sh DESCRIPTION These functions can be used by daemons to notify .Xr blacklistd 8 about successful and failed remote connections so that blacklistd can block or release port access to prevent Denial of Service attacks. .Pp The function .Fn blacklist_open creates the necessary state to communicate with .Xr blacklistd 8 and returns a pointer to it, or .Dv NULL on failure. .Pp The .Fn blacklist_close function frees all memory and resources used. .Pp The .Fn blacklist function sends a message to .Xr blacklistd 8 , with an integer .Ar action argument specifying the type of notification, a file descriptor .Ar fd specifying the accepted file descriptor connected to the client, and an optional message in the .Ar msg argument. .Pp The .Ar action parameter can take these values: .Bl -tag -width ".Va BLACKLIST_ABUSIVE_BEHAVIOR" .It Va BLACKLIST_AUTH_FAIL There was an unsuccessful authentication attempt. .It Va BLACKLIST_AUTH_OK A user successfully authenticated. .It Va BLACKLIST_ABUSIVE_BEHAVIOR The sending daemon has detected abusive behavior from the remote system. The remote address should be blocked as soon as possible. .It Va BLACKLIST_BAD_USER The sending daemon has determined the username presented for authentication is invalid. The .Xr blacklistd 8 daemon compares the username to a configured list of forbidden usernames and blocks the address immediately if a forbidden username matches. (The .Ar BLACKLIST_BAD_USER support is not currently available.) .El .Pp The .Fn blacklist_r function is more efficient because it keeps the blacklist state around. .Pp The .Fn blacklist_sa and .Fn blacklist_sa_r functions can be used with unconnected sockets, where .Xr getpeername 2 will not work, the server will pass the peer name in the message. .Pp By default, .Xr syslogd 8 is used for message logging. The internal .Fn bl_create function can be used to create the required internal state and specify a custom logging function. .Sh RETURN VALUES The function .Fn blacklist_open returns a cookie on success and .Dv NULL on failure setting .Dv errno to an appropriate value. .Pp The functions .Fn blacklist , .Fn blacklist_sa , and .Fn blacklist_sa_r return .Dv 0 on success and .Dv \-1 on failure setting .Dv errno to an appropriate value. .Sh SEE ALSO .Xr blacklistd.conf 5 , .Xr blacklistd 8 .Sh AUTHORS .An Christos Zoulas Index: head/contrib/blacklist =================================================================== --- head/contrib/blacklist (revision 354398) +++ head/contrib/blacklist (revision 354399) Property changes on: head/contrib/blacklist ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/NetBSD/blacklist/dist:r354388