diff options
| author | Jose Luis Duran <jlduran@FreeBSD.org> | 2025-10-12 16:27:03 +0000 |
|---|---|---|
| committer | Jose Luis Duran <jlduran@FreeBSD.org> | 2025-10-12 16:33:37 +0000 |
| commit | 70f30afd4e9af5a51ee324d97e4d8c5f2124ec15 (patch) | |
| tree | 8f5a969027ef6ca3db1fe329974984abf7bfba64 | |
| parent | e6a066ac3e8fdf1fcd4f3f2ca1b82bd55eb2da2a (diff) | |
60 files changed, 995 insertions, 277 deletions
@@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.1 2015/01/21 16:16:00 christos Exp $ +# $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:52 christos Exp $ SUBDIR = lib .WAIT include bin etc libexec diff --git a/Makefile.inc b/Makefile.inc index 60c9aaf0bf29..b22d4a801240 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.inc,v 1.2 2015/01/22 04:20:50 christos Exp $ +# $NetBSD: Makefile.inc,v 1.3 2025/02/11 17:48:30 christos Exp $ WARNS=6 .if !defined(LIB) @@ -7,4 +7,5 @@ DPADD+= ${LIBBLOCKLIST} .endif CPPFLAGS+= -I${.CURDIR}/../include CPPFLAGS+=-DHAVE_STRUCT_SOCKADDR_SA_LEN -DHAVE_UTIL_H -DHAVE_DB_H +CPPFLAGS+=-DHAVE_SYS_CDEFS_H @@ -1,4 +1,4 @@ -# $NetBSD: README,v 1.7 2015/01/26 00:34:50 christos Exp $ +# $NetBSD: README,v 1.3 2024/02/09 00:53:30 wiz Exp $ This package contains library that can be used by network daemons to communicate with a packet filter via a daemon to enforce opening and @@ -15,7 +15,7 @@ blocklistd=YES in /etc/rc.conf, start it up, and you are all set. There is also a startup file in etc/rc.d/blocklistd -Patches to various daemons to add blocklisting capabilitiers are in the +Patches to various daemons to add blocklisting capabilities are in the "diff" directory: - OpenSSH: diff/ssh.diff [tcp socket example] - Bind: diff/named.diff [both tcp and udp] @@ -24,7 +24,7 @@ Patches to various daemons to add blocklisting capabilitiers are in the These patches have been applied to NetBSD-current. The network daemon (for example sshd) communicates to blocklistd, via -a unix socket like syslog. The library calls are simple and everything +a Unix socket like syslog. The library calls are simple and everything is handled by the library. In the simplest form the only thing the daemon needs to do is to call: @@ -52,7 +52,7 @@ peer information to blocklistd via: The configuration file contains entries of the form: -# Blacklist rule +# Blocklist rule # host/Port type protocol owner name nfail disable 192.168.1.1:ssh stream tcp * -int 10 1m 8.8.8.8:ssh stream tcp * -ext 6 60m @@ -60,11 +60,11 @@ ssh stream tcp6 * * 6 60m http stream tcp * * 6 60m Here note that owner is * because the connection is done from the -child ssh socket which runs with user privs. We treat ipv4 connections +child ssh socket which runs with user privs. We treat IPv4 connections differently by maintaining two different rules one for the external interface and one from the internal We also register for both tcp and tcp6 since those are different listening sockets and addresses; -we don't bother with ipv6 and separate rules. We use nfail = 6, +we don't bother with IPv6 and separate rules. We use nfail = 6, because ssh allows 3 password attempts per connection, and this will let us have 2 connections before blocking. Finally we block for an hour; we could block forever too by specifying * in the @@ -100,7 +100,7 @@ group "internal" on $int_if { You can use 'blocklistctl dump -a' to list all the current entries in the database; the ones that have nfail <c>/<t> where <c>urrent ->= <t>otal, should have an id assosiated with them; this means that +>= <t>otal, should have an id associated with them; this means that there is a packet filter rule added for that entry. For npf, you can examine the packet filter dynamic rule entries using 'npfctl rule <rulename> list'. The number of current entries can exceed @@ -1,4 +1,4 @@ -# $NetBSD: TODO,v 1.6 2015/01/22 18:15:56 christos Exp $ +# $NetBSD: TODO,v 1.3 2025/02/05 20:22:26 christos Exp $ - don't poll periodically, find the next timeout - use the socket also for commands? Or separate socket? @@ -19,3 +19,46 @@ unblock - do we need an api in blocklistctl to perform maintenance - fix the blocklistctl output to be more user friendly + +- figure out some way to do distributed operation securely (perhaps with + a helper daemon that authenticates local sockets and then communicates + local DB changes to the central server over a secure channel -- + perhaps blocklistd-helper can have a back-end that can send updates to + a central server) + +- add "blocklistd -l" to enable filter logging on all rules by default + +- add some new options in the config file + + "/all" - block both TCP and UDP (on the proto field?) + + "/log" - enable filter logging (if not the default) (on the name field?) + "/nolog"- disable filter logging (if not the default) (on the name field?) + + The latter two probably require a new parameter for blocklistd-helper. + +- "blocklistd -f" should (also?) be a blocklistctl function!?!?! + +- if blocklistd was started with '-r' then a SIGHUP should also do a + "control flush $rulename" and then re-add all the filter rules? + +- should/could /etc/rc.conf.d/ipfilter be created with the following? + + reload_postcmd=blocklistd_reload + start_postcmd=blocklistd_start + stop_precmd=blocklistd_stop + blocklistd_reload () + { + /etc/rc.d/blocklistd reload # IFF SIGHUP does flush/re-add + # /etc/rc.d/blocklistd restart + } + blocklistd_stop () + { + /etc/rc.d/blocklistd stop + } + blocklistd_start () + { + /etc/rc.d/blocklistd start + } + + or is there a better way? diff --git a/bin/Makefile b/bin/Makefile index d935e10e7ea9..1856e2524f3c 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.10 2015/01/22 17:49:41 christos Exp $ +# $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:52 christos Exp $ BINDIR=/sbin diff --git a/bin/blocklistctl.8 b/bin/blocklistctl.8 index f3de48a6a9bd..a98c16374f19 100644 --- a/bin/blocklistctl.8 +++ b/bin/blocklistctl.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: blocklistctl.8,v 1.8 2016/06/07 17:31:02 christos Exp $ +.\" $NetBSD: blocklistctl.8,v 1.4 2025/02/07 01:35:38 kre Exp $ .\" .\" Copyright (c) 2015 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,27 +27,43 @@ .\" 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 January 27, 2025 .Dt BLOCKLISTCTL 8 .Os .Sh NAME .Nm blocklistctl -.Nd display and change the state of blocklistd +.Nd display and change the state of the blocklistd database .Sh SYNOPSIS .Nm .Cm dump .Op Fl abdnrw +.Op Fl D Ar dbname .Sh DESCRIPTION .Nm -is a program used to display the state of +is a program used to display and change the state of the .Xr blocklistd 8 +database. +The following sub-commands are supported: +.Ss dump .Pp -The following options are available: +The following options are available for the +.Cm dump +sub-command: .Bl -tag -width indent .It Fl a -Show all database entries, by default it shows only the embryonic ones. +Show all database entries, by default it shows only the active ones. +Inactive entries will be shown with a last-access (or, with +.Fl r , +the remaining) time of +.Ql never . .It Fl b Show only the blocked entries. +.It Fl D Ar dbname +Specify the location of the +.Ic blocklistd +database file to use. +The default is +.Pa /var/db/blocklistd.db . .It Fl d Increase debugging level. .It Fl n @@ -59,6 +75,35 @@ Normally the width of addresses is good for IPv4, the .Fl w flag, makes the display wide enough for IPv6 addresses. .El +.Pp +The output of the +.Cm dump +sub-command consists of a header (unless +.Fl n +was given) and one line for each record in the database, where each line +has the following columns: +.Bl -tag -width indent +.It Ql address/ma:port +The remote address, mask, and local port number of the client connection +associated with the database entry. +.It Ql id +column will show the identifier for the packet filter rule associated +with the database entry, though this may only be the word +.Ql OK +for packet filters which do not creat a unique identifier for each rule. +.It Ql nfail +The number of +.Em failures +reported for the client on the noted port, as well as the number of +failures allowed before blocking (or, with +.Fl a , +an asterisk +.Aq * ) +.It So last access Sc | So remaining time Sc +The last time a the client was reported as attempting access, or, with +.Fl r , +the time remaining before the rule blocking the client will be removed. +.El .Sh SEE ALSO .Xr blocklistd 8 .Sh NOTES diff --git a/bin/blocklistctl.c b/bin/blocklistctl.c index a11ae8739cca..8c75e0430c61 100644 --- a/bin/blocklistctl.c +++ b/bin/blocklistctl.c @@ -1,4 +1,4 @@ -/* $NetBSD: blocklistctl.c,v 1.22 2018/05/24 19:19:37 christos Exp $ */ +/* $NetBSD: blocklistctl.c,v 1.4 2025/02/11 17:48:30 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -32,8 +32,10 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> -__RCSID("$NetBSD: blocklistctl.c,v 1.22 2018/05/24 19:19:37 christos Exp $"); +#endif +__RCSID("$NetBSD: blocklistctl.c,v 1.4 2025/02/11 17:48:30 christos Exp $"); #include <stdio.h> #include <time.h> @@ -61,9 +63,10 @@ usage(int c) { if (c == 0) warnx("Missing/unknown command"); - else + else if (c != '?') warnx("Unknown option `%c'", (char)c); - fprintf(stderr, "Usage: %s dump [-abdnrw]\n", getprogname()); + fprintf(stderr, + "Usage: %s dump [-abdnrw] [-D dbname]\n", getprogname()); exit(EXIT_FAILURE); } @@ -123,7 +126,6 @@ main(int argc, char *argv[]) break; default: usage(o); - break; } db = state_open(dbname, O_RDONLY, 0); diff --git a/bin/blocklistd.8 b/bin/blocklistd.8 index c28e8ac08e90..38bf22175361 100644 --- a/bin/blocklistd.8 +++ b/bin/blocklistd.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: blocklistd.8,v 1.23 2020/04/21 13:57:12 christos Exp $ +.\" $NetBSD: blocklistd.8,v 1.8 2025/02/25 22:13:34 christos Exp $ .\" .\" Copyright (c) 2015 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd April 21, 2020 +.Dd February 25, 2025 .Dt BLOCKLISTD 8 .Os .Sh NAME @@ -53,18 +53,31 @@ for notifications from other daemons about successful or failed connection attempts. If no such file is specified, then it only listens to the socket path specified by -.Ar sockspath +.Ar sockpath or if that is not specified to .Pa /var/run/blocklistd.sock . Each notification contains an (action, port, protocol, address, owner) tuple that identifies the remote connection and the action. -This tuple is consulted against entries in -.Ar configfile -with syntax specified in +This tuple is consulted against entries from the +.Ar configfile , +with the syntax specified in .Xr blocklistd.conf 5 . If an entry is matched, a state entry is created for that tuple. Each entry contains a number of tries limit and a duration. .Pp +If +.Ar configfile +is a directory, or a directory exists with the same name as +.Ar configfile +with +.Qq .d +appended to it, each file in the directory will be read as configuration file. +If +.Ar configfile +exists as a file it will be processed before the contents of the +.Ar configfile Ns .d +directory if that also exists. +.Pp The way .Nm does configuration entry matching is by having the client side pass the @@ -152,7 +165,7 @@ The following options are available: .It Fl C Ar controlprog Use .Ar controlprog -to communicate with the packet filter, usually +to communicate with the packet filter, instead of the default, which is .Pa /libexec/blocklistd-helper . The following arguments are passed to the control program: .Bl -tag -width protocol @@ -161,7 +174,7 @@ The action to perform: .Dv add , .Dv rem , or -.Dv flush +.Dv flush ; to add, remove or flush a firewall rule. .It name The rule name. @@ -183,12 +196,16 @@ identifier of the rule to be removed. The add command is expected to return the rule identifier string to stdout. .El .It Fl c Ar configuration -The name of the configuration file to read, usually +The name of the configuration file to read. +The default when +.Fl c +is not given is .Pa /etc/blocklistd.conf . .It Fl D Ar dbfile The Berkeley DB file where .Nm -stores its state, usually +stores its state. +It defaults to .Pa /var/db/blocklistd.db . .It Fl d Normally, @@ -203,7 +220,7 @@ are deleted by invoking the control script as: .Bd -literal -offset indent control flush <rulename> .Ed -.It Fl P Ar sockspathsfile +.It Fl P Ar sockpathsfile A file containing a list of pathnames, one per line that .Nm will create sockets to listen to. diff --git a/bin/blocklistd.c b/bin/blocklistd.c index 01dd629aecd0..4846b507c8d1 100644 --- a/bin/blocklistd.c +++ b/bin/blocklistd.c @@ -1,4 +1,4 @@ -/* $NetBSD: blocklistd.c,v 1.42 2020/03/11 02:33:18 roy Exp $ */ +/* $NetBSD: blocklistd.c,v 1.10 2025/03/26 17:09:35 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -31,8 +31,11 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif + +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> -__RCSID("$NetBSD: blocklistd.c,v 1.42 2020/03/11 02:33:18 roy Exp $"); +#endif +__RCSID("$NetBSD: blocklistd.c,v 1.10 2025/03/26 17:09:35 christos Exp $"); #include <sys/types.h> #include <sys/socket.h> @@ -105,7 +108,7 @@ sigdone(int n __unused) static __dead void usage(int c) { - if (c) + if (c != '?') warnx("Unknown option `%c'", (char)c); fprintf(stderr, "Usage: %s [-vdfr] [-c <config>] [-R <rulename>] " "[-P <sockpathsfile>] [-C <controlprog>] [-D <dbfile>] " @@ -175,6 +178,8 @@ process(bl_t bl) struct dbinfo dbi; struct timespec ts; + memset(&dbi, 0, sizeof(dbi)); + memset(&c, 0, sizeof(c)); if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { (*lfun)(LOG_ERR, "clock_gettime failed (%m)"); return; @@ -188,10 +193,11 @@ process(bl_t bl) if (getremoteaddress(bi, &rss, &rsl) == -1) goto out; - if (debug) { + if (debug || bi->bi_msg[0]) { 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, + (*lfun)(bi->bi_msg[0] ? LOG_INFO : 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); } @@ -216,16 +222,19 @@ process(bl_t bl) 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 the application has signaled abusive behavior, set the + * number of fails to be two less than the configured limit. + * Fall through to the normal BL_ADD and BL_BADUSER 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; + dbi.count = c.c_nfail - 2; /*FALLTHROUGH*/ case BL_ADD: + dbi.count++; /* will become += 2 */ + /*FALLTHROUGH*/ + case BL_BADUSER: dbi.count++; dbi.last = ts.tv_sec; if (c.c_nfail != -1 && dbi.count >= c.c_nfail) { @@ -254,9 +263,6 @@ process(bl_t bl) dbi.count = 0; dbi.last = 0; break; - case BL_BADUSER: - /* ignore for now */ - break; default: (*lfun)(LOG_ERR, "unknown message %d", bi->bi_type); } @@ -322,7 +328,7 @@ again: if (dbi.id[0]) { run_change("rem", &c, dbi.id, 0); sockaddr_snprintf(buf, sizeof(buf), "%a", ss); - syslog(LOG_INFO, "released %s/%d:%d after %d seconds", + (*lfun)(LOG_INFO, "released %s/%d:%d after %d seconds", buf, c.c_lmask, c.c_port, c.c_duration); } state_del(state, &c); @@ -334,7 +340,7 @@ 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); + bl_t bl = bl_create(true, path, vflag ? vdlog : vsyslog_r); if (bl == NULL || !bl_isconnected(bl)) exit(EXIT_FAILURE); if (*nfd >= *maxfd) { @@ -395,15 +401,25 @@ rules_flush(void) static void rules_restore(void) { + DB *db; struct conf c; struct dbinfo dbi; unsigned int f; - for (f = 1; state_iterate(state, &c, &dbi, f) == 1; f = 0) { + db = state_open(dbfile, O_RDONLY, 0); + if (db == NULL) { + (*lfun)(LOG_ERR, "Can't open `%s' to restore state (%m)", + dbfile); + return; + } + for (f = 1; state_iterate(db, &c, &dbi, f) == 1; f = 0) { if (dbi.id[0] == '\0') continue; (void)run_change("add", &c, dbi.id, sizeof(dbi.id)); + state_put(state, &c, &dbi); } + state_close(db); + state_sync(state); } int @@ -474,7 +490,7 @@ main(int argc, char *argv[]) argc -= optind; if (argc) - usage(0); + usage('?'); signal(SIGHUP, sighup); signal(SIGINT, sigdone); diff --git a/bin/blocklistd.conf.5 b/bin/blocklistd.conf.5 index 6d1eb36e098e..3a7dbfc07f58 100644 --- a/bin/blocklistd.conf.5 +++ b/bin/blocklistd.conf.5 @@ -1,6 +1,6 @@ -.\" $NetBSD: blocklistd.conf.5,v 1.9 2019/11/06 20:33:30 para Exp $ +.\" $NetBSD: blocklistd.conf.5,v 1.7 2025/02/11 17:47:05 christos Exp $ .\" -.\" Copyright (c) 2015 The NetBSD Foundation, Inc. +.\" Copyright (c) 2015, 2025 The NetBSD Foundation, Inc. .\" All rights reserved. .\" .\" This code is derived from software contributed to The NetBSD Foundation @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd May 18, 2020 +.Dd February 5, 2025 .Dt BLOCKLISTD.CONF 5 .Os .Sh NAME @@ -48,34 +48,34 @@ Comments are denoted by a at the beginning of a line. .Pp There are two kinds of configuration lines, -.Va local +.Va [local] and -.Va remote . +.Va [remote] . By default, configuration lines are -.Va local , +.Va [local] , i.e. the address specified refers to the addresses on the local machine. To switch to between -.Va local +.Va [local] and -.Va remote +.Va [remote] configuration lines you can specify the stanzas: .Dq [local] and .Dq [remote] . .Pp On -.Va local +.Va [local] and -.Va remote +.Va [remote] lines .Dq * means use the default, or wildcard match. In addition, for -.Va remote +.Va [remote] lines .Dq = means use the values from the matched -.Va local +.Va [local] configuration line. .Pp The first four fields, @@ -85,9 +85,9 @@ The first four fields, and .Va owner are used to match the -.Va local +.Va [local] or -.Va remote +.Va [remote] addresses, whereas the last 3 fields .Va name , .Va nfail , @@ -110,8 +110,8 @@ The 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 -can have multiple addresses in different protocols where the mask has a different -size. +can have multiple addresses in different protocols where the mask has a +different size. .Pp The .Dv mask @@ -143,8 +143,8 @@ The field, is the name of the packet filter rule to be used. If the .Va name -starts with a -.Dq - , +starts with a hyphen +.Pq Dq - , then the default rulename is prepended to the given name. If the .Dv name @@ -160,13 +160,13 @@ field contains the number of failed attempts before access is blocked, defaulting to .Dq * meaning never, and the last field -.Va disable +.Va duration 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 +.Va duration is seconds, but one can specify suffixes for different units, such as .Dq m for minutes @@ -176,25 +176,31 @@ for hours and for days. .Pp Matching is done first by checking the -.Va local +.Va [local] rules individually, in the order of the most specific to the least specific. -If a match is found, then the -.Va remote +If a match is found, then the matching +.Va [remote] rules are applied. The .Va name , .Va nfail , and -.Va disable +.Va duration fields can be altered by the -.Va remote +.Va [remote] rule that matched. .Pp The -.Va remote +.Va [remote] rules can be used for allowing specific addresses, changing the mask -size, the rule that the packet filter uses, the number of failed attempts, -or the block duration. +size (via +.Va name ) , +the rule that the packet filter uses (also via +.Va name ) , +the number of failed attempts (via +.Va nfail ) , +or the duration to block (via +.Va duration ) . .Sh FILES .Bl -tag -width /etc/blocklistd.conf -compact .It Pa /etc/blocklistd.conf @@ -209,7 +215,9 @@ 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 +# Never block the example IPv6 subnet either +[2001:db8::]/32:ssh * * * * * * +# For addresses coming from 8.8.0.0/16 block whole /24 networks instead # individual hosts, but keep the rest of the blocking parameters the same. 8.8.0.0/16:ssh * * * /24 = = .Ed diff --git a/bin/conf.c b/bin/conf.c index 6beb1051459b..3c6fadb5fa45 100644 --- a/bin/conf.c +++ b/bin/conf.c @@ -1,4 +1,4 @@ -/* $NetBSD: conf.c,v 1.30 2020/03/12 19:47:32 christos Exp $ */ +/* $NetBSD: conf.c,v 1.10 2025/02/11 17:48:30 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -32,8 +32,10 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> -__RCSID("$NetBSD: conf.c,v 1.30 2020/03/12 19:47:32 christos Exp $"); +#endif +__RCSID("$NetBSD: conf.c,v 1.10 2025/02/11 17:48:30 christos Exp $"); #include <stdio.h> #ifdef HAVE_LIBUTIL_H @@ -58,6 +60,7 @@ __RCSID("$NetBSD: conf.c,v 1.30 2020/03/12 19:47:32 christos Exp $"); #include <net/if.h> #include <net/route.h> #include <sys/socket.h> +#include <dirent.h> #include "bl.h" #include "internal.h" @@ -261,7 +264,7 @@ conf_gethostport(const char *f, size_t l, bool local, struct conf *c, if (debug) (*lfun)(LOG_DEBUG, "%s: host6 %s", __func__, p); if (strcmp(p, "*") != 0) { - if (inet_pton(AF_INET6, p, &sin6->sin6_addr) == -1) + if (inet_pton(AF_INET6, p, &sin6->sin6_addr) != 1) goto out; sin6->sin6_family = AF_INET6; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN @@ -269,6 +272,8 @@ conf_gethostport(const char *f, size_t l, bool local, struct conf *c, #endif port = &sin6->sin6_port; } + if (!*pstr) + pstr = "*"; } else if (pstr != p || strchr(p, '.') || conf_is_interface(p)) { if (pstr == p) pstr = "*"; @@ -311,7 +316,7 @@ conf_gethostport(const char *f, size_t l, bool local, struct conf *c, *port = htons((in_port_t)c->c_port); return 0; out: - (*lfun)(LOG_ERR, "%s: %s, %zu: Bad address [%s]", __func__, f, l, pstr); + (*lfun)(LOG_ERR, "%s: %s, %zu: Bad address [%s]", __func__, f, l, p); return -1; out1: (*lfun)(LOG_ERR, "%s: %s, %zu: Can't specify mask %d with " @@ -407,6 +412,8 @@ conf_parseline(const char *f, size_t l, char *p, struct conf *c, bool local) { int e; + c->c_lineno = l; + while (*p && isspace((unsigned char)*p)) p++; @@ -471,7 +478,6 @@ conf_amask_eq(const void *v1, const void *v2, size_t len, int mask) uint32_t m; int omask = mask; - len >>= 2; switch (mask) { case FSTAR: if (memcmp(v1, v2, len) == 0) @@ -485,7 +491,7 @@ conf_amask_eq(const void *v1, const void *v2, size_t len, int mask) break; } - for (size_t i = 0; i < len; i++) { + for (size_t i = 0; i < (len >> 2); i++) { if (mask > 32) { m = htonl((uint32_t)~0); mask -= 32; @@ -501,7 +507,6 @@ conf_amask_eq(const void *v1, const void *v2, size_t len, int mask) out: if (debug > 1) { char b1[256], b2[256]; - len <<= 2; blhexdump(b1, sizeof(b1), "a1", v1, len); blhexdump(b2, sizeof(b2), "a2", v2, len); (*lfun)(LOG_DEBUG, "%s: %s != %s [0x%x]", __func__, @@ -691,6 +696,25 @@ conf_addr_eq(const struct sockaddr_storage *s1, static int conf_eq(const struct conf *c1, const struct conf *c2) { + if (!conf_addr_eq(&c1->c_ss, &c2->c_ss, FSTAR)) + return 0; + +#define CMP(a, b, f) \ + if ((a)->f != (b)->f) \ + return 0; + + CMP(c1, c2, c_port); + CMP(c1, c2, c_proto); + CMP(c1, c2, c_family); + CMP(c1, c2, c_uid); +#undef CMP + + return 1; +} + +static int +conf_match(const struct conf *c1, const struct conf *c2) +{ if (!conf_addr_eq(&c1->c_ss, &c2->c_ss, c2->c_lmask)) return 0; @@ -953,13 +977,54 @@ confset_free(struct confset *cs) } static void -confset_replace(struct confset *dc, struct confset *sc) +confset_merge(struct confset *dc, struct confset *sc) { - struct confset tc; - tc = *dc; - *dc = *sc; - confset_init(sc); - confset_free(&tc); + size_t i, j; + char buf[BUFSIZ]; + + /* Check each rule of the src confset (sc) */ + for (i = 0; i < sc->cs_n; i++) { + /* Compare to each rule in the dest confset (dc) */ + for (j = 0; j < dc->cs_n; j++) { + if (conf_eq(&dc->cs_c[j], &sc->cs_c[i])) { + break; + } + } + + if (j == dc->cs_n) { + /* This is a new rule to add to the dest confset. */ + if (confset_full(dc) && confset_grow(dc) == -1) + return; + + *confset_get(dc) = sc->cs_c[i]; + confset_add(dc); + continue; + } + + /* We had a match above. */ + /* + * Check whether the rule from the src confset is more + * restrictive than the existing one. Adjust the + * existing rule if necessary. + */ + if (sc->cs_c[i].c_nfail == dc->cs_c[j].c_nfail && + sc->cs_c[i].c_duration && dc->cs_c[j].c_duration) { + (*lfun)(LOG_DEBUG, "skipping existing rule: %s", + conf_print(buf, sizeof (buf), "", "\t", &sc->cs_c[i])); + continue; + } + + if (sc->cs_c[i].c_nfail < dc->cs_c[j].c_nfail) + dc->cs_c[j].c_nfail = sc->cs_c[i].c_nfail; + + if (sc->cs_c[i].c_duration > dc->cs_c[j].c_duration) + dc->cs_c[j].c_duration = sc->cs_c[i].c_duration; + + (*lfun)(LOG_DEBUG, "adjusted existing rule: %s", + conf_print(buf, sizeof (buf), "", "\t", &dc->cs_c[j])); + } + + confset_free(sc); } static void @@ -990,7 +1055,7 @@ confset_match(const struct confset *cs, struct conf *c, 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 (conf_match(c, &cs->cs_c[i])) { if (debug) (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), @@ -1005,7 +1070,6 @@ confset_match(const struct confset *cs, struct conf *c, #ifdef AF_ROUTE static int conf_route_perm(int fd) { -/* Disable for now, the access check in the routing socket uses curlwp */ #if defined(RTM_IFANNOUNCE) && defined(RT_ROUNDUP) /* * Send a routing message that is not supported to check for access @@ -1161,21 +1225,14 @@ conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss, return cr; } - -void -conf_parse(const char *f) +static void +conf_parsefile(FILE *fp, const char *config_file) { - FILE *fp; char *line; 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); - return; - } - - lineno = 1; + lineno = 0; confset_init(&rc); confset_init(&lc); @@ -1198,23 +1255,103 @@ conf_parse(const char *f) if (confset_grow(cs) == -1) { confset_free(&lc); confset_free(&rc); - fclose(fp); free(line); return; } } - if (conf_parseline(f, lineno, line, confset_get(cs), + if (conf_parseline(config_file, lineno, line, confset_get(cs), cs == &lc) == -1) continue; confset_add(cs); } - fclose(fp); - confset_sort(&lc); - confset_sort(&rc); + confset_merge(&rconf, &rc); + confset_merge(&lconf, &lc); +} + + +static void +conf_parsedir(DIR *dir, const char *config_path) +{ + long path_max; + struct dirent *dent; + char *path; + FILE *fp; + + if ((path_max = pathconf(config_path, _PC_PATH_MAX)) == -1) + path_max = 2048; + + if ((path = malloc((size_t)path_max)) == NULL) { + (*lfun)(LOG_ERR, "%s: Failed to allocate memory for path (%m)", + __func__); + return; + } + + while ((dent = readdir(dir)) != NULL) { + if (strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0) + continue; + + (void) snprintf(path, (size_t)path_max, "%s/%s", config_path, + dent->d_name); + if ((fp = fopen(path, "r")) == NULL) { + (*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__, + path); + continue; + } + conf_parsefile(fp, path); + fclose(fp); + } + + free(path); +} + +void +conf_parse(const char *config_path) +{ + char *path; + DIR *dir; + FILE *fp; + + if ((dir = opendir(config_path)) != NULL) { + /* + * If config_path is a directory, parse the configuration files + * in the directory. Then we're done here. + */ + conf_parsedir(dir, config_path); + closedir(dir); + goto out; + } else if ((fp = fopen(config_path, "r")) != NULL) { + /* If config_path is a file, parse it. */ + conf_parsefile(fp, config_path); + fclose(fp); + } + + /* + * Append ".d" to config_path, and if that is a directory, parse the + * configuration files in the directory. + */ + if (asprintf(&path, "%s.d", config_path) < 0) { + (*lfun)(LOG_ERR, "%s: Failed to allocate memory for path (%m)", + __func__); + goto out; + } + + if ((dir = opendir(path)) != NULL) { + conf_parsedir(dir, path); + closedir(dir); + } + free(path); + +out: + if (dir == NULL && fp == NULL) { + (*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__, + config_path); + return; + } - confset_replace(&rconf, &rc); - confset_replace(&lconf, &lc); + confset_sort(&lconf); + confset_sort(&rconf); if (debug) { confset_list(&lconf, "local", "target"); diff --git a/bin/conf.h b/bin/conf.h index 3062c1d35c1a..8e4cd3a41fae 100644 --- a/bin/conf.h +++ b/bin/conf.h @@ -1,4 +1,4 @@ -/* $NetBSD: conf.h,v 1.5 2015/01/21 19:24:03 christos Exp $ */ +/* $NetBSD: conf.h,v 1.2 2025/02/05 20:09:33 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -34,6 +34,7 @@ #include <sys/socket.h> struct conf { + size_t c_lineno; struct sockaddr_storage c_ss; int c_lmask; int c_port; diff --git a/bin/internal.c b/bin/internal.c index c3099d82a141..625de55928d8 100644 --- a/bin/internal.c +++ b/bin/internal.c @@ -1,4 +1,4 @@ -/* $NetBSD: internal.c,v 1.4 2015/01/25 20:59:39 christos Exp $ */ +/* $NetBSD: internal.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -32,8 +32,10 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> -__RCSID("$NetBSD: internal.c,v 1.4 2015/01/25 20:59:39 christos Exp $"); +#endif +__RCSID("$NetBSD: internal.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); #include <stdio.h> #include <syslog.h> diff --git a/bin/internal.h b/bin/internal.h index e2319775e5e3..b88e1330221a 100644 --- a/bin/internal.h +++ b/bin/internal.h @@ -1,4 +1,4 @@ -/* $NetBSD: internal.h,v 1.13 2015/10/14 16:01:29 christos Exp $ */ +/* $NetBSD: internal.h,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. diff --git a/bin/run.c b/bin/run.c index 5588f0198c04..adcc407e65c6 100644 --- a/bin/run.c +++ b/bin/run.c @@ -1,4 +1,4 @@ -/* $NetBSD: run.c,v 1.14 2016/04/04 15:52:56 christos Exp $ */ +/* $NetBSD: run.c,v 1.3 2025/02/11 17:48:30 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -32,8 +32,10 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> -__RCSID("$NetBSD: run.c,v 1.14 2016/04/04 15:52:56 christos Exp $"); +#endif +__RCSID("$NetBSD: run.c,v 1.3 2025/02/11 17:48:30 christos Exp $"); #include <stdio.h> #ifdef HAVE_LIBUTIL_H @@ -131,7 +133,8 @@ run_change(const char *how, const struct conf *c, char *id, size_t len) prname = "udp"; break; default: - (*lfun)(LOG_ERR, "%s: bad protocol %d", __func__, c->c_proto); + (*lfun)(LOG_ERR, "%s: bad protocol %d (line %zu)", __func__, + c->c_proto, c->c_lineno); return -1; } diff --git a/bin/run.h b/bin/run.h index ec310191b3c2..da21906e0db6 100644 --- a/bin/run.h +++ b/bin/run.h @@ -1,4 +1,4 @@ -/* $NetBSD: run.h,v 1.4 2015/01/22 04:13:04 christos Exp $ */ +/* $NetBSD: run.h,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. diff --git a/bin/state.c b/bin/state.c index 27d3eeceaff2..08e2622e223f 100644 --- a/bin/state.c +++ b/bin/state.c @@ -1,4 +1,4 @@ -/* $NetBSD: state.c,v 1.18 2016/04/04 15:52:56 christos Exp $ */ +/* $NetBSD: state.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -32,8 +32,10 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> -__RCSID("$NetBSD: state.c,v 1.18 2016/04/04 15:52:56 christos Exp $"); +#endif +__RCSID("$NetBSD: state.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); #include <sys/types.h> #include <sys/socket.h> diff --git a/bin/state.h b/bin/state.h index 823f97e8451f..48f63a41ef33 100644 --- a/bin/state.h +++ b/bin/state.h @@ -1,4 +1,4 @@ -/* $NetBSD: state.h,v 1.4 2015/01/24 07:46:20 christos Exp $ */ +/* $NetBSD: state.h,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. diff --git a/bin/support.c b/bin/support.c index d560d2303223..91e40812611e 100644 --- a/bin/support.c +++ b/bin/support.c @@ -1,4 +1,4 @@ -/* $NetBSD: support.c,v 1.9 2018/09/18 22:12:19 christos Exp $ */ +/* $NetBSD: support.c,v 1.3 2025/02/11 17:48:30 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -32,8 +32,10 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> -__RCSID("$NetBSD: support.c,v 1.9 2018/09/18 22:12:19 christos Exp $"); +#endif +__RCSID("$NetBSD: support.c,v 1.3 2025/02/11 17:48:30 christos Exp $"); #include <time.h> #include <string.h> @@ -66,7 +68,8 @@ expandm(char *buf, size_t len, const char *fmt) } void -vdlog(int level __unused, const char *fmt, va_list ap) +vdlog(int level __unused, struct syslog_data *sd __unused, + const char *fmt, va_list ap) { char buf[BUFSIZ]; @@ -81,7 +84,7 @@ dlog(int level, const char *fmt, ...) va_list ap; va_start(ap, fmt); - vdlog(level, fmt, ap); + vdlog(level, NULL, fmt, ap); va_end(ap); } diff --git a/bin/support.h b/bin/support.h index b27016f5a7ec..bb865cb8fe68 100644 --- a/bin/support.h +++ b/bin/support.h @@ -1,4 +1,4 @@ -/* $NetBSD: support.h,v 1.6 2015/06/02 14:02:10 christos Exp $ */ +/* $NetBSD: support.h,v 1.2 2024/08/02 17:11:55 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -34,8 +34,9 @@ __BEGIN_DECLS const char *fmttime(char *, size_t, time_t); const char *fmtydhms(char *, size_t, time_t); -void vdlog(int, const char *, va_list) - __attribute__((__format__(__printf__, 2, 0))); +struct syslog_data; +void vdlog(int, struct syslog_data *, const char *, va_list) + __attribute__((__format__(__printf__, 3, 0))); void dlog(int, const char *, ...) __attribute__((__format__(__printf__, 2, 3))); ssize_t blhexdump(char *, size_t, const char *, const void *, size_t); diff --git a/diff/postfix.diff b/diff/postfix.diff index 6d88e714c505..6f14389515cf 100644 --- a/diff/postfix.diff +++ b/diff/postfix.diff @@ -80,3 +80,19 @@ diff -u -r1.6 Makefile DPADD+= ${LIBPTLS} ${LIBSSL} ${LIBCRYPTO} LDADD+= ${LIBPTLS} -lssl -lcrypto +Index: dist/src/smtpd/smtpd.c +=================================================================== +RCS file: /cvsroot/src/external/ibm-public/postfix/dist/src/smtpd/smtpd.c,v +retrieving revision 1.17 +diff -u -u -r1.17 smtpd.c +--- dist/src/smtpd/smtpd.c 18 Mar 2020 19:05:20 -0000 1.17 ++++ dist/src/smtpd/smtpd.c 25 Sep 2020 12:51:52 -0000 +@@ -5795,6 +5795,8 @@ + || strcmp(state->reason, REASON_LOST_CONNECTION)) { + msg_info("%s after %s from %s", + state->reason, state->where, state->namaddr); ++ if (strcmp(state->where, SMTPD_CMD_AUTH) == 0) ++ pfilter_notify(1, vstream_fileno(state->client)); + } + } + diff --git a/etc/Makefile b/etc/Makefile index 702a1da8da37..f4f2dc79f857 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -1,10 +1,10 @@ -# $NetBSD: Makefile,v 1.2 2015/01/23 21:33:50 christos Exp $ +# $NetBSD: Makefile,v 1.2 2025/02/05 20:24:26 christos Exp $ -SUBDIR=rc.d +SUBDIR= rc.d -FILESDIR= /usr/share/examples/blocklist -FILESMODE= 644 -FILES= blocklistd.conf npf.conf +FILESDIR= /usr/share/examples/blocklist +FILESMODE= 644 +FILES= blocklistd.conf ipf.conf npf.conf .include <bsd.files.mk> .include <bsd.subdir.mk> diff --git a/etc/blocklistd.conf b/etc/blocklistd.conf index f061b004ad36..b52b994fe950 100644 --- a/etc/blocklistd.conf +++ b/etc/blocklistd.conf @@ -1,5 +1,5 @@ -# Blacklist rule -# adr/mask:port type proto owner name nfail disable +# Blocklist rule +# adr/mask:port type proto owner name nfail duration [local] ssh stream * * * 3 6h ftp stream * * * 3 6h @@ -7,8 +7,9 @@ domain * * named * 3 12h #6161 stream tcp6 christos * 2 10m * * * * * 3 60 -# adr/mask:port type proto owner name nfail disable +# adr/mask:port type proto owner name nfail duration [remote] #129.168.0.0/16 * * * = * * +#[2001:db8::]/32:ssh * * * = * * #6161 = = = =/24 = = #* stream tcp * = = = diff --git a/etc/ipf.conf b/etc/ipf.conf new file mode 100644 index 000000000000..f6bec74238d6 --- /dev/null +++ b/etc/ipf.conf @@ -0,0 +1,45 @@ +#======================================== +# +# subsection for abuse blocking +# +#======================================== +# +# This section should be included early in the main /etc/ipf.conf file, right +# after any basic generic accounting ("count") rules, and any cleanup rules to +# block invalid fragments, invalid options (e.g. "ssrr"), etc. +# +# Note these will not actually block anything since they don't include the +# "quick" flag, and are thus part of a last-match group. They simply set up a +# group such that any connection logging rule further below won't also match if +# one of the rules in the group matches, no matter when or where the subsequent +# matching rule is added. I.e. all rules in the group are checked for a match +# (and a possible "first match" with "quick") before any subsequent rules +# further below are used. Note group rules can be added at any time, including +# at runtime after all other rules have been added -- they will still belong to +# the group and once added will be checked as part of the group. +# +# head of "blocklistd" group: +# +# The "blocklistd" group will be used by blocklistd(8). +# +block in proto tcp/udp from any to any head blocklistd +# +# head of "attackers" group to block all attackers: +# +# The "attackers" group is intended to be used for manually maintained rules +# e.g. as could be added like this: +# +# echo 'block return-rst in log quick proto tcp from 118.136.0.0/15 to any flags S/SAFR group attackers' >> /etc/ipf.conf +# /etc/rc.d/ipfliter reload +# +# Note the choice in this example is to return RST packets for blocked SYN +# packets to help the other end close. This is not necessary, but it better +# mimics what the kernel does by default, thus perhaps hiding the fact a +# firewall is present. +# +# XXX This example still allows UDP services, but we would need to duplicate +# each rule with "proto udp" (and without "flags blah") due to IPF parsing +# limitations.... +# +block in proto tcp/udp from any to any head attackers +# diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile index 231108db2150..9e214984f7c2 100644 --- a/etc/rc.d/Makefile +++ b/etc/rc.d/Makefile @@ -1,4 +1,4 @@ -# $NetBSD$ +# $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ SCRIPTS=blocklistd SCRIPTSDIR=/etc/rc.d diff --git a/etc/rc.d/blocklistd b/etc/rc.d/blocklistd index 8e68aa372f92..89871ebda4a0 100644 --- a/etc/rc.d/blocklistd +++ b/etc/rc.d/blocklistd @@ -1,10 +1,10 @@ #!/bin/sh # -# $NetBSD: blocklistd,v 1.1 2015/01/22 17:49:41 christos Exp $ +# $NetBSD: blocklistd,v 1.2 2021/03/07 00:46:39 christos Exp $ # # PROVIDE: blocklistd -# REQUIRE: npf +# REQUIRE: npf pf ipfilter # BEFORE: SERVERS $_rc_subr_loaded . /etc/rc.subr diff --git a/include/Makefile b/include/Makefile index 49eea8ff8bf5..b7ce1eca278c 100644 --- a/include/Makefile +++ b/include/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.140 2013/12/11 01:24:08 joerg Exp $ +# $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ # Doing a make includes builds /usr/include diff --git a/include/bl.h b/include/bl.h index b89a49d3eb60..c7ed517d7a6d 100644 --- a/include/bl.h +++ b/include/bl.h @@ -1,4 +1,4 @@ -/* $NetBSD: bl.h,v 1.13 2016/03/11 17:16:40 christos Exp $ */ +/* $NetBSD: bl.h,v 1.2 2024/08/02 17:11:55 christos Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -65,7 +65,8 @@ __BEGIN_DECLS typedef struct blocklist *bl_t; -bl_t bl_create(bool, const char *, void (*)(int, const char *, va_list)); +bl_t bl_create(bool, const char *, + void (*)(int, struct syslog_data *, const char *, va_list)); void bl_destroy(bl_t); int bl_send(bl_t, bl_type_t, int, const struct sockaddr *, socklen_t, const char *); diff --git a/include/blocklist.h b/include/blocklist.h index 2a3c4750a650..f09e5139079b 100644 --- a/include/blocklist.h +++ b/include/blocklist.h @@ -1,4 +1,4 @@ -/* $NetBSD: blocklist.h,v 1.3 2015/01/23 18:48:56 christos Exp $ */ +/* $NetBSD: blocklist.h,v 1.4 2025/02/11 17:42:17 christos Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -32,16 +32,26 @@ #define _BLOCKLIST_H #include <sys/socket.h> +#include <syslog.h> -__BEGIN_DECLS +#if defined(__cplusplus) +extern "C" { +#endif + +struct syslog_data; struct blocklist *blocklist_open(void); +struct blocklist *blocklist_open2( + void (*)(int, struct syslog_data *, const char *, va_list)); void blocklist_close(struct blocklist *); int blocklist(int, int, const char *); int blocklist_r(struct blocklist *, int, int, const char *); int blocklist_sa(int, int, const struct sockaddr *, socklen_t, const char *); int blocklist_sa_r(struct blocklist *, int, int, const struct sockaddr *, socklen_t, const char *); -__END_DECLS + +#if defined(__cplusplus) +} +#endif /* action values for user applications */ #define BLOCKLIST_API_ENUM 1 diff --git a/lib/Makefile b/lib/Makefile index 43da41f83b90..147f311c4782 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.6 2016/01/05 13:07:46 christos Exp $ +# $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ .include <bsd.own.mk> @@ -1,4 +1,4 @@ -/* $NetBSD: bl.c,v 1.29 2020/03/10 13:36:08 roy Exp $ */ +/* $NetBSD: bl.c,v 1.9 2025/03/30 01:53:59 christos Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -32,8 +32,10 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> -__RCSID("$NetBSD: bl.c,v 1.29 2020/03/10 13:36:08 roy Exp $"); +#endif +__RCSID("$NetBSD: bl.c,v 1.9 2025/03/30 01:53:59 christos Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -57,6 +59,10 @@ __RCSID("$NetBSD: bl.c,v 1.29 2020/03/10 13:36:08 roy Exp $"); #include <pthread.h> #endif +#if defined(SO_RECVUCRED) +#include <ucred.h> +#endif + #include "bl.h" typedef struct { @@ -82,7 +88,8 @@ struct blocklist { int b_fd; int b_connected; struct sockaddr_un b_sun; - void (*b_fun)(int, const char *, va_list); + struct syslog_data b_syslog_data; + void (*b_fun)(int, struct syslog_data *, const char *, va_list); bl_info_t b_info; }; @@ -115,14 +122,16 @@ bl_reset(bl_t b, bool locked) } static void -bl_log(void (*fun)(int, const char *, va_list), int level, - const char *fmt, ...) +bl_log(bl_t b, int level, const char *fmt, ...) { va_list ap; int serrno = errno; + if (b->b_fun == NULL) + return; + va_start(ap, fmt); - (*fun)(level, fmt, ap); + (*b->b_fun)(level, &b->b_syslog_data, fmt, ap); va_end(ap); errno = serrno; } @@ -152,7 +161,7 @@ bl_init(bl_t b, bool srv) b->b_fd = socket(PF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK|SOCK_NOSIGPIPE, 0); if (b->b_fd == -1) { - bl_log(b->b_fun, LOG_ERR, "%s: socket failed (%s)", + bl_log(b, LOG_ERR, "%s: socket failed (%s)", __func__, strerror(errno)); BL_UNLOCK(b); return -1; @@ -186,7 +195,7 @@ bl_init(bl_t b, bool srv) rv = connect(b->b_fd, (const void *)sun, (socklen_t)sizeof(*sun)); if (rv == 0) { if (srv) { - bl_log(b->b_fun, LOG_ERR, + bl_log(b, LOG_ERR, "%s: another daemon is handling `%s'", __func__, sun->sun_path); goto out; @@ -199,7 +208,7 @@ bl_init(bl_t b, bool srv) * and only log once. */ if (b->b_connected != 1) { - bl_log(b->b_fun, LOG_DEBUG, + bl_log(b, LOG_DEBUG, "%s: connect failed for `%s' (%s)", __func__, sun->sun_path, strerror(errno)); b->b_connected = 1; @@ -207,8 +216,7 @@ bl_init(bl_t b, bool srv) BL_UNLOCK(b); return -1; } - bl_log(b->b_fun, LOG_DEBUG, "Connected to blocklist server", - __func__); + bl_log(b, LOG_DEBUG, "Connected to blocklist server", __func__); } if (srv) { @@ -219,8 +227,7 @@ bl_init(bl_t b, bool srv) (void)umask(om); errno = serrno; if (rv == -1) { - bl_log(b->b_fun, LOG_ERR, - "%s: bind failed for `%s' (%s)", + bl_log(b, LOG_ERR, "%s: bind failed for `%s' (%s)", __func__, sun->sun_path, strerror(errno)); goto out; } @@ -231,8 +238,8 @@ bl_init(bl_t b, bool srv) #if defined(LOCAL_CREDS) #define CRED_LEVEL 0 #define CRED_NAME LOCAL_CREDS -#define CRED_SC_UID sc_euid -#define CRED_SC_GID sc_egid +#define CRED_SC_UID(x) (x)->sc_euid +#define CRED_SC_GID(x) (x)->sc_egid #define CRED_MESSAGE SCM_CREDS #define CRED_SIZE SOCKCREDSIZE(NGROUPS_MAX) #define CRED_TYPE struct sockcred @@ -240,12 +247,21 @@ bl_init(bl_t b, bool srv) #elif defined(SO_PASSCRED) #define CRED_LEVEL SOL_SOCKET #define CRED_NAME SO_PASSCRED -#define CRED_SC_UID uid -#define CRED_SC_GID gid +#define CRED_SC_UID(x) (x)->uid +#define CRED_SC_GID(x) (x)->gid #define CRED_MESSAGE SCM_CREDENTIALS #define CRED_SIZE sizeof(struct ucred) #define CRED_TYPE struct ucred #define GOT_CRED 2 +#elif defined(SO_RECVUCRED) +#define CRED_LEVEL SOL_SOCKET +#define CRED_NAME SO_RECVUCRED +#define CRED_SC_UID(x) ucred_geteuid(x) +#define CRED_SC_GID(x) ucred_getegid(x) +#define CRED_MESSAGE SCM_UCRED +#define CRED_SIZE ucred_size() +#define CRED_TYPE ucred_t +#define GOT_CRED 2 #else #define GOT_CRED 0 /* @@ -259,7 +275,7 @@ bl_init(bl_t b, bool srv) #ifdef CRED_LEVEL if (setsockopt(b->b_fd, CRED_LEVEL, CRED_NAME, &one, (socklen_t)sizeof(one)) == -1) { - bl_log(b->b_fun, LOG_ERR, "%s: setsockopt %s " + bl_log(b, LOG_ERR, "%s: setsockopt %s " "failed (%s)", __func__, __STRING(CRED_NAME), strerror(errno)); goto out; @@ -275,12 +291,15 @@ out: } bl_t -bl_create(bool srv, const char *path, void (*fun)(int, const char *, va_list)) +bl_create(bool srv, const char *path, + void (*fun)(int, struct syslog_data *, const char *, va_list)) { + static struct syslog_data sd = SYSLOG_DATA_INIT; bl_t b = calloc(1, sizeof(*b)); if (b == NULL) - goto out; - b->b_fun = fun == NULL ? vsyslog : fun; + return NULL; + b->b_fun = fun; + b->b_syslog_data = sd; b->b_fd = -1; b->b_connected = -1; BL_INIT(b); @@ -295,11 +314,6 @@ bl_create(bool srv, const char *path, void (*fun)(int, const char *, va_list)) bl_init(b, srv); return b; -out: - free(b); - bl_log(fun, LOG_ERR, "%s: malloc failed (%s)", __func__, - strerror(errno)); - return NULL; } void @@ -327,7 +341,7 @@ bl_getsock(bl_t b, struct sockaddr_storage *ss, const struct sockaddr *sa, family = AF_INET6; break; default: - bl_log(b->b_fun, LOG_ERR, "%s: invalid socket len %u (%s)", + bl_log(b, LOG_ERR, "%s: invalid socket len %u (%s)", __func__, (unsigned)slen, ctx); errno = EINVAL; return -1; @@ -336,7 +350,7 @@ bl_getsock(bl_t b, struct sockaddr_storage *ss, const struct sockaddr *sa, memcpy(ss, sa, slen); if (ss->ss_family != family) { - bl_log(b->b_fun, LOG_INFO, + bl_log(b, LOG_INFO, "%s: correcting socket family %d to %d (%s)", __func__, ss->ss_family, family, ctx); ss->ss_family = family; @@ -344,7 +358,7 @@ bl_getsock(bl_t b, struct sockaddr_storage *ss, const struct sockaddr *sa, #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN if (ss->ss_len != slen) { - bl_log(b->b_fun, LOG_INFO, + bl_log(b, LOG_INFO, "%s: correcting socket len %u to %u (%s)", __func__, ss->ss_len, (unsigned)slen, ctx); ss->ss_len = (uint8_t)slen; @@ -424,16 +438,18 @@ bl_recv(bl_t b) union { char ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(CRED_SIZE)]; uint32_t fd; - CRED_TYPE sc; } ua; struct cmsghdr *cmsg; +#if GOT_CRED != 0 CRED_TYPE *sc; +#endif union { bl_message_t bl; char buf[512]; } ub; int got; ssize_t rlen; + size_t rem; bl_info_t *bi = &b->b_info; got = 0; @@ -449,18 +465,18 @@ bl_recv(bl_t b) msg.msg_flags = 0; msg.msg_control = ua.ctrl; - msg.msg_controllen = sizeof(ua.ctrl) + 100; + msg.msg_controllen = sizeof(ua.ctrl); rlen = recvmsg(b->b_fd, &msg, 0); if (rlen == -1) { - bl_log(b->b_fun, LOG_ERR, "%s: recvmsg failed (%s)", __func__, + bl_log(b, LOG_ERR, "%s: recvmsg failed (%s)", __func__, strerror(errno)); return NULL; } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level != SOL_SOCKET) { - bl_log(b->b_fun, LOG_ERR, + bl_log(b, LOG_ERR, "%s: unexpected cmsg_level %d", __func__, cmsg->cmsg_level); continue; @@ -468,10 +484,15 @@ bl_recv(bl_t b) switch (cmsg->cmsg_type) { case SCM_RIGHTS: if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) { - bl_log(b->b_fun, LOG_ERR, + int *fd = (void *)CMSG_DATA(cmsg); + size_t len = cmsg->cmsg_len / sizeof(int); + bl_log(b, LOG_ERR, "%s: unexpected cmsg_len %d != %zu", __func__, cmsg->cmsg_len, - CMSG_LEN(2 * sizeof(int))); + CMSG_LEN(sizeof(int))); + + for (size_t i = 0; i < len; i++) + (void)close(fd[i]); continue; } memcpy(&bi->bi_fd, CMSG_DATA(cmsg), sizeof(bi->bi_fd)); @@ -480,13 +501,13 @@ bl_recv(bl_t b) #ifdef CRED_MESSAGE case CRED_MESSAGE: sc = (void *)CMSG_DATA(cmsg); - bi->bi_uid = sc->CRED_SC_UID; - bi->bi_gid = sc->CRED_SC_GID; + bi->bi_uid = CRED_SC_UID(sc); + bi->bi_gid = CRED_SC_GID(sc); got |= GOT_CRED; break; #endif default: - bl_log(b->b_fun, LOG_ERR, + bl_log(b, LOG_ERR, "%s: unexpected cmsg_type %d", __func__, cmsg->cmsg_type); continue; @@ -495,7 +516,7 @@ bl_recv(bl_t b) } if (got != (GOT_CRED|GOT_FD)) { - bl_log(b->b_fun, LOG_ERR, "message missing %s %s", + bl_log(b, LOG_ERR, "message missing %s %s", #if GOT_CRED != 0 (got & GOT_CRED) == 0 ? "cred" : #endif @@ -503,13 +524,15 @@ bl_recv(bl_t b) return NULL; } - if ((size_t)rlen <= sizeof(ub.bl)) { - bl_log(b->b_fun, LOG_ERR, "message too short %zd", rlen); + rem = (size_t)rlen; + if (rem < sizeof(ub.bl)) { + bl_log(b, LOG_ERR, "message too short %zd", rlen); return NULL; } + rem -= sizeof(ub.bl); if (ub.bl.bl_version != BL_VERSION) { - bl_log(b->b_fun, LOG_ERR, "bad version %d", ub.bl.bl_version); + bl_log(b, LOG_ERR, "bad version %d", ub.bl.bl_version); return NULL; } @@ -520,7 +543,12 @@ bl_recv(bl_t b) bi->bi_uid = -1; bi->bi_gid = -1; #endif - strlcpy(bi->bi_msg, ub.bl.bl_data, MIN(sizeof(bi->bi_msg), - ((size_t)rlen - sizeof(ub.bl) + 1))); + if (rem == 0) + bi->bi_msg[0] = '\0'; + else { + rem = MIN(sizeof(bi->bi_msg) - 1, rem); + memcpy(bi->bi_msg, ub.bl.bl_data, rem); + bi->bi_msg[rem] = '\0'; + } return bi; } diff --git a/lib/blocklist.c b/lib/blocklist.c index 9c09f4186ba6..139fc4342626 100644 --- a/lib/blocklist.c +++ b/lib/blocklist.c @@ -1,4 +1,4 @@ -/* $NetBSD: blocklist.c,v 1.6 2019/11/06 20:50:01 christos Exp $ */ +/* $NetBSD: blocklist.c,v 1.4 2025/02/11 17:48:30 christos Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -32,8 +32,10 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> -__RCSID("$NetBSD: blocklist.c,v 1.6 2019/11/06 20:50:01 christos Exp $"); +#endif +__RCSID("$NetBSD: blocklist.c,v 1.4 2025/02/11 17:48:30 christos Exp $"); #include <stdio.h> #include <bl.h> @@ -98,7 +100,14 @@ blocklist_r(struct blocklist *bl, int action, int rfd, const char *msg) struct blocklist * blocklist_open(void) { - return bl_create(false, NULL, vsyslog); + return bl_create(false, NULL, vsyslog_r); +} + +struct blocklist * +blocklist_open2( + void (*logger)(int, struct syslog_data *, const char *, va_list)) +{ + return bl_create(false, NULL, logger); } void diff --git a/lib/libblocklist.3 b/lib/libblocklist.3 index 8368624dbc6a..7a016625a047 100644 --- a/lib/libblocklist.3 +++ b/lib/libblocklist.3 @@ -1,4 +1,4 @@ -.\" $NetBSD: libblocklist.3,v 1.10 2020/03/30 15:47:15 christos Exp $ +.\" $NetBSD: libblocklist.3,v 1.7 2025/02/05 20:14:30 christos Exp $ .\" .\" Copyright (c) 2015 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,23 +27,26 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd March 30, 2020 +.Dd February 5, 2025 .Dt LIBBLOCKLIST 3 .Os .Sh NAME .Nm blocklist_open , +.Nm blocklist_open2 , .Nm blocklist_close , .Nm blocklist_r , .Nm blocklist , .Nm blocklist_sa , .Nm blocklist_sa_r -.Nd Blacklistd notification library +.Nd Blocklistd notification library .Sh LIBRARY .Lb libblocklist .Sh SYNOPSIS .In blocklist.h .Ft struct blocklist * .Fn blocklist_open "void" +.Ft struct blocklist * +.Fn blocklist_open2 "void (*logger)(int, struct syslog_data *, va_list)" .Ft void .Fn blocklist_close "struct blocklist *cookie" .Ft int @@ -68,6 +71,19 @@ and returns a pointer to it, or .Dv NULL on failure. .Pp +The function +.Fn blocklist_open2 +is similar to +.Fn blocklist_open +but allows a +.Fa logger +to be specified. +If the +.Fa logger +is +.Dv NULL , +then no logging is performed. +.Pp The .Fn blocklist_close function frees all memory and resources used. @@ -89,27 +105,21 @@ argument. The .Ar action parameter can take these values: -.Bl -tag -width ".Va BLOCKLIST_ABUSIVE_BEHAVIOR" +.Bl -tag -width ".Dv BLOCKLIST_ABUSIVE_BEHAVIOR" +.It Va BLOCKLIST_BAD_USER +The sending daemon has determined the username presented for +authentication is invalid. +This is considered as one failure count. .It Va BLOCKLIST_AUTH_FAIL There was an unsuccessful authentication attempt. -.It Va BLOCKLIST_AUTH_OK -A user successfully authenticated. +This is considered as two failure counts together. .It Va BLOCKLIST_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 BLOCKLIST_BAD_USER -The sending daemon has determined the username -presented for authentication is invalid. -The -.Xr blocklistd 8 -daemon compares the username to a configured list of forbidden -usernames and -blocks the address immediately if a forbidden username matches. -(The -.Ar BLOCKLIST_BAD_USER -support is not currently available.) +The sending daemon has detected abusive behavior from the remote system. +This is considered as a total immediate failure. +The remote address will be blocked as soon as possible. +.It Va BLOCKLIST_AUTH_OK +A valid user successfully authenticated. +Any entry for the remote address will be removed as soon as possible. .El .Pp The diff --git a/lib/shlib_version b/lib/shlib_version index 97c9f92d6b8f..3d7c908e43d6 100644 --- a/lib/shlib_version +++ b/lib/shlib_version @@ -1,2 +1,2 @@ major=0 -minor=0 +minor=1 diff --git a/libexec/Makefile b/libexec/Makefile index da7f4980b569..619d962c23b2 100644 --- a/libexec/Makefile +++ b/libexec/Makefile @@ -1,4 +1,4 @@ -# $NetBSD$ +# $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ SCRIPTS= blocklistd-helper SCRIPTSDIR= /libexec diff --git a/libexec/blocklistd-helper b/libexec/blocklistd-helper index a5f239fd2c1c..f27cde4ed4ea 100644..100755 --- a/libexec/blocklistd-helper +++ b/libexec/blocklistd-helper @@ -17,24 +17,41 @@ if [ -f "/etc/ipfw-blocklist.rc" ]; then fi if [ -z "$pf" ]; then - for f in npf pf ipf; do - if [ -f "/etc/$f.conf" ]; then + for f in npf pf ipfilter ipfw; do + if [ -x /etc/rc.d/$f ]; then + if /etc/rc.d/$f status >/dev/null 2>&1; then + pf="$f" + break + fi + elif [ -f "/etc/$f.conf" ]; then + # xxx assume a config file means it can be enabled -- + # and the first one wins! pf="$f" break fi done fi +if [ -z "$pf" -a -x "/sbin/iptables" ]; then + pf="iptables" +fi + if [ -z "$pf" ]; then echo "$0: Unsupported packet filter" 1>&2 exit 1 fi +flags= if [ -n "$3" ]; then + raw_proto="$3" proto="proto $3" + if [ $3 = "tcp" ]; then + flags="flags S/SAFR" + fi fi if [ -n "$6" ]; then + raw_port="$6" port="port $6" fi @@ -51,12 +68,65 @@ esac case "$1" in add) case "$pf" in - ipf) - /sbin/ipfstat -io | /sbin/ipf -I -f - >/dev/null 2>&1 - echo block in quick $proto from $addr/$mask to \ - any port=$6 head port$6 | \ - /sbin/ipf -I -f - -s >/dev/null 2>&1 && echo OK + ipfilter) + # N.B.: If you reload /etc/ipf.conf then you need to stop and + # restart blocklistd (and make sure blocklistd_flags="-r"). + # This should normally already be implemented in + # /etc/rc.d/ipfilter, but if then not add the following lines to + # the end of the ipfilter_reload() function: + # + # if checkyesnox blocklistd; then + # /etc/rc.d/blocklistd restart + # fi + # + # XXX we assume the following rule is present in /etc/ipf.conf: + # (should we check? -- it probably cannot be added dynamically) + # + # block in proto tcp/udp from any to any head blocklistd + # + # where "blocklistd" is the default rulename (i.e. "$2") + # + # This rule can come before any rule that logs connections, + # etc., and should be followed by final rules such as: + # + # # log all as-yet unblocked incoming TCP connection + # # attempts + # log in proto tcp from any to any flags S/SAFR + # # last "pass" match wins for all non-blocked packets + # pass in all + # pass out all + # + # I.e. a "pass" rule which will be the final match and override + # the "block". This way the rules added by blocklistd will + # actually block packets, and prevent logging of them as + # connections, because they include the "quick" flag. + # + # N.b.: $port is not included/used in rules -- abusers are cut + # off completely from all services! + # + # Note RST packets are not returned for blocked SYN packets of + # active attacks, so the port will not appear to be closed. + # This will probably give away the fact that a firewall has been + # triggered to block connections, but it prevents generating + # extra outbound traffic, and it may also slow down the attacker + # somewhat. + # + # Note also that we don't block all packets, just new attempts + # to open connections (see $flags above). This allows us to do + # counterespionage against the attacker (or continue to make use + # of any other services that might be on the same subnet as the + # supposed attacker). However it does not kill any active + # connections -- we rely on the reporting daemon to do its own + # protection and cleanup. + # + # N.B.: The rule generated here must exactly match the + # corresponding rule generated for the "rem" command below! + # + echo block in log quick $proto \ + from $addr/$mask to any $flags group $2 | \ + /sbin/ipf -A -f - >/dev/null 2>&1 && echo OK ;; + ipfw) # use $ipfw_offset+$port for rule number rule=$(($ipfw_offset + $6)) @@ -69,10 +139,23 @@ add) table"("$tname")" to any dst-port $6 >/dev/null && \ echo OK ;; + + iptables) + if ! /sbin/iptables --list "$2" >/dev/null 2>&1; then + /sbin/iptables --new-chain "$2" + fi + /sbin/iptables --append INPUT --proto "$raw_proto" \ + --dport "$raw_port" --jump "$2" + /sbin/iptables --append "$2" --proto "$raw_proto" \ + --source "$addr/$mask" --dport "$raw_port" --jump DROP + echo OK + ;; + npf) /sbin/npfctl rule "$2" add block in final $proto from \ "$addr/$mask" to any $port ;; + pf) # if the filtering rule does not exist, create it /sbin/pfctl -a "$2/$6" -sr 2>/dev/null | \ @@ -80,45 +163,105 @@ add) echo "block in quick $proto from <port$6> to any $port" | \ /sbin/pfctl -a "$2/$6" -f - # insert $ip/$mask into per-protocol/port anchored table - /sbin/pfctl -a "$2/$6" -t "port$6" -T add "$addr/$mask" && \ - echo OK + /sbin/pfctl -qa "$2/$6" -t "port$6" -T add "$addr/$mask" && \ + /sbin/pfctl -qk "$addr" && echo OK ;; + esac ;; rem) case "$pf" in - ipf) - /sbin/ipfstat -io | /sbin/ipf -I -f - >/dev/null 2>&1 - echo block in quick $proto from $addr/$mask to \ - any port=$6 head port$6 | \ - /sbin/ipf -I -r -f - -s >/dev/null 2>&1 && echo OK + ipfilter) + # N.B.: The rule generated here must exactly match the + # corresponding rule generated for the "add" command above! + # + echo block in log quick $proto \ + from $addr/$mask to any $flags group $2 | \ + /sbin/ipf -A -r -f - >/dev/null 2>&1 && echo OK ;; + ipfw) /sbin/ipfw table "port$6" delete "$addr/$mask" 2>/dev/null && \ echo OK ;; + + iptables) + if /sbin/iptables --list "$2" >/dev/null 2>&1; then + /sbin/iptables --delete "$2" --proto "$raw_proto" \ + --source "$addr/$mask" --dport "$raw_port" \ + --jump DROP + fi + echo OK + ;; + npf) /sbin/npfctl rule "$2" rem-id "$7" ;; + pf) - /sbin/pfctl -a "$2/$6" -t "port$6" -T delete "$addr/$mask" && \ + /sbin/pfctl -qa "$2/$6" -t "port$6" -T delete "$addr/$mask" && \ echo OK ;; + esac ;; flush) case "$pf" in - ipf) - /sbin/ipf -Z -I -Fi -s > /dev/null && echo OK + ipfilter) + # + # N.B. WARNING: This is obviously not reentrant! + # + # First we flush all the rules from the inactive set, then we + # reload the ones that do not belong to the group "$2", and + # finally we swap the active and inactive rule sets. + # + /sbin/ipf -I -F a + # + # "ipf -I -F a" also flushes active accounting rules! + # + # Note that accounting rule groups are unique to accounting + # rules and have nothing to do with filter rules, though of + # course theoretically one could use the same group name for + # them too. + # + # In theory anyone using any such accounting rules should have a + # wrapper /etc/rc.conf.d/blocklistd script (and corresponding + # /etc/rc.conf.d/ipfilter script) that will record and + # consolidate the values accumulated by such accounting rules + # before they are flushed, since otherwise their counts will be + # lost forever. + # + /usr/sbin/ipfstat -io | fgrep -v "group $2" | \ + /sbin/ipf -I -f - >/dev/null 2>&1 + # + # This MUST be done last and separately as "-s" is executed + # _while_ the command arguments are being processed! + # + /sbin/ipf -s && echo OK ;; + ipfw) /sbin/ipfw table "port$6" flush 2>/dev/null && echo OK ;; + + iptables) + if /sbin/iptables --list "$2" >/dev/null 2>&1; then + /sbin/iptables --flush "$2" + fi + echo OK + ;; + npf) /sbin/npfctl rule "$2" flush ;; + pf) - /sbin/pfctl -a "$2/$6" -t "port$6" -T flush && echo OK + # dynamically determine which anchors exist + for anchor in $(/sbin/pfctl -a "$2" -s Anchors 2> /dev/null); do + /sbin/pfctl -a "$anchor" -t "port${anchor##*/}" -T flush + /sbin/pfctl -a "$anchor" -F rules + done + echo OK ;; esac ;; diff --git a/port/Makefile.am b/port/Makefile.am index 76ce02fe6f2e..0e6085f9580f 100644 --- a/port/Makefile.am +++ b/port/Makefile.am @@ -1,13 +1,27 @@ # ACLOCAL_AMFLAGS = -I m4 lib_LTLIBRARIES = libblocklist.la -include_HEADERS = ../include/blocklist.h +include_HEADERS = $(srcdir)/../include/blocklist.h -bin_PROGRAMS = blocklistd blocklistctl srvtest cltest +exampledir = $(datarootdir)/examples +example_DATA = $(srcdir)/../etc/blocklistd.conf $(srcdir)/../etc/npf.conf $(srcdir)/../etc/ipf.conf -VPATH = ../bin:../lib:../test:../include +sbin_PROGRAMS = blocklistd blocklistctl +noinst_PROGRAMS = srvtest cltest +libexec_SCRIPTS = $(srcdir)/../libexec/blocklistd-helper -AM_CPPFLAGS = -I../include -DDOT="." +man5_MANS = $(srcdir)/../bin/blocklistd.conf.5 +man8_MANS = $(srcdir)/../bin/blocklistd.8 $(srcdir)/../bin/blocklistctl.8 + +VPATH = $(srcdir)/../port:$(srcdir)/../bin:$(srcdir)/../lib:$(srcdir)/../test:$(srcdir)/../include + +AM_CPPFLAGS = -I$(srcdir)/../include -DDOT="." +AM_CPPFLAGS += -D_PATH_BLCONF=\"$(sysconfdir)/blocklistd.conf\" +AM_CPPFLAGS += -D_PATH_BLCONTROL=\"$(libexecdir)/blocklistd-helper\" +AM_CPPFLAGS += -D_PATH_BLSOCK=\"$(runstatedir)/blocklistd.sock\" +AM_CPPFLAGS += -D_PATH_BLSTATE=\"$(localstatedir)/db/blocklistd.db\" +AM_CPPFLAGS += -std=c99 -D_POSIX_C_SOURCE=200809L -D__EXTENSIONS__ +AM_CPPFLAGS += -D__BSD_VISIBLE=1 AM_CFLAGS = @WARNINGS@ libblocklist_la_SOURCES = bl.c blocklist.c diff --git a/port/_strtoi.h b/port/_strtoi.h index 031a76c8dc22..f50eefd67ff1 100644 --- a/port/_strtoi.h +++ b/port/_strtoi.h @@ -1,4 +1,4 @@ -/* $NetBSD: _strtoi.h,v 1.2 2015/01/18 17:55:22 christos Exp $ */ +/* $NetBSD: _strtoi.h,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ */ /*- * Copyright (c) 1990, 1993 diff --git a/port/configure.ac b/port/configure.ac index a459f4542f57..99ecf8732c93 100644 --- a/port/configure.ac +++ b/port/configure.ac @@ -7,9 +7,10 @@ AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) AC_SUBST(WARNINGS) +AC_SUBST(LINK_NTOA) dnl Checks for programs. -AC_PROG_CC_STDC +AC_PROG_CC AC_USE_SYSTEM_EXTENSIONS AM_PROG_CC_C_O AC_C_BIGENDIAN @@ -18,18 +19,19 @@ AC_PROG_LN_S LT_INIT([disable-static pic-only]) gl_VISIBILITY dnl Checks for headers -AC_HEADER_STDC AC_HEADER_MAJOR AC_HEADER_SYS_WAIT AC_CHECK_HEADERS(stdint.h fcntl.h stdint.h inttypes.h unistd.h) AC_CHECK_HEADERS(sys/un.h sys/socket.h limits.h) AC_CHECK_HEADERS(arpa/inet.h getopt.h err.h) AC_CHECK_HEADERS(sys/types.h util.h sys/time.h time.h) -AC_CHECK_HEADERS(netatalk/at.h net/if_dl.h db.h db_185.h) +AC_CHECK_HEADERS(netatalk/at.h db.h db_185.h) +AC_CHECK_HEADERS(sys/cdefs.h) AC_CHECK_LIB(rt, clock_gettime) AC_CHECK_LIB(db, __db185_open) AC_CHECK_LIB(util, pidfile) AC_CHECK_LIB(util, sockaddr_snprintf) +AC_SEARCH_LIBS(__xnet_connect, socket) AH_BOTTOM([ #ifndef __NetBSD__ @@ -82,7 +84,7 @@ dnl Checks for functions AC_CHECK_FUNCS(strerror) dnl Provide implementation of some required functions if necessary -AC_REPLACE_FUNCS(strtoi sockaddr_snprintf popenve clock_gettime strlcpy strlcat getprogname fparseln fgetln pidfile) +AC_REPLACE_FUNCS(strtoi sockaddr_snprintf popenve clock_gettime strlcpy strlcat getprogname fparseln fgetln pidfile vsyslog_r) dnl See if we are cross-compiling AM_CONDITIONAL(IS_CROSS_COMPILE, test "$cross_compiling" = yes) diff --git a/port/debian/blocklist.manpages b/port/debian/blocklist.manpages new file mode 100644 index 000000000000..29bf2aa3eda8 --- /dev/null +++ b/port/debian/blocklist.manpages @@ -0,0 +1,4 @@ +bin/blocklistctl.8 +bin/blocklistd.8 +bin/blocklistd.conf.5 +lib/libblocklist.3 diff --git a/port/debian/changelog b/port/debian/changelog new file mode 100644 index 000000000000..cd69e1d13e09 --- /dev/null +++ b/port/debian/changelog @@ -0,0 +1,6 @@ +blocklist (1.7+nmu1) unstable; urgency=low + + * nmu; import from https://github.com/zoulasc/blocklist + * + + -- Two Sigma Base Platform Engineering <bpeng@twosigma.com> Tue, 30 Jun 2020 14:40:28 +0000 diff --git a/port/debian/compat b/port/debian/compat new file mode 100644 index 000000000000..f599e28b8ab0 --- /dev/null +++ b/port/debian/compat @@ -0,0 +1 @@ +10 diff --git a/port/debian/control b/port/debian/control new file mode 100644 index 000000000000..cec0c4ef1a3c --- /dev/null +++ b/port/debian/control @@ -0,0 +1,21 @@ +Source: blocklist +Section: net +Priority: optional +Maintainer: Christos Zoulas <christos@zoulas.com> +Standards-Version: 4.4.1 +Build-Depends: debhelper (>= 10~), + dh-exec, + dpkg-dev (>= 1.16.1~), + libdb-dev, + quilt + +Package: blocklist +Architecture: any +Homepage: https://github.com/zoulasc/blocklist +Depends: ${misc:Depends}, + ${shlibs:Depends}, + libdb5.3 +Description: This package contains library that can be used + by network daemons to communicate with a packet filter via + a daemon to enforce opening and closing ports dynamically + based on policy. diff --git a/port/debian/copyright b/port/debian/copyright new file mode 100644 index 000000000000..1eb037760415 --- /dev/null +++ b/port/debian/copyright @@ -0,0 +1,38 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: blocklist +Upstream-Contact: christos@zoulas.com +Source: https://github.com/zoulasc/blocklist +Comment: + This package contains library that can be used by network daemons to + communicate with a packet filter via a daemon to enforce opening and + closing ports dynamically based on policy. + +Files: * +Copyright: 2020 Christos Zoulas +License: NetBSD + * 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. diff --git a/port/debian/install b/port/debian/install new file mode 100644 index 000000000000..6c5e1ac71267 --- /dev/null +++ b/port/debian/install @@ -0,0 +1 @@ +libexec/blocklistd-helper usr/libexec diff --git a/port/debian/rules b/port/debian/rules new file mode 100755 index 000000000000..80c2d9c5a827 --- /dev/null +++ b/port/debian/rules @@ -0,0 +1,15 @@ +#!/usr/bin/make -f + +# Uncomment this to turn on verbose mode. +# export DH_VERBOSE=1 + +# This has to be exported to make some magic below work. +export DH_OPTIONS + +%: + dh $@ --sourcedirectory=port --with quilt + +# https://lintian.debian.org/tags/non-empty-dependency_libs-in-la-file.html +override_dh_auto_install: + dh_auto_install + sed -i "/dependency_libs/ s/'.*'/''/" `find . -name '*.la'` diff --git a/port/debian/source/format b/port/debian/source/format new file mode 100644 index 000000000000..89ae9db8f88b --- /dev/null +++ b/port/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/port/fgetln.c b/port/fgetln.c index 54a3fa4ad897..006e19f5279f 100644 --- a/port/fgetln.c +++ b/port/fgetln.c @@ -1,4 +1,4 @@ -/* $NetBSD: fgetln.c,v 1.9 2008/04/29 06:53:03 martin Exp $ */ +/* $NetBSD: fgetln.c,v 1.1.1.1 2020/06/15 01:52:54 christos Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. diff --git a/port/fparseln.c b/port/fparseln.c index eef66598380a..22850ea9e304 100644 --- a/port/fparseln.c +++ b/port/fparseln.c @@ -1,4 +1,4 @@ -/* $NetBSD: fparseln.c,v 1.10 2009/10/21 01:07:45 snj Exp $ */ +/* $NetBSD: fparseln.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ /* * Copyright (c) 1997 Christos Zoulas. All rights reserved. @@ -27,9 +27,11 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> +#endif #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: fparseln.c,v 1.10 2009/10/21 01:07:45 snj Exp $"); +__RCSID("$NetBSD: fparseln.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); #endif /* LIBC_SCCS and not lint */ #include <assert.h> diff --git a/port/pidfile.c b/port/pidfile.c index bb4d9dd0ddf8..1dbbf510c4e3 100644 --- a/port/pidfile.c +++ b/port/pidfile.c @@ -1,4 +1,4 @@ -/* $NetBSD: pidfile.c,v 1.1 2015/01/22 16:19:53 christos Exp $ */ +/* $NetBSD: pidfile.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -32,9 +32,11 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> +#endif #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: pidfile.c,v 1.1 2015/01/22 16:19:53 christos Exp $"); +__RCSID("$NetBSD: pidfile.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); #endif #include <sys/param.h> diff --git a/port/popenve.c b/port/popenve.c index 054f93eddca9..bdff8cdc1de4 100644 --- a/port/popenve.c +++ b/port/popenve.c @@ -1,4 +1,4 @@ -/* $NetBSD: popenve.c,v 1.1 2015/01/22 01:39:18 christos Exp $ */ +/* $NetBSD: popenve.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ /* * Copyright (c) 1988, 1993 @@ -36,12 +36,14 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> +#endif #if defined(LIBC_SCCS) && !defined(lint) #if 0 static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95"; #else -__RCSID("$NetBSD: popenve.c,v 1.1 2015/01/22 01:39:18 christos Exp $"); +__RCSID("$NetBSD: popenve.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ diff --git a/port/port.h b/port/port.h index 2808d6b8ef2a..d1a9ac6bd6e5 100644 --- a/port/port.h +++ b/port/port.h @@ -1,6 +1,7 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif +#include <sys/param.h> #include <stdio.h> #include <inttypes.h> #include <time.h> @@ -15,6 +16,22 @@ #define __dead __attribute__((__noreturn__)) #endif +#ifndef __BEGIN_DECLS +#define __BEGIN_DECLS +#endif + +#ifndef __END_DECLS +#define __END_DECLS +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + #ifndef __RCSID #define __RCSID(a) #endif @@ -27,6 +44,10 @@ #define __arraycount(a) (sizeof(a) / sizeof(a[0])) #endif +#ifndef __STRING +#define __STRING(x) #x +#endif + #ifndef HAVE_STRLCPY size_t strlcpy(char *, const char *, size_t); #endif @@ -78,9 +99,10 @@ int clock_gettime(int, struct timespec *); #define CLOCK_REALTIME 0 #endif -#if !defined(__FreeBSD__) -#define _PATH_BLCONF "conf" -#define _PATH_BLCONTROL "control" -#define _PATH_BLSOCK "blocklistd.sock" -#define _PATH_BLSTATE "blocklistd.db" +#ifndef HAVE_VSYSLOG_R +#define SYSLOG_DATA_INIT { 0 } +struct syslog_data { + int dummy; +}; +void vsyslog_r(int, struct syslog_data *, const char *, va_list); #endif diff --git a/port/sockaddr_snprintf.c b/port/sockaddr_snprintf.c index 7b1c96548f75..a37eded14a88 100644 --- a/port/sockaddr_snprintf.c +++ b/port/sockaddr_snprintf.c @@ -1,4 +1,4 @@ -/* $NetBSD: sockaddr_snprintf.c,v 1.10 2016/04/05 12:28:57 christos Exp $ */ +/* $NetBSD: sockaddr_snprintf.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ /*- * Copyright (c) 2004 The NetBSD Foundation, Inc. @@ -32,9 +32,11 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> +#endif #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: sockaddr_snprintf.c,v 1.10 2016/04/05 12:28:57 christos Exp $"); +__RCSID("$NetBSD: sockaddr_snprintf.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); #endif /* LIBC_SCCS and not lint */ #include <sys/param.h> diff --git a/port/strlcat.c b/port/strlcat.c index 86a545c4b3ad..8cabd654e6b0 100644 --- a/port/strlcat.c +++ b/port/strlcat.c @@ -1,4 +1,4 @@ -/* $NetBSD: strlcat.c,v 1.1 2015/01/22 02:36:15 christos Exp $ */ +/* $NetBSD: strlcat.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ /* $OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp $ */ /* @@ -22,9 +22,12 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> +#endif + #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: strlcat.c,v 1.1 2015/01/22 02:36:15 christos Exp $"); +__RCSID("$NetBSD: strlcat.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); #endif /* LIBC_SCCS and not lint */ #ifdef _LIBC diff --git a/port/strlcpy.c b/port/strlcpy.c index 248f2ea3bd7b..3de72a640c59 100644 --- a/port/strlcpy.c +++ b/port/strlcpy.c @@ -1,4 +1,4 @@ -/* $NetBSD: strlcpy.c,v 1.1 2015/01/22 02:36:15 christos Exp $ */ +/* $NetBSD: strlcpy.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ /* $OpenBSD: strlcpy.c,v 1.7 2003/04/12 21:56:39 millert Exp $ */ /* @@ -22,9 +22,12 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> +#endif + #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: strlcpy.c,v 1.1 2015/01/22 02:36:15 christos Exp $"); +__RCSID("$NetBSD: strlcpy.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); #endif /* LIBC_SCCS and not lint */ #ifdef _LIBC diff --git a/port/strtoi.c b/port/strtoi.c index ef44c40f681a..b0bed7058cc3 100644 --- a/port/strtoi.c +++ b/port/strtoi.c @@ -1,4 +1,4 @@ -/* $NetBSD: strtoi.c,v 1.2 2015/01/22 02:35:44 christos Exp $ */ +/* $NetBSD: strtoi.c,v 1.2 2025/02/11 17:48:31 christos Exp $ */ /*- * Copyright (c) 2005 The DragonFly Project. All rights reserved. @@ -33,8 +33,10 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> -__RCSID("$NetBSD: strtoi.c,v 1.2 2015/01/22 02:35:44 christos Exp $"); +#endif +__RCSID("$NetBSD: strtoi.c,v 1.2 2025/02/11 17:48:31 christos Exp $"); #if defined(_KERNEL) #include <sys/param.h> diff --git a/port/vsyslog_r.c b/port/vsyslog_r.c new file mode 100644 index 000000000000..848f31b04453 --- /dev/null +++ b/port/vsyslog_r.c @@ -0,0 +1,13 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <syslog.h> +#include <stdarg.h> + +void +vsyslog_r(int priority, struct syslog_data *sd __unused, const char *fmt, va_list ap) +{ + vsyslog(priority, fmt, ap); +} + diff --git a/test/Makefile b/test/Makefile index cf7651154134..d127955acdb7 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.2 2015/01/22 05:03:52 christos Exp $ +# $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:54 christos Exp $ MKMAN=no diff --git a/test/cltest.c b/test/cltest.c index 1b6b1b4f0885..dc77a522bad8 100644 --- a/test/cltest.c +++ b/test/cltest.c @@ -1,4 +1,4 @@ -/* $NetBSD: cltest.c,v 1.5 2015/01/22 05:03:52 christos Exp $ */ +/* $NetBSD: cltest.c,v 1.2 2025/02/11 17:48:31 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -32,8 +32,10 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> -__RCSID("$NetBSD: cltest.c,v 1.5 2015/01/22 05:03:52 christos Exp $"); +#endif +__RCSID("$NetBSD: cltest.c,v 1.2 2025/02/11 17:48:31 christos Exp $"); #include <sys/types.h> #include <sys/socket.h> diff --git a/test/srvtest.c b/test/srvtest.c index 146b71c1a4f8..4eb9468ed5fd 100644 --- a/test/srvtest.c +++ b/test/srvtest.c @@ -1,4 +1,4 @@ -/* $NetBSD: srvtest.c,v 1.9 2015/01/22 05:35:55 christos Exp $ */ +/* $NetBSD: srvtest.c,v 1.2 2025/02/11 17:43:16 christos Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -32,8 +32,10 @@ #include "config.h" #endif +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> -__RCSID("$NetBSD: srvtest.c,v 1.9 2015/01/22 05:35:55 christos Exp $"); +#endif +__RCSID("$NetBSD: srvtest.c,v 1.2 2025/02/11 17:43:16 christos Exp $"); #include <sys/types.h> #include <sys/socket.h> @@ -167,7 +169,11 @@ static __dead void usage(int c) { warnx("Unknown option `%c'", (char)c); - fprintf(stderr, "Usage: %s [-u] [-p <num>]\n", getprogname()); + fprintf(stderr, "Usage: %s [-u] [-p <num>]" +#ifdef BLDEBUG + " [-s <sockpath>]" +#endif + "\n", getprogname()); exit(EXIT_FAILURE); } @@ -182,14 +188,16 @@ main(int argc, char *argv[]) struct pollfd pfd[NUMFD]; int type = SOCK_STREAM, c; in_port_t port = 6161; - - signal(SIGCHLD, SIG_IGN); - #ifdef BLDEBUG - b = bl_create(false, "blsock", vsyslog); + char *sockpath = "blsock"; + const char *optstr = "up:s:"; +#else + const char *optstr = "up:"; #endif - while ((c = getopt(argc, argv, "up:")) != -1) + signal(SIGCHLD, SIG_IGN); + + while ((c = getopt(argc, argv, optstr)) != -1) switch (c) { case 'u': type = SOCK_DGRAM; @@ -197,10 +205,20 @@ main(int argc, char *argv[]) case 'p': port = (in_port_t)atoi(optarg); break; +#ifdef BLDEBUG + case 's': + sockpath = (char *)optarg; + break; +#endif default: usage(c); } +#ifdef BLDEBUG + b = bl_create(false, sockpath, vsyslog_r); +#endif + + pfd[0].fd = cr(AF_INET, type, port); pfd[0].events = POLLIN; #if NUMFD > 1 |
