├── port ├── debian │ ├── compat │ ├── source │ │ └── format │ ├── install │ ├── blocklist.manpages │ ├── changelog │ ├── rules │ ├── control │ └── copyright ├── m4 │ └── .cvsignore ├── vsyslog_r.c ├── clock_gettime.c ├── getprogname.c ├── Makefile.am ├── strtoi.c ├── strlcpy.c ├── port.h ├── configure.ac ├── strlcat.c ├── _strtoi.h ├── fgetln.c ├── pidfile.c ├── fparseln.c ├── popenve.c └── sockaddr_snprintf.c ├── lib ├── shlib_version ├── Makefile ├── blocklist.c ├── libblocklist.3 └── bl.c ├── Makefile ├── etc ├── rc.d │ ├── Makefile │ └── blocklistd ├── Makefile ├── npf.conf ├── blocklistd.conf └── ipf.conf ├── libexec ├── Makefile └── blocklistd-helper ├── include ├── Makefile ├── blocklist.h └── bl.h ├── test ├── Makefile ├── cltest.c └── srvtest.c ├── Makefile.inc ├── bin ├── Makefile ├── run.h ├── support.h ├── internal.c ├── internal.h ├── state.h ├── conf.h ├── support.c ├── blocklistctl.8 ├── run.c ├── blocklistctl.c ├── state.c ├── blocklistd.conf.5 ├── blocklistd.8 └── blocklistd.c ├── TODO ├── diff ├── ftpd.diff ├── proftpd.diff ├── postfix.diff ├── ssh.diff └── named.diff └── README /port/debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /port/m4/.cvsignore: -------------------------------------------------------------------------------- 1 | *.m4 2 | -------------------------------------------------------------------------------- /lib/shlib_version: -------------------------------------------------------------------------------- 1 | major=0 2 | minor=1 3 | -------------------------------------------------------------------------------- /port/debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /port/debian/install: -------------------------------------------------------------------------------- 1 | libexec/blocklistd-helper usr/libexec 2 | -------------------------------------------------------------------------------- /port/debian/blocklist.manpages: -------------------------------------------------------------------------------- 1 | bin/blocklistctl.8 2 | bin/blocklistd.8 3 | bin/blocklistd.conf.5 4 | lib/libblocklist.3 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:52 christos Exp $ 2 | 3 | SUBDIR = lib .WAIT include bin etc libexec 4 | 5 | .include 6 | -------------------------------------------------------------------------------- /etc/rc.d/Makefile: -------------------------------------------------------------------------------- 1 | # $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ 2 | 3 | SCRIPTS=blocklistd 4 | SCRIPTSDIR=/etc/rc.d 5 | 6 | .include 7 | -------------------------------------------------------------------------------- /libexec/Makefile: -------------------------------------------------------------------------------- 1 | # $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ 2 | 3 | SCRIPTS= blocklistd-helper 4 | SCRIPTSDIR= /libexec 5 | 6 | .include 7 | -------------------------------------------------------------------------------- /port/debian/changelog: -------------------------------------------------------------------------------- 1 | blocklist (1.7+nmu1) unstable; urgency=low 2 | 3 | * nmu; import from https://github.com/zoulasc/blocklist 4 | * 5 | 6 | -- Two Sigma Base Platform Engineering Tue, 30 Jun 2020 14:40:28 +0000 7 | -------------------------------------------------------------------------------- /include/Makefile: -------------------------------------------------------------------------------- 1 | # $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ 2 | 3 | # Doing a make includes builds /usr/include 4 | 5 | NOOBJ= # defined 6 | 7 | INCS= blocklist.h 8 | INCSDIR= /usr/include 9 | 10 | .include 11 | -------------------------------------------------------------------------------- /etc/Makefile: -------------------------------------------------------------------------------- 1 | # $NetBSD: Makefile,v 1.2 2025/02/05 20:24:26 christos Exp $ 2 | 3 | SUBDIR= rc.d 4 | 5 | FILESDIR= /usr/share/examples/blocklist 6 | FILESMODE= 644 7 | FILES= blocklistd.conf ipf.conf npf.conf 8 | 9 | .include 10 | .include 11 | -------------------------------------------------------------------------------- /etc/npf.conf: -------------------------------------------------------------------------------- 1 | # Transparent firewall example for blocklistd 2 | 3 | $ext_if = "bnx0" 4 | 5 | set bpf.jit on; 6 | alg "icmp" 7 | 8 | group "external" on $ext_if { 9 | ruleset "blocklistd" 10 | pass final all 11 | } 12 | 13 | group default { 14 | pass final all 15 | } 16 | -------------------------------------------------------------------------------- /port/vsyslog_r.c: -------------------------------------------------------------------------------- 1 | #ifdef HAVE_CONFIG_H 2 | #include "config.h" 3 | #endif 4 | 5 | #include 6 | #include 7 | 8 | void 9 | vsyslog_r(int priority, struct syslog_data *sd __unused, const char *fmt, va_list ap) 10 | { 11 | vsyslog(priority, fmt, ap); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | # $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:54 christos Exp $ 2 | 3 | MKMAN=no 4 | 5 | PROGS=srvtest cltest 6 | SRCS.srvtest = srvtest.c 7 | SRCS.cltest = cltest.c 8 | CPPFLAGS+=-DBLDEBUG 9 | LDADD+=-lutil 10 | DPADD+=${LIBUTIL} 11 | 12 | .include 13 | -------------------------------------------------------------------------------- /Makefile.inc: -------------------------------------------------------------------------------- 1 | # $NetBSD: Makefile.inc,v 1.3 2025/02/11 17:48:30 christos Exp $ 2 | 3 | WARNS=6 4 | .if !defined(LIB) 5 | LDADD+= -lblocklist 6 | DPADD+= ${LIBBLOCKLIST} 7 | .endif 8 | CPPFLAGS+= -I${.CURDIR}/../include 9 | CPPFLAGS+=-DHAVE_STRUCT_SOCKADDR_SA_LEN -DHAVE_UTIL_H -DHAVE_DB_H 10 | CPPFLAGS+=-DHAVE_SYS_CDEFS_H 11 | 12 | -------------------------------------------------------------------------------- /port/clock_gettime.c: -------------------------------------------------------------------------------- 1 | #ifdef HAVE_CONFIG_H 2 | #include "config.h" 3 | #endif 4 | 5 | #include 6 | #include 7 | 8 | int 9 | clock_gettime(int clock __unused, struct timespec *ts) 10 | { 11 | struct timeval tv; 12 | if (gettimeofday(&tv, NULL) == -1) 13 | return -1; 14 | ts->tv_sec = tv.tv_sec; 15 | ts->tv_nsec = tv.tv_usec * 1000; 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /port/getprogname.c: -------------------------------------------------------------------------------- 1 | #ifdef HAVE_CONFIG_H 2 | #include "config.h" 3 | #endif 4 | #include 5 | 6 | extern char *__progname; 7 | 8 | const char * 9 | getprogname(void) 10 | { 11 | return __progname; 12 | } 13 | 14 | void 15 | setprogname(char *p) 16 | { 17 | char *q; 18 | if (p == NULL) 19 | return; 20 | if ((q = strrchr(p, '/')) != NULL) 21 | __progname = ++q; 22 | else 23 | __progname = p; 24 | } 25 | -------------------------------------------------------------------------------- /etc/blocklistd.conf: -------------------------------------------------------------------------------- 1 | # Blocklist rule 2 | # adr/mask:port type proto owner name nfail duration 3 | [local] 4 | ssh stream * * * 3 6h 5 | ftp stream * * * 3 6h 6 | domain * * named * 3 12h 7 | #6161 stream tcp6 christos * 2 10m 8 | * * * * * 3 60 9 | 10 | # adr/mask:port type proto owner name nfail duration 11 | [remote] 12 | #129.168.0.0/16 * * * = * * 13 | #[2001:db8::]/32:ssh * * * = * * 14 | #6161 = = = =/24 = = 15 | #* stream tcp * = = = 16 | -------------------------------------------------------------------------------- /port/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | # Uncomment this to turn on verbose mode. 4 | # export DH_VERBOSE=1 5 | 6 | # This has to be exported to make some magic below work. 7 | export DH_OPTIONS 8 | 9 | %: 10 | dh $@ --sourcedirectory=port --with quilt 11 | 12 | # https://lintian.debian.org/tags/non-empty-dependency_libs-in-la-file.html 13 | override_dh_auto_install: 14 | dh_auto_install 15 | sed -i "/dependency_libs/ s/'.*'/''/" `find . -name '*.la'` 16 | -------------------------------------------------------------------------------- /bin/Makefile: -------------------------------------------------------------------------------- 1 | # $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:52 christos Exp $ 2 | 3 | BINDIR=/sbin 4 | 5 | PROGS=blocklistd blocklistctl 6 | MAN.blocklistd=blocklistd.8 blocklistd.conf.5 7 | MAN.blocklistctl=blocklistctl.8 8 | SRCS.blocklistd = blocklistd.c conf.c run.c state.c support.c internal.c 9 | SRCS.blocklistctl = blocklistctl.c conf.c state.c support.c internal.c 10 | DBG=-g 11 | 12 | LDADD+=-lutil 13 | DPADD+=${LIBUTIL} 14 | 15 | .include 16 | -------------------------------------------------------------------------------- /lib/Makefile: -------------------------------------------------------------------------------- 1 | # $NetBSD: Makefile,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ 2 | 3 | .include 4 | 5 | USE_SHLIBDIR= yes 6 | 7 | CPPFLAGS+=-D_REENTRANT 8 | #LIBDPLIBS+=pthread ${NETBSDSRCDIR}/lib/libpthread 9 | LIB=blocklist 10 | SRCS=bl.c blocklist.c 11 | MAN=libblocklist.3 12 | MLINKS+=libblocklist.3 blocklist_open.3 13 | MLINKS+=libblocklist.3 blocklist_close.3 14 | MLINKS+=libblocklist.3 blocklist.3 15 | MLINKS+=libblocklist.3 blocklist_r.3 16 | MLINKS+=libblocklist.3 blocklist_sa.3 17 | MLINKS+=libblocklist.3 blocklist_sa_r.3 18 | 19 | .include 20 | -------------------------------------------------------------------------------- /port/debian/control: -------------------------------------------------------------------------------- 1 | Source: blocklist 2 | Section: net 3 | Priority: optional 4 | Maintainer: Christos Zoulas 5 | Standards-Version: 4.4.1 6 | Build-Depends: debhelper (>= 10~), 7 | dh-exec, 8 | dpkg-dev (>= 1.16.1~), 9 | libdb-dev, 10 | quilt 11 | 12 | Package: blocklist 13 | Architecture: any 14 | Homepage: https://github.com/zoulasc/blocklist 15 | Depends: ${misc:Depends}, 16 | ${shlibs:Depends}, 17 | libdb5.3 18 | Description: This package contains library that can be used 19 | by network daemons to communicate with a packet filter via 20 | a daemon to enforce opening and closing ports dynamically 21 | based on policy. 22 | -------------------------------------------------------------------------------- /etc/rc.d/blocklistd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # $NetBSD: blocklistd,v 1.2 2021/03/07 00:46:39 christos Exp $ 4 | # 5 | 6 | # PROVIDE: blocklistd 7 | # REQUIRE: npf pf ipfilter 8 | # BEFORE: SERVERS 9 | 10 | $_rc_subr_loaded . /etc/rc.subr 11 | 12 | name="blocklistd" 13 | rcvar=$name 14 | command="/sbin/${name}" 15 | pidfile="/var/run/${name}.pid" 16 | required_files="/etc/${name}.conf" 17 | start_precmd="${name}_precmd" 18 | extra_commands="reload" 19 | 20 | _sockfile="/var/run/${name}.sockets" 21 | _sockname="blocklistd.sock" 22 | 23 | blocklistd_precmd() 24 | { 25 | # Create default list of blocklistd sockets to watch 26 | # 27 | ( umask 022 ; > $_sockfile ) 28 | 29 | # Find /etc/rc.d scripts with "chrootdir" rcorder(8) keyword, 30 | # and if $${app}_chrootdir is a directory, add appropriate 31 | # blocklistd socket to list of sockets to watch. 32 | # 33 | for _lr in $(rcorder -k chrootdir /etc/rc.d/*); do 34 | ( 35 | _l=${_lr##*/} 36 | load_rc_config ${_l} 37 | eval _ldir=\$${_l}_chrootdir 38 | if checkyesno $_l && [ -n "$_ldir" ]; then 39 | echo "${_ldir}/var/run/${_sockname}" >> $_sockfile 40 | fi 41 | ) 42 | done 43 | 44 | # If other sockets have been provided, change run_rc_command()'s 45 | # internal copy of $blocklistd_flags to force use of specific 46 | # blocklistd sockets. 47 | # 48 | if [ -s $_sockfile ]; then 49 | echo "/var/run/${_sockname}" >> $_sockfile 50 | rc_flags="-P $_sockfile $rc_flags" 51 | fi 52 | 53 | return 0 54 | } 55 | 56 | load_rc_config $name 57 | run_rc_command "$1" 58 | -------------------------------------------------------------------------------- /port/Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | ACLOCAL_AMFLAGS = -I m4 3 | lib_LTLIBRARIES = libblocklist.la 4 | include_HEADERS = $(srcdir)/../include/blocklist.h 5 | 6 | exampledir = $(datarootdir)/examples 7 | example_DATA = $(srcdir)/../etc/blocklistd.conf $(srcdir)/../etc/npf.conf $(srcdir)/../etc/ipf.conf 8 | 9 | sbin_PROGRAMS = blocklistd blocklistctl 10 | noinst_PROGRAMS = srvtest cltest 11 | libexec_SCRIPTS = $(srcdir)/../libexec/blocklistd-helper 12 | 13 | man5_MANS = $(srcdir)/../bin/blocklistd.conf.5 14 | man8_MANS = $(srcdir)/../bin/blocklistd.8 $(srcdir)/../bin/blocklistctl.8 15 | 16 | VPATH = $(srcdir)/../port:$(srcdir)/../bin:$(srcdir)/../lib:$(srcdir)/../test:$(srcdir)/../include 17 | 18 | AM_CPPFLAGS = -I$(srcdir)/../include -DDOT="." 19 | AM_CPPFLAGS += -D_PATH_BLCONF=\"$(sysconfdir)/blocklistd.conf\" 20 | AM_CPPFLAGS += -D_PATH_BLCONTROL=\"$(libexecdir)/blocklistd-helper\" 21 | AM_CPPFLAGS += -D_PATH_BLSOCK=\"$(runstatedir)/blocklistd.sock\" 22 | AM_CPPFLAGS += -D_PATH_BLSTATE=\"$(localstatedir)/db/blocklistd.db\" 23 | AM_CPPFLAGS += -std=c99 -D_POSIX_C_SOURCE=200809L -D__EXTENSIONS__ 24 | AM_CPPFLAGS += -D__BSD_VISIBLE=1 25 | AM_CFLAGS = @WARNINGS@ 26 | 27 | libblocklist_la_SOURCES = bl.c blocklist.c 28 | libblocklist_la_LDFLAGS = -no-undefined -version-info 0:0:0 29 | libblocklist_la_LIBADD = $(LTLIBOBJS) 30 | 31 | SRCS = internal.c support.c run.c conf.c state.c 32 | blocklistd_SOURCES = blocklistd.c ${SRCS} 33 | blocklistd_LDADD = libblocklist.la 34 | blocklistctl_SOURCES = blocklistctl.c ${SRCS} 35 | blocklistctl_LDADD = libblocklist.la 36 | srvtest_SOURCES = srvtest.c ${SRCS} 37 | srvtest_LDADD = libblocklist.la 38 | cltest_SOURCES = cltest.c ${SRCS} 39 | cltest_LDADD = libblocklist.la 40 | -------------------------------------------------------------------------------- /bin/run.h: -------------------------------------------------------------------------------- 1 | /* $NetBSD: run.h,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifndef _RUN_H 32 | #define _RUN_H 33 | 34 | __BEGIN_DECLS 35 | struct conf; 36 | void run_flush(const struct conf *); 37 | struct sockaddr_storage; 38 | int run_change(const char *, const struct conf *, char *, size_t); 39 | __END_DECLS 40 | 41 | #endif /* _RUN_H */ 42 | -------------------------------------------------------------------------------- /port/debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: blocklist 3 | Upstream-Contact: christos@zoulas.com 4 | Source: https://github.com/zoulasc/blocklist 5 | Comment: 6 | This package contains library that can be used by network daemons to 7 | communicate with a packet filter via a daemon to enforce opening and 8 | closing ports dynamically based on policy. 9 | 10 | Files: * 11 | Copyright: 2020 Christos Zoulas 12 | License: NetBSD 13 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 14 | * All rights reserved. 15 | * 16 | * This code is derived from software contributed to The NetBSD Foundation 17 | * by Christos Zoulas. 18 | * 19 | * Redistribution and use in source and binary forms, with or without 20 | * modification, are permitted provided that the following conditions 21 | * are met: 22 | * 1. Redistributions of source code must retain the above copyright 23 | * notice, this list of conditions and the following disclaimer. 24 | * 2. Redistributions in binary form must reproduce the above copyright 25 | * notice, this list of conditions and the following disclaimer in the 26 | * documentation and/or other materials provided with the distribution. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 | * POSSIBILITY OF SUCH DAMAGE. 39 | -------------------------------------------------------------------------------- /etc/ipf.conf: -------------------------------------------------------------------------------- 1 | #======================================== 2 | # 3 | # subsection for abuse blocking 4 | # 5 | #======================================== 6 | # 7 | # This section should be included early in the main /etc/ipf.conf file, right 8 | # after any basic generic accounting ("count") rules, and any cleanup rules to 9 | # block invalid fragments, invalid options (e.g. "ssrr"), etc. 10 | # 11 | # Note these will not actually block anything since they don't include the 12 | # "quick" flag, and are thus part of a last-match group. They simply set up a 13 | # group such that any connection logging rule further below won't also match if 14 | # one of the rules in the group matches, no matter when or where the subsequent 15 | # matching rule is added. I.e. all rules in the group are checked for a match 16 | # (and a possible "first match" with "quick") before any subsequent rules 17 | # further below are used. Note group rules can be added at any time, including 18 | # at runtime after all other rules have been added -- they will still belong to 19 | # the group and once added will be checked as part of the group. 20 | # 21 | # head of "blocklistd" group: 22 | # 23 | # The "blocklistd" group will be used by blocklistd(8). 24 | # 25 | block in proto tcp/udp from any to any head blocklistd 26 | # 27 | # head of "attackers" group to block all attackers: 28 | # 29 | # The "attackers" group is intended to be used for manually maintained rules 30 | # e.g. as could be added like this: 31 | # 32 | # 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 33 | # /etc/rc.d/ipfliter reload 34 | # 35 | # Note the choice in this example is to return RST packets for blocked SYN 36 | # packets to help the other end close. This is not necessary, but it better 37 | # mimics what the kernel does by default, thus perhaps hiding the fact a 38 | # firewall is present. 39 | # 40 | # XXX This example still allows UDP services, but we would need to duplicate 41 | # each rule with "proto udp" (and without "flags blah") due to IPF parsing 42 | # limitations.... 43 | # 44 | block in proto tcp/udp from any to any head attackers 45 | # 46 | -------------------------------------------------------------------------------- /bin/support.h: -------------------------------------------------------------------------------- 1 | /* $NetBSD: support.h,v 1.2 2024/08/02 17:11:55 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifndef _SUPPORT_H 32 | #define _SUPPORT_H 33 | 34 | __BEGIN_DECLS 35 | const char *fmttime(char *, size_t, time_t); 36 | const char *fmtydhms(char *, size_t, time_t); 37 | struct syslog_data; 38 | void vdlog(int, struct syslog_data *, const char *, va_list) 39 | __attribute__((__format__(__printf__, 3, 0))); 40 | void dlog(int, const char *, ...) 41 | __attribute__((__format__(__printf__, 2, 3))); 42 | ssize_t blhexdump(char *, size_t, const char *, const void *, size_t); 43 | __END_DECLS 44 | 45 | #endif /* _SUPPORT_H */ 46 | -------------------------------------------------------------------------------- /bin/internal.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: internal.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifdef HAVE_CONFIG_H 32 | #include "config.h" 33 | #endif 34 | 35 | #ifdef HAVE_SYS_CDEFS_H 36 | #include 37 | #endif 38 | __RCSID("$NetBSD: internal.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); 39 | 40 | #include 41 | #include 42 | #include "conf.h" 43 | #include "internal.h" 44 | 45 | int debug; 46 | const char *rulename = "blocklistd"; 47 | const char *controlprog = _PATH_BLCONTROL; 48 | struct confset lconf, rconf; 49 | struct ifaddrs *ifas; 50 | void (*lfun)(int, const char *, ...) = syslog; 51 | -------------------------------------------------------------------------------- /bin/internal.h: -------------------------------------------------------------------------------- 1 | /* $NetBSD: internal.h,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifndef _INTERNAL_H 32 | #define _INTERNAL_H 33 | 34 | #ifndef _PATH_BLCONF 35 | #define _PATH_BLCONF "/etc/blocklistd.conf" 36 | #endif 37 | #ifndef _PATH_BLCONTROL 38 | #define _PATH_BLCONTROL "/libexec/blocklistd-helper" 39 | #endif 40 | #ifndef _PATH_BLSTATE 41 | #define _PATH_BLSTATE "/var/db/blocklistd.db" 42 | #endif 43 | 44 | extern struct confset rconf, lconf; 45 | extern int debug; 46 | extern const char *rulename; 47 | extern const char *controlprog; 48 | extern struct ifaddrs *ifas; 49 | 50 | #if !defined(__syslog_attribute__) && !defined(__syslog__) 51 | #define __syslog__ __printf__ 52 | #endif 53 | 54 | extern void (*lfun)(int, const char *, ...) 55 | __attribute__((__format__(__syslog__, 2, 3))); 56 | 57 | #endif /* _INTERNAL_H */ 58 | -------------------------------------------------------------------------------- /bin/state.h: -------------------------------------------------------------------------------- 1 | /* $NetBSD: state.h,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifndef _STATE_H 32 | #define _STATE_H 33 | 34 | #ifdef HAVE_DB_185_H 35 | #include 36 | #elif HAVE_DB_H 37 | #include 38 | #else 39 | #error "no db.h" 40 | #endif 41 | #include 42 | 43 | struct dbinfo { 44 | int count; 45 | time_t last; 46 | char id[64]; 47 | }; 48 | 49 | __BEGIN_DECLS 50 | struct sockaddr_storage; 51 | struct conf; 52 | 53 | DB *state_open(const char *, int, mode_t); 54 | int state_close(DB *); 55 | int state_get(DB *, const struct conf *, struct dbinfo *); 56 | int state_put(DB *, const struct conf *, const struct dbinfo *); 57 | int state_del(DB *, const struct conf *); 58 | int state_iterate(DB *, struct conf *, struct dbinfo *, unsigned int); 59 | int state_sync(DB *); 60 | __END_DECLS 61 | 62 | #endif /* _STATE_H */ 63 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | # $NetBSD: TODO,v 1.3 2025/02/05 20:22:26 christos Exp $ 2 | 3 | - don't poll periodically, find the next timeout 4 | - use the socket also for commands? Or separate socket? 5 | - add functionality to the control program. Should it change the database 6 | directly, or talk to the daemon to have it do it? 7 | - perhaps handle interfaces too instead of addresses for dynamic ip? 8 | ? What to do with multiple addresses? 9 | - perhaps rate limit against DoS 10 | - perhaps instead of scanning the list have a sparse map by port? 11 | - do we want to use libnpf directly for efficiency? 12 | - add more daemons ftpd? 13 | - do we care about the db state becoming too large? 14 | - instead of a yes = bump one, no = return to 0 interface, do we want 15 | to have something more flexible like? 16 | +n 17 | -n 18 | block 19 | unblock 20 | - do we need an api in blocklistctl to perform maintenance 21 | - fix the blocklistctl output to be more user friendly 22 | 23 | - figure out some way to do distributed operation securely (perhaps with 24 | a helper daemon that authenticates local sockets and then communicates 25 | local DB changes to the central server over a secure channel -- 26 | perhaps blocklistd-helper can have a back-end that can send updates to 27 | a central server) 28 | 29 | - add "blocklistd -l" to enable filter logging on all rules by default 30 | 31 | - add some new options in the config file 32 | 33 | "/all" - block both TCP and UDP (on the proto field?) 34 | 35 | "/log" - enable filter logging (if not the default) (on the name field?) 36 | "/nolog"- disable filter logging (if not the default) (on the name field?) 37 | 38 | The latter two probably require a new parameter for blocklistd-helper. 39 | 40 | - "blocklistd -f" should (also?) be a blocklistctl function!?!?! 41 | 42 | - if blocklistd was started with '-r' then a SIGHUP should also do a 43 | "control flush $rulename" and then re-add all the filter rules? 44 | 45 | - should/could /etc/rc.conf.d/ipfilter be created with the following? 46 | 47 | reload_postcmd=blocklistd_reload 48 | start_postcmd=blocklistd_start 49 | stop_precmd=blocklistd_stop 50 | blocklistd_reload () 51 | { 52 | /etc/rc.d/blocklistd reload # IFF SIGHUP does flush/re-add 53 | # /etc/rc.d/blocklistd restart 54 | } 55 | blocklistd_stop () 56 | { 57 | /etc/rc.d/blocklistd stop 58 | } 59 | blocklistd_start () 60 | { 61 | /etc/rc.d/blocklistd start 62 | } 63 | 64 | or is there a better way? 65 | -------------------------------------------------------------------------------- /bin/conf.h: -------------------------------------------------------------------------------- 1 | /* $NetBSD: conf.h,v 1.2 2025/02/05 20:09:33 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifndef _CONF_H 32 | #define _CONF_H 33 | 34 | #include 35 | 36 | struct conf { 37 | size_t c_lineno; 38 | struct sockaddr_storage c_ss; 39 | int c_lmask; 40 | int c_port; 41 | int c_proto; 42 | int c_family; 43 | int c_uid; 44 | int c_nfail; 45 | char c_name[128]; 46 | int c_rmask; 47 | int c_duration; 48 | }; 49 | 50 | struct confset { 51 | struct conf *cs_c; 52 | size_t cs_n; 53 | size_t cs_m; 54 | }; 55 | 56 | #define CONFNAMESZ sizeof(((struct conf *)0)->c_name) 57 | 58 | __BEGIN_DECLS 59 | const char *conf_print(char *, size_t, const char *, const char *, 60 | const struct conf *); 61 | void conf_parse(const char *); 62 | const struct conf *conf_find(int, uid_t, const struct sockaddr_storage *, 63 | struct conf *); 64 | __END_DECLS 65 | 66 | #endif /* _CONF_H */ 67 | -------------------------------------------------------------------------------- /port/strtoi.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: strtoi.c,v 1.2 2025/02/11 17:48:31 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2005 The DragonFly Project. All rights reserved. 5 | * Copyright (c) 2003 Citrus Project, 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * Created by Kamil Rytarowski, based on ID: 30 | * NetBSD: src/common/lib/libc/stdlib/strtoul.c,v 1.3 2008/08/20 19:58:34 oster Exp 31 | */ 32 | #ifdef HAVE_CONFIG_H 33 | #include "config.h" 34 | #endif 35 | 36 | #ifdef HAVE_SYS_CDEFS_H 37 | #include 38 | #endif 39 | __RCSID("$NetBSD: strtoi.c,v 1.2 2025/02/11 17:48:31 christos Exp $"); 40 | 41 | #if defined(_KERNEL) 42 | #include 43 | #include 44 | #include 45 | #elif defined(_STANDALONE) 46 | #include 47 | #include 48 | #include 49 | #include 50 | #else 51 | #include 52 | #include 53 | #include 54 | #include 55 | #endif 56 | 57 | #define _FUNCNAME strtoi 58 | #define __TYPE intmax_t 59 | #define __WRAPPED strtoimax 60 | 61 | #if !HAVE_STRTOI 62 | #include "_strtoi.h" 63 | #endif 64 | -------------------------------------------------------------------------------- /port/strlcpy.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: strlcpy.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ 2 | /* $OpenBSD: strlcpy.c,v 1.7 2003/04/12 21:56:39 millert Exp $ */ 3 | 4 | /* 5 | * Copyright (c) 1998 Todd C. Miller 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL 12 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 13 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE 14 | * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #if !defined(_KERNEL) && !defined(_STANDALONE) 21 | #if HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #ifdef HAVE_SYS_CDEFS_H 26 | #include 27 | #endif 28 | 29 | #if defined(LIBC_SCCS) && !defined(lint) 30 | __RCSID("$NetBSD: strlcpy.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); 31 | #endif /* LIBC_SCCS and not lint */ 32 | 33 | #ifdef _LIBC 34 | #include "namespace.h" 35 | #endif 36 | #include 37 | #include 38 | #include 39 | 40 | #ifdef _LIBC 41 | # ifdef __weak_alias 42 | __weak_alias(strlcpy, _strlcpy) 43 | # endif 44 | #endif 45 | #else 46 | #include 47 | #endif /* !_KERNEL && !_STANDALONE */ 48 | 49 | 50 | #if !HAVE_STRLCPY 51 | /* 52 | * Copy src to string dst of size siz. At most siz-1 characters 53 | * will be copied. Always NUL terminates (unless siz == 0). 54 | * Returns strlen(src); if retval >= siz, truncation occurred. 55 | */ 56 | size_t 57 | strlcpy(char *dst, const char *src, size_t siz) 58 | { 59 | char *d = dst; 60 | const char *s = src; 61 | size_t n = siz; 62 | 63 | /* Copy as many bytes as will fit */ 64 | if (n != 0 && --n != 0) { 65 | do { 66 | if ((*d++ = *s++) == 0) 67 | break; 68 | } while (--n != 0); 69 | } 70 | 71 | /* Not enough room in dst, add NUL and traverse rest of src */ 72 | if (n == 0) { 73 | if (siz != 0) 74 | *d = '\0'; /* NUL-terminate dst */ 75 | while (*s++) 76 | ; 77 | } 78 | 79 | return(s - src - 1); /* count does not include NUL */ 80 | } 81 | #endif 82 | -------------------------------------------------------------------------------- /port/port.h: -------------------------------------------------------------------------------- 1 | #ifndef _GNU_SOURCE 2 | #define _GNU_SOURCE 3 | #endif 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifndef __unused 12 | #define __unused __attribute__((__unused__)) 13 | #endif 14 | 15 | #ifndef __dead 16 | #define __dead __attribute__((__noreturn__)) 17 | #endif 18 | 19 | #ifndef __BEGIN_DECLS 20 | #define __BEGIN_DECLS 21 | #endif 22 | 23 | #ifndef __END_DECLS 24 | #define __END_DECLS 25 | #endif 26 | 27 | #ifndef MIN 28 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) 29 | #endif 30 | 31 | #ifndef MAX 32 | #define MAX(a,b) ((a) > (b) ? (a) : (b)) 33 | #endif 34 | 35 | #ifndef __RCSID 36 | #define __RCSID(a) 37 | #endif 38 | 39 | #ifndef __UNCONST 40 | #define __UNCONST(a) ((void *)(intptr_t)(a)) 41 | #endif 42 | 43 | #ifndef __arraycount 44 | #define __arraycount(a) (sizeof(a) / sizeof(a[0])) 45 | #endif 46 | 47 | #ifndef __STRING 48 | #define __STRING(x) #x 49 | #endif 50 | 51 | #ifndef HAVE_STRLCPY 52 | size_t strlcpy(char *, const char *, size_t); 53 | #endif 54 | 55 | #ifndef HAVE_STRLCAT 56 | size_t strlcat(char *, const char *, size_t); 57 | #endif 58 | 59 | #ifndef HAVE_POPENVE 60 | FILE *popenve(const char *, char *const *, char *const *, const char *); 61 | int pcloseve(FILE *); 62 | #define pclose(a) pcloseve(a); 63 | #endif 64 | 65 | #ifndef HAVE_SOCKADDR_SNPRINTF 66 | struct sockaddr; 67 | int sockaddr_snprintf(char *, size_t, const char *, const struct sockaddr *); 68 | #endif 69 | 70 | #ifndef HAVE_STRTOI 71 | intmax_t strtoi(const char *, char **, int, intmax_t, intmax_t, int *); 72 | #endif 73 | 74 | #ifndef HAVE_GETPROGNAME 75 | const char *getprogname(void); 76 | void setprogname(char *); 77 | #endif 78 | 79 | #ifndef HAVE_PIDFILE 80 | int pidfile(const char *); 81 | #endif 82 | 83 | #ifndef HAVE_FPARSELN 84 | #define FPARSELN_UNESCALL 0xf 85 | #define FPARSELN_UNESCCOMM 0x1 86 | #define FPARSELN_UNESCCONT 0x2 87 | #define FPARSELN_UNESCESC 0x4 88 | #define FPARSELN_UNESCREST 0x8 89 | char *fparseln(FILE *, size_t *, size_t *, const char delim[3], int); 90 | #endif 91 | 92 | #ifndef HAVE_FGETLN 93 | char *fgetln(FILE *, size_t *); 94 | #endif 95 | 96 | #ifndef HAVE_CLOCK_GETTIME 97 | struct timespec; 98 | int clock_gettime(int, struct timespec *); 99 | #define CLOCK_REALTIME 0 100 | #endif 101 | 102 | #ifndef HAVE_VSYSLOG_R 103 | #define SYSLOG_DATA_INIT { 0 } 104 | struct syslog_data { 105 | int dummy; 106 | }; 107 | void vsyslog_r(int, struct syslog_data *, const char *, va_list); 108 | #endif 109 | -------------------------------------------------------------------------------- /include/blocklist.h: -------------------------------------------------------------------------------- 1 | /* $NetBSD: blocklist.h,v 1.4 2025/02/11 17:42:17 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifndef _BLOCKLIST_H 32 | #define _BLOCKLIST_H 33 | 34 | #include 35 | #include 36 | 37 | #if defined(__cplusplus) 38 | extern "C" { 39 | #endif 40 | 41 | struct syslog_data; 42 | struct blocklist *blocklist_open(void); 43 | struct blocklist *blocklist_open2( 44 | void (*)(int, struct syslog_data *, const char *, va_list)); 45 | void blocklist_close(struct blocklist *); 46 | int blocklist(int, int, const char *); 47 | int blocklist_r(struct blocklist *, int, int, const char *); 48 | int blocklist_sa(int, int, const struct sockaddr *, socklen_t, const char *); 49 | int blocklist_sa_r(struct blocklist *, int, int, 50 | const struct sockaddr *, socklen_t, const char *); 51 | 52 | #if defined(__cplusplus) 53 | } 54 | #endif 55 | 56 | /* action values for user applications */ 57 | #define BLOCKLIST_API_ENUM 1 58 | enum { 59 | BLOCKLIST_AUTH_OK = 0, 60 | BLOCKLIST_AUTH_FAIL, 61 | BLOCKLIST_ABUSIVE_BEHAVIOR, 62 | BLOCKLIST_BAD_USER 63 | }; 64 | 65 | #endif /* _BLOCKLIST_H */ 66 | -------------------------------------------------------------------------------- /include/bl.h: -------------------------------------------------------------------------------- 1 | /* $NetBSD: bl.h,v 1.2 2024/08/02 17:11:55 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifndef _BL_H 32 | #define _BL_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include "blocklist.h" 39 | 40 | typedef enum { 41 | BL_INVALID, 42 | BL_ADD, 43 | BL_DELETE, 44 | BL_ABUSE, 45 | BL_BADUSER 46 | } bl_type_t; 47 | 48 | typedef struct { 49 | bl_type_t bi_type; 50 | int bi_fd; 51 | uid_t bi_uid; 52 | gid_t bi_gid; 53 | socklen_t bi_slen; 54 | struct sockaddr_storage bi_ss; 55 | char bi_msg[1024]; 56 | } bl_info_t; 57 | 58 | #define bi_cred bi_u._bi_cred 59 | 60 | #ifndef _PATH_BLSOCK 61 | #define _PATH_BLSOCK "/var/run/blocklistd.sock" 62 | #endif 63 | 64 | __BEGIN_DECLS 65 | 66 | typedef struct blocklist *bl_t; 67 | 68 | bl_t bl_create(bool, const char *, 69 | void (*)(int, struct syslog_data *, const char *, va_list)); 70 | void bl_destroy(bl_t); 71 | int bl_send(bl_t, bl_type_t, int, const struct sockaddr *, socklen_t, 72 | const char *); 73 | int bl_getfd(bl_t); 74 | bl_info_t *bl_recv(bl_t); 75 | bool bl_isconnected(bl_t); 76 | 77 | __END_DECLS 78 | 79 | #endif /* _BL_H */ 80 | -------------------------------------------------------------------------------- /diff/ftpd.diff: -------------------------------------------------------------------------------- 1 | --- /dev/null 2015-01-23 17:30:40.000000000 -0500 2 | +++ pfilter.c 2015-01-23 17:12:02.000000000 -0500 3 | @@ -0,0 +1,24 @@ 4 | +#include 5 | +#include 6 | + 7 | +#include "pfilter.h" 8 | + 9 | +static struct blocklist *blstate; 10 | + 11 | +void 12 | +pfilter_open(void) 13 | +{ 14 | + if (blstate == NULL) 15 | + blstate = blocklist_open(); 16 | +} 17 | + 18 | +void 19 | +pfilter_notify(int what, const char *msg) 20 | +{ 21 | + pfilter_open(); 22 | + 23 | + if (blstate == NULL) 24 | + return; 25 | + 26 | + blocklist_r(blstate, what, 0, msg); 27 | +} 28 | --- /dev/null 2015-01-23 17:30:40.000000000 -0500 29 | +++ pfilter.h 2015-01-23 17:07:25.000000000 -0500 30 | @@ -0,0 +1,2 @@ 31 | +void pfilter_open(void); 32 | +void pfilter_notify(int, const char *); 33 | Index: Makefile 34 | =================================================================== 35 | RCS file: /cvsroot/src/libexec/ftpd/Makefile,v 36 | retrieving revision 1.63 37 | diff -u -p -u -r1.63 Makefile 38 | --- Makefile 14 Aug 2011 11:46:28 -0000 1.63 39 | +++ Makefile 23 Jan 2015 22:32:20 -0000 40 | @@ -11,6 +11,10 @@ LDADD+= -lcrypt -lutil 41 | MAN= ftpd.conf.5 ftpusers.5 ftpd.8 42 | MLINKS= ftpusers.5 ftpchroot.5 43 | 44 | +SRCS+= pfilter.c 45 | +LDADD+= -lblocklist 46 | +DPADD+= ${LIBBLOCKLIST} 47 | + 48 | .if defined(NO_INTERNAL_LS) 49 | CPPFLAGS+=-DNO_INTERNAL_LS 50 | .else 51 | Index: ftpd.c 52 | =================================================================== 53 | RCS file: /cvsroot/src/libexec/ftpd/ftpd.c,v 54 | retrieving revision 1.200 55 | diff -u -p -u -r1.200 ftpd.c 56 | --- ftpd.c 31 Jul 2013 19:50:47 -0000 1.200 57 | +++ ftpd.c 23 Jan 2015 22:32:20 -0000 58 | @@ -165,6 +165,8 @@ __RCSID("$NetBSD: ftpd.c,v 1.200 2013/07 59 | #include 60 | #endif 61 | 62 | +#include "pfilter.h" 63 | + 64 | #define GLOBAL 65 | #include "extern.h" 66 | #include "pathnames.h" 67 | @@ -471,6 +473,8 @@ main(int argc, char *argv[]) 68 | if (EMPTYSTR(confdir)) 69 | confdir = _DEFAULT_CONFDIR; 70 | 71 | + pfilter_open(); 72 | + 73 | if (dowtmp) { 74 | #ifdef SUPPORT_UTMPX 75 | ftpd_initwtmpx(); 76 | @@ -1401,6 +1405,7 @@ do_pass(int pass_checked, int pass_rval, 77 | if (rval) { 78 | reply(530, "%s", rval == 2 ? "Password expired." : 79 | "Login incorrect."); 80 | + pfilter_notify(1, rval == 2 ? "exppass" : "badpass"); 81 | if (logging) { 82 | syslog(LOG_NOTICE, 83 | "FTP LOGIN FAILED FROM %s", remoteloghost); 84 | @@ -1444,6 +1449,7 @@ do_pass(int pass_checked, int pass_rval, 85 | *remote_ip = 0; 86 | remote_ip[sizeof(remote_ip) - 1] = 0; 87 | if (!auth_hostok(lc, remotehost, remote_ip)) { 88 | + pfilter_notify(1, "bannedhost"); 89 | syslog(LOG_INFO|LOG_AUTH, 90 | "FTP LOGIN FAILED (HOST) as %s: permission denied.", 91 | pw->pw_name); 92 | -------------------------------------------------------------------------------- /port/configure.ac: -------------------------------------------------------------------------------- 1 | dnl Process this file with autoconf to produce a configure script. 2 | AC_INIT([blocklistd],[0.1],[christos@netbsd.com]) 3 | AM_INIT_AUTOMAKE([subdir-objects foreign]) 4 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 5 | 6 | AC_CONFIG_HEADERS([config.h]) 7 | AC_CONFIG_MACRO_DIR([m4]) 8 | 9 | AC_SUBST(WARNINGS) 10 | AC_SUBST(LINK_NTOA) 11 | 12 | dnl Checks for programs. 13 | AC_PROG_CC 14 | AC_USE_SYSTEM_EXTENSIONS 15 | AM_PROG_CC_C_O 16 | AC_C_BIGENDIAN 17 | AC_PROG_INSTALL 18 | AC_PROG_LN_S 19 | LT_INIT([disable-static pic-only]) 20 | gl_VISIBILITY 21 | dnl Checks for headers 22 | AC_HEADER_MAJOR 23 | AC_HEADER_SYS_WAIT 24 | AC_CHECK_HEADERS(stdint.h fcntl.h stdint.h inttypes.h unistd.h) 25 | AC_CHECK_HEADERS(sys/un.h sys/socket.h limits.h) 26 | AC_CHECK_HEADERS(arpa/inet.h getopt.h err.h) 27 | AC_CHECK_HEADERS(sys/types.h util.h sys/time.h time.h) 28 | AC_CHECK_HEADERS(netatalk/at.h db.h db_185.h) 29 | AC_CHECK_HEADERS(sys/cdefs.h) 30 | AC_CHECK_LIB(rt, clock_gettime) 31 | AC_CHECK_LIB(db, __db185_open) 32 | AC_CHECK_LIB(util, pidfile) 33 | AC_CHECK_LIB(util, sockaddr_snprintf) 34 | AC_SEARCH_LIBS(__xnet_connect, socket) 35 | 36 | AH_BOTTOM([ 37 | #ifndef __NetBSD__ 38 | #include "port.h" 39 | #endif 40 | ]) 41 | 42 | dnl Checks for typedefs, structures, and compiler characteristics. 43 | AC_C_CONST 44 | AC_TYPE_OFF_T 45 | AC_TYPE_SIZE_T 46 | AC_SYS_LARGEFILE 47 | AC_CHECK_MEMBERS([struct sockaddr.sa_len], [], [], [#include ]) 48 | 49 | AC_TYPE_PID_T 50 | AC_TYPE_UINT8_T 51 | AC_TYPE_UINT16_T 52 | AC_TYPE_UINT32_T 53 | AC_TYPE_INT32_T 54 | AC_TYPE_UINT64_T 55 | AC_TYPE_INT64_T 56 | AC_TYPE_INTPTR_T 57 | AC_TYPE_UINTPTR_T 58 | 59 | AC_MSG_CHECKING(for gcc compiler warnings) 60 | AC_ARG_ENABLE(warnings, 61 | [ --disable-warnings disable compiler warnings], 62 | [if test "${enableval}" = no -o "$GCC" = no; then 63 | AC_MSG_RESULT(no) 64 | WARNINGS= 65 | else 66 | AC_MSG_RESULT(yes) 67 | WARNINGS="-Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith \ 68 | -Wmissing-declarations -Wredundant-decls -Wnested-externs \ 69 | -Wsign-compare -Wreturn-type -Wswitch -Wshadow \ 70 | -Wcast-qual -Wwrite-strings -Wextra -Wunused-parameter -Wformat=2" 71 | fi], [ 72 | if test "$GCC" = yes; then 73 | AC_MSG_RESULT(yes) 74 | WARNINGS="-Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith \ 75 | -Wmissing-declarations -Wredundant-decls -Wnested-externs \ 76 | -Wsign-compare -Wreturn-type -Wswitch -Wshadow \ 77 | -Wcast-qual -Wwrite-strings -Wextra -Wunused-parameter -Wformat=2" 78 | else 79 | WARNINGS= 80 | AC_MSG_RESULT(no) 81 | fi]) 82 | 83 | dnl Checks for functions 84 | AC_CHECK_FUNCS(strerror) 85 | 86 | dnl Provide implementation of some required functions if necessary 87 | AC_REPLACE_FUNCS(strtoi sockaddr_snprintf popenve clock_gettime strlcpy strlcat getprogname fparseln fgetln pidfile vsyslog_r) 88 | 89 | dnl See if we are cross-compiling 90 | AM_CONDITIONAL(IS_CROSS_COMPILE, test "$cross_compiling" = yes) 91 | 92 | AC_CONFIG_FILES([Makefile]) 93 | AC_OUTPUT 94 | -------------------------------------------------------------------------------- /port/strlcat.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: strlcat.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ 2 | /* $OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp $ */ 3 | 4 | /* 5 | * Copyright (c) 1998 Todd C. Miller 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL 12 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 13 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE 14 | * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #if !defined(_KERNEL) && !defined(_STANDALONE) 21 | #if HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #ifdef HAVE_SYS_CDEFS_H 26 | #include 27 | #endif 28 | 29 | #if defined(LIBC_SCCS) && !defined(lint) 30 | __RCSID("$NetBSD: strlcat.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); 31 | #endif /* LIBC_SCCS and not lint */ 32 | 33 | #ifdef _LIBC 34 | #include "namespace.h" 35 | #endif 36 | #include 37 | #include 38 | #include 39 | 40 | #ifdef _LIBC 41 | # ifdef __weak_alias 42 | __weak_alias(strlcat, _strlcat) 43 | # endif 44 | #endif 45 | 46 | #else 47 | #include 48 | #endif /* !_KERNEL && !_STANDALONE */ 49 | 50 | #if !HAVE_STRLCAT 51 | /* 52 | * Appends src to string dst of size siz (unlike strncat, siz is the 53 | * full size of dst, not space left). At most siz-1 characters 54 | * will be copied. Always NUL terminates (unless siz <= strlen(dst)). 55 | * Returns strlen(src) + MIN(siz, strlen(initial dst)). 56 | * If retval >= siz, truncation occurred. 57 | */ 58 | size_t 59 | strlcat(char *dst, const char *src, size_t siz) 60 | { 61 | #if 1 62 | char *d = dst; 63 | const char *s = src; 64 | size_t n = siz; 65 | size_t dlen; 66 | 67 | /* Find the end of dst and adjust bytes left but don't go past end */ 68 | while (n-- != 0 && *d != '\0') 69 | d++; 70 | dlen = d - dst; 71 | n = siz - dlen; 72 | 73 | if (n == 0) 74 | return(dlen + strlen(s)); 75 | while (*s != '\0') { 76 | if (n != 1) { 77 | *d++ = *s; 78 | n--; 79 | } 80 | s++; 81 | } 82 | *d = '\0'; 83 | 84 | return(dlen + (s - src)); /* count does not include NUL */ 85 | #else 86 | 87 | /* 88 | * Find length of string in dst (maxing out at siz). 89 | */ 90 | size_t dlen = strnlen(dst, siz); 91 | 92 | /* 93 | * Copy src into any remaining space in dst (truncating if needed). 94 | * Note strlcpy(dst, src, 0) returns strlen(src). 95 | */ 96 | return dlen + strlcpy(dst + dlen, src, siz - dlen); 97 | #endif 98 | } 99 | #endif 100 | -------------------------------------------------------------------------------- /port/_strtoi.h: -------------------------------------------------------------------------------- 1 | /* $NetBSD: _strtoi.h,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 1990, 1993 5 | * The Regents of the University of California. All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 3. Neither the name of the University nor the names of its contributors 16 | * may be used to endorse or promote products derived from this software 17 | * without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | * SUCH DAMAGE. 30 | * 31 | * Original version ID: 32 | * NetBSD: src/lib/libc/locale/_wcstoul.h,v 1.2 2003/08/07 16:43:03 agc Exp 33 | * 34 | * Created by Kamil Rytarowski, based on ID: 35 | * NetBSD: src/common/lib/libc/stdlib/_strtoul.h,v 1.7 2013/05/17 12:55:56 joerg Exp 36 | */ 37 | 38 | /* 39 | * function template for strtoi and strtou 40 | * 41 | * parameters: 42 | * _FUNCNAME : function name 43 | * __TYPE : return and range limits type 44 | * __WRAPPED : wrapped function, strtoimax or strtoumax 45 | */ 46 | 47 | __TYPE 48 | _FUNCNAME(const char * __restrict nptr, char ** __restrict endptr, int base, 49 | __TYPE lo, __TYPE hi, int * rstatus) 50 | { 51 | int serrno; 52 | __TYPE im; 53 | char *ep; 54 | int rep; 55 | 56 | /* endptr may be NULL */ 57 | 58 | if (endptr == NULL) 59 | endptr = &ep; 60 | 61 | if (rstatus == NULL) 62 | rstatus = &rep; 63 | 64 | serrno = errno; 65 | errno = 0; 66 | 67 | im = __WRAPPED(nptr, endptr, base); 68 | 69 | *rstatus = errno; 70 | errno = serrno; 71 | 72 | if (*rstatus == 0) { 73 | /* No digits were found */ 74 | if (nptr == *endptr) 75 | *rstatus = ECANCELED; 76 | /* There are further characters after number */ 77 | else if (**endptr != '\0') 78 | *rstatus = ENOTSUP; 79 | } 80 | 81 | if (im < lo) { 82 | if (*rstatus == 0) 83 | *rstatus = ERANGE; 84 | return lo; 85 | } 86 | if (im > hi) { 87 | if (*rstatus == 0) 88 | *rstatus = ERANGE; 89 | return hi; 90 | } 91 | 92 | return im; 93 | } 94 | -------------------------------------------------------------------------------- /port/fgetln.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: fgetln.c,v 1.1.1.1 2020/06/15 01:52:54 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #ifdef HAVE_CONFIG_H 33 | #include "config.h" 34 | #endif 35 | 36 | #if !HAVE_FGETLN 37 | #include 38 | #ifndef HAVE_NBTOOL_CONFIG_H 39 | /* These headers are required, but included from nbtool_config.h */ 40 | #include 41 | #include 42 | #include 43 | #include 44 | #endif 45 | 46 | char * 47 | fgetln(FILE *fp, size_t *len) 48 | { 49 | static char *buf = NULL; 50 | static size_t bufsiz = 0; 51 | char *ptr; 52 | 53 | 54 | if (buf == NULL) { 55 | bufsiz = BUFSIZ; 56 | if ((buf = malloc(bufsiz)) == NULL) 57 | return NULL; 58 | } 59 | 60 | if (fgets(buf, bufsiz, fp) == NULL) 61 | return NULL; 62 | 63 | *len = 0; 64 | while ((ptr = strchr(&buf[*len], '\n')) == NULL) { 65 | size_t nbufsiz = bufsiz + BUFSIZ; 66 | char *nbuf = realloc(buf, nbufsiz); 67 | 68 | if (nbuf == NULL) { 69 | int oerrno = errno; 70 | free(buf); 71 | errno = oerrno; 72 | buf = NULL; 73 | return NULL; 74 | } else 75 | buf = nbuf; 76 | 77 | if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL) { 78 | buf[bufsiz] = '\0'; 79 | *len = strlen(buf); 80 | return buf; 81 | } 82 | 83 | *len = bufsiz; 84 | bufsiz = nbufsiz; 85 | } 86 | 87 | *len = (ptr - buf) + 1; 88 | return buf; 89 | } 90 | 91 | #endif 92 | 93 | #ifdef TEST 94 | int 95 | main(int argc, char *argv[]) 96 | { 97 | char *p; 98 | size_t len; 99 | 100 | while ((p = fgetln(stdin, &len)) != NULL) { 101 | (void)printf("%zu %s", len, p); 102 | free(p); 103 | } 104 | return 0; 105 | } 106 | #endif 107 | -------------------------------------------------------------------------------- /diff/proftpd.diff: -------------------------------------------------------------------------------- 1 | --- Make.rules.in.orig 2015-05-27 20:25:54.000000000 -0400 2 | +++ Make.rules.in 2016-01-25 21:48:47.000000000 -0500 3 | @@ -110,3 +110,8 @@ 4 | 5 | FTPWHO_OBJS=ftpwho.o scoreboard.o misc.o 6 | BUILD_FTPWHO_OBJS=utils/ftpwho.o utils/scoreboard.o utils/misc.o 7 | + 8 | +CPPFLAGS+=-DHAVE_BLOCKLIST 9 | +LIBS+=-lblocklist 10 | +OBJS+= pfilter.o 11 | +BUILD_OBJS+= src/pfilter.o 12 | --- /dev/null 2016-01-22 17:30:55.000000000 -0500 13 | +++ include/pfilter.h 2016-01-22 16:18:33.000000000 -0500 14 | @@ -0,0 +1,3 @@ 15 | + 16 | +void pfilter_notify(int); 17 | +void pfilter_init(void); 18 | --- modules/mod_auth.c.orig 2015-05-27 20:25:54.000000000 -0400 19 | +++ modules/mod_auth.c 2016-01-22 16:21:06.000000000 -0500 20 | @@ -30,6 +30,7 @@ 21 | 22 | #include "conf.h" 23 | #include "privs.h" 24 | +#include "pfilter.h" 25 | 26 | extern pid_t mpid; 27 | 28 | @@ -84,6 +85,8 @@ 29 | _("Login timeout (%d %s): closing control connection"), TimeoutLogin, 30 | TimeoutLogin != 1 ? "seconds" : "second"); 31 | 32 | + pfilter_notify(1); 33 | + 34 | /* It's possible that any listeners of this event might terminate the 35 | * session process themselves (e.g. mod_ban). So write out that the 36 | * TimeoutLogin has been exceeded to the log here, in addition to the 37 | @@ -913,6 +916,7 @@ 38 | pr_memscrub(pass, strlen(pass)); 39 | } 40 | 41 | + pfilter_notify(1); 42 | pr_log_auth(PR_LOG_NOTICE, "SECURITY VIOLATION: Root login attempted"); 43 | return 0; 44 | } 45 | @@ -1726,6 +1730,7 @@ 46 | return 1; 47 | 48 | auth_failure: 49 | + pfilter_notify(1); 50 | if (pass) 51 | pr_memscrub(pass, strlen(pass)); 52 | session.user = session.group = NULL; 53 | --- src/main.c.orig 2016-01-22 17:36:43.000000000 -0500 54 | +++ src/main.c 2016-01-22 17:37:58.000000000 -0500 55 | @@ -49,6 +49,7 @@ 56 | #endif 57 | 58 | #include "privs.h" 59 | +#include "pfilter.h" 60 | 61 | int (*cmd_auth_chk)(cmd_rec *); 62 | void (*cmd_handler)(server_rec *, conn_t *); 63 | @@ -1050,6 +1051,7 @@ 64 | pid_t pid; 65 | sigset_t sig_set; 66 | 67 | + pfilter_init(); 68 | if (!nofork) { 69 | 70 | /* A race condition exists on heavily loaded servers where the parent 71 | @@ -1169,7 +1171,8 @@ 72 | 73 | /* Reseed pseudo-randoms */ 74 | srand((unsigned int) (time(NULL) * getpid())); 75 | - 76 | +#else 77 | + pfilter_init(); 78 | #endif /* PR_DEVEL_NO_FORK */ 79 | 80 | /* Child is running here */ 81 | --- /dev/null 2016-01-22 17:30:55.000000000 -0500 82 | +++ src/pfilter.c 2016-01-22 16:37:55.000000000 -0500 83 | @@ -0,0 +1,41 @@ 84 | +#include "pfilter.h" 85 | +#include "conf.h" 86 | +#include "privs.h" 87 | +#ifdef HAVE_BLOCKLIST 88 | +#include 89 | +#endif 90 | + 91 | +static struct blocklist *blstate; 92 | + 93 | +void 94 | +pfilter_init(void) 95 | +{ 96 | +#ifdef HAVE_BLOCKLIST 97 | + if (blstate == NULL) 98 | + blstate = blocklist_open(); 99 | +#endif 100 | +} 101 | + 102 | +void 103 | +pfilter_notify(int a) 104 | +{ 105 | +#ifdef HAVE_BLOCKLIST 106 | + conn_t *c = session.c; 107 | + int fd; 108 | + 109 | + if (c == NULL) 110 | + return; 111 | + if (c->rfd != -1) 112 | + fd = c->rfd; 113 | + else if (c->wfd != -1) 114 | + fd = c->wfd; 115 | + else 116 | + return; 117 | + 118 | + if (blstate == NULL) 119 | + pfilter_init(); 120 | + if (blstate == NULL) 121 | + return; 122 | + (void)blocklist_r(blstate, a, fd, "proftpd"); 123 | +#endif 124 | +} 125 | -------------------------------------------------------------------------------- /diff/postfix.diff: -------------------------------------------------------------------------------- 1 | Index: dist/src/smtpd/pfilter.c 2 | =================================================================== 3 | RCS file: dist/src/smtpd/pfilter.c 4 | diff -N dist/src/smtpd/pfilter.c 5 | --- /dev/null 1 Jan 1970 00:00:00 -0000 6 | +++ dist/src/smtpd/pfilter.c 1 Feb 2018 03:29:09 -0000 7 | @@ -0,0 +1,19 @@ 8 | +#include "pfilter.h" 9 | +#include /* for NULL */ 10 | +#include 11 | + 12 | +static struct blocklist *blstate; 13 | + 14 | +void 15 | +pfilter_notify(int a, int fd) 16 | +{ 17 | + if (blstate == NULL) 18 | + blstate = blocklist_open(); 19 | + if (blstate == NULL) 20 | + return; 21 | + (void)blocklist_r(blstate, a, fd, "smtpd"); 22 | + if (a == 0) { 23 | + blocklist_close(blstate); 24 | + blstate = NULL; 25 | + } 26 | +} 27 | Index: dist/src/smtpd/pfilter.h 28 | =================================================================== 29 | RCS file: dist/src/smtpd/pfilter.h 30 | diff -N dist/src/smtpd/pfilter.h 31 | --- /dev/null 1 Jan 1970 00:00:00 -0000 32 | +++ dist/src/smtpd/pfilter.h 1 Feb 2018 03:29:09 -0000 33 | @@ -0,0 +1,2 @@ 34 | + 35 | +void pfilter_notify(int, int); 36 | Index: dist/src/smtpd/smtpd.c 37 | =================================================================== 38 | RCS file: /cvsroot/src/external/ibm-public/postfix/dist/src/smtpd/smtpd.c,v 39 | retrieving revision 1.14 40 | diff -u -r1.14 smtpd.c 41 | --- dist/src/smtpd/smtpd.c 14 Feb 2017 01:16:48 -0000 1.14 42 | +++ dist/src/smtpd/smtpd.c 1 Feb 2018 03:29:09 -0000 43 | @@ -1197,6 +1197,8 @@ 44 | #include 45 | #include 46 | 47 | +#include "pfilter.h" 48 | + 49 | /* 50 | * Tunable parameters. Make sure that there is some bound on the length of 51 | * an SMTP command, so that the mail system stays in control even when a 52 | @@ -5048,6 +5050,7 @@ 53 | if (state->error_count >= var_smtpd_hard_erlim) { 54 | state->reason = REASON_ERROR_LIMIT; 55 | state->error_mask |= MAIL_ERROR_PROTOCOL; 56 | + pfilter_notify(1, vstream_fileno(state->client)); 57 | smtpd_chat_reply(state, "421 4.7.0 %s Error: too many errors", 58 | var_myhostname); 59 | break; 60 | Index: libexec/smtpd/Makefile 61 | =================================================================== 62 | RCS file: /cvsroot/src/external/ibm-public/postfix/libexec/smtpd/Makefile,v 63 | retrieving revision 1.6 64 | diff -u -r1.6 Makefile 65 | --- libexec/smtpd/Makefile 21 May 2017 15:28:40 -0000 1.6 66 | +++ libexec/smtpd/Makefile 1 Feb 2018 03:29:09 -0000 67 | @@ -13,11 +13,14 @@ 68 | SRCS= smtpd.c smtpd_token.c smtpd_check.c smtpd_chat.c smtpd_state.c \ 69 | smtpd_peer.c smtpd_sasl_proto.c smtpd_sasl_glue.c smtpd_proxy.c \ 70 | smtpd_xforward.c smtpd_dsn_fix.c smtpd_milter.c smtpd_resolve.c \ 71 | - smtpd_expand.c smtpd_haproxy.c 72 | + smtpd_expand.c smtpd_haproxy.c pfilter.c 73 | 74 | DPADD+= ${LIBPMASTER} ${LIBPMILTER} ${LIBPGLOBAL} ${LIBPDNS} ${LIBPXSASL} 75 | LDADD+= ${LIBPMASTER} ${LIBPMILTER} ${LIBPGLOBAL} ${LIBPDNS} ${LIBPXSASL} 76 | 77 | +DPADD+= ${LIBBLOCKLIST} 78 | +LDADD+= -lblocklist 79 | + 80 | DPADD+= ${LIBPTLS} ${LIBSSL} ${LIBCRYPTO} 81 | LDADD+= ${LIBPTLS} -lssl -lcrypto 82 | 83 | Index: dist/src/smtpd/smtpd.c 84 | =================================================================== 85 | RCS file: /cvsroot/src/external/ibm-public/postfix/dist/src/smtpd/smtpd.c,v 86 | retrieving revision 1.17 87 | diff -u -u -r1.17 smtpd.c 88 | --- dist/src/smtpd/smtpd.c 18 Mar 2020 19:05:20 -0000 1.17 89 | +++ dist/src/smtpd/smtpd.c 25 Sep 2020 12:51:52 -0000 90 | @@ -5795,6 +5795,8 @@ 91 | || strcmp(state->reason, REASON_LOST_CONNECTION)) { 92 | msg_info("%s after %s from %s", 93 | state->reason, state->where, state->namaddr); 94 | + if (strcmp(state->where, SMTPD_CMD_AUTH) == 0) 95 | + pfilter_notify(1, vstream_fileno(state->client)); 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /lib/blocklist.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: blocklist.c,v 1.4 2025/02/11 17:48:30 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifdef HAVE_CONFIG_H 32 | #include "config.h" 33 | #endif 34 | 35 | #ifdef HAVE_SYS_CDEFS_H 36 | #include 37 | #endif 38 | __RCSID("$NetBSD: blocklist.c,v 1.4 2025/02/11 17:48:30 christos Exp $"); 39 | 40 | #include 41 | #include 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | int 50 | blocklist_sa(int action, int rfd, const struct sockaddr *sa, socklen_t salen, 51 | const char *msg) 52 | { 53 | struct blocklist *bl; 54 | int rv; 55 | if ((bl = blocklist_open()) == NULL) 56 | return -1; 57 | rv = blocklist_sa_r(bl, action, rfd, sa, salen, msg); 58 | blocklist_close(bl); 59 | return rv; 60 | } 61 | 62 | int 63 | blocklist_sa_r(struct blocklist *bl, int action, int rfd, 64 | const struct sockaddr *sa, socklen_t slen, const char *msg) 65 | { 66 | bl_type_t internal_action; 67 | 68 | /* internal values are not the same as user application values */ 69 | switch (action) { 70 | case BLOCKLIST_AUTH_FAIL: 71 | internal_action = BL_ADD; 72 | break; 73 | case BLOCKLIST_AUTH_OK: 74 | internal_action = BL_DELETE; 75 | break; 76 | case BLOCKLIST_ABUSIVE_BEHAVIOR: 77 | internal_action = BL_ABUSE; 78 | break; 79 | case BLOCKLIST_BAD_USER: 80 | internal_action = BL_BADUSER; 81 | break; 82 | default: 83 | internal_action = BL_INVALID; 84 | break; 85 | } 86 | return bl_send(bl, internal_action, rfd, sa, slen, msg); 87 | } 88 | 89 | int 90 | blocklist(int action, int rfd, const char *msg) 91 | { 92 | return blocklist_sa(action, rfd, NULL, 0, msg); 93 | } 94 | 95 | int 96 | blocklist_r(struct blocklist *bl, int action, int rfd, const char *msg) 97 | { 98 | return blocklist_sa_r(bl, action, rfd, NULL, 0, msg); 99 | } 100 | 101 | struct blocklist * 102 | blocklist_open(void) { 103 | return bl_create(false, NULL, vsyslog_r); 104 | } 105 | 106 | struct blocklist * 107 | blocklist_open2( 108 | void (*logger)(int, struct syslog_data *, const char *, va_list)) 109 | { 110 | return bl_create(false, NULL, logger); 111 | } 112 | 113 | void 114 | blocklist_close(struct blocklist *bl) 115 | { 116 | bl_destroy(bl); 117 | } 118 | -------------------------------------------------------------------------------- /test/cltest.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: cltest.c,v 1.2 2025/02/11 17:48:31 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifdef HAVE_CONFIG_H 32 | #include "config.h" 33 | #endif 34 | 35 | #ifdef HAVE_SYS_CDEFS_H 36 | #include 37 | #endif 38 | __RCSID("$NetBSD: cltest.c,v 1.2 2025/02/11 17:48:31 christos Exp $"); 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #ifdef HAVE_UTIL_H 51 | #include 52 | #endif 53 | 54 | static __dead void 55 | usage(int c) 56 | { 57 | warnx("Unknown option `%c'", (char)c); 58 | fprintf(stderr, "Usage: %s [-u] [-a ] [-m ] [-p ]\n", 59 | getprogname()); 60 | exit(EXIT_FAILURE); 61 | } 62 | 63 | static void 64 | getaddr(const char *a, in_port_t p, struct sockaddr_storage *ss, 65 | socklen_t *slen) 66 | { 67 | int c; 68 | 69 | memset(ss, 0, sizeof(*ss)); 70 | p = htons(p); 71 | 72 | if (strchr(a, ':')) { 73 | struct sockaddr_in6 *s6 = (void *)ss; 74 | c = inet_pton(AF_INET6, a, &s6->sin6_addr); 75 | s6->sin6_family = AF_INET6; 76 | *slen = sizeof(*s6); 77 | s6->sin6_port = p; 78 | } else { 79 | struct sockaddr_in *s = (void *)ss; 80 | c = inet_pton(AF_INET, a, &s->sin_addr); 81 | s->sin_family = AF_INET; 82 | *slen = sizeof(*s); 83 | s->sin_port = p; 84 | } 85 | #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 86 | ss->ss_len = (uint8_t)*slen; 87 | #endif 88 | if (c == -1) 89 | err(EXIT_FAILURE, "Invalid address `%s'", a); 90 | } 91 | 92 | int 93 | main(int argc, char *argv[]) 94 | { 95 | int sfd; 96 | int c; 97 | struct sockaddr_storage ss; 98 | const char *msg = "hello"; 99 | const char *addr = "127.0.0.1"; 100 | int type = SOCK_STREAM; 101 | in_port_t port = 6161; 102 | socklen_t slen; 103 | char buf[128]; 104 | 105 | while ((c = getopt(argc, argv, "a:m:p:u")) != -1) { 106 | switch (c) { 107 | case 'a': 108 | addr = optarg; 109 | break; 110 | case 'm': 111 | msg = optarg; 112 | break; 113 | case 'p': 114 | port = (in_port_t)atoi(optarg); 115 | break; 116 | case 'u': 117 | type = SOCK_DGRAM; 118 | break; 119 | default: 120 | usage(c); 121 | } 122 | } 123 | 124 | getaddr(addr, port, &ss, &slen); 125 | 126 | if ((sfd = socket(AF_INET, type, 0)) == -1) 127 | err(EXIT_FAILURE, "socket"); 128 | 129 | sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (const void *)&ss); 130 | printf("connecting to: %s\n", buf); 131 | if (connect(sfd, (const void *)&ss, slen) == -1) 132 | err(EXIT_FAILURE, "connect"); 133 | 134 | size_t len = strlen(msg) + 1; 135 | if (write(sfd, msg, len) != (ssize_t)len) 136 | err(EXIT_FAILURE, "write"); 137 | return 0; 138 | } 139 | -------------------------------------------------------------------------------- /bin/support.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: support.c,v 1.3 2025/02/11 17:48:30 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifdef HAVE_CONFIG_H 32 | #include "config.h" 33 | #endif 34 | 35 | #ifdef HAVE_SYS_CDEFS_H 36 | #include 37 | #endif 38 | __RCSID("$NetBSD: support.c,v 1.3 2025/02/11 17:48:30 christos Exp $"); 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "support.h" 49 | 50 | static __attribute__((__format_arg__(3))) const char * 51 | expandm(char *buf, size_t len, const char *fmt) 52 | { 53 | char *p; 54 | size_t r; 55 | 56 | if ((p = strstr(fmt, "%m")) == NULL) 57 | return fmt; 58 | 59 | r = (size_t)(p - fmt); 60 | if (r >= len) 61 | return fmt; 62 | 63 | strlcpy(buf, fmt, r + 1); 64 | strlcat(buf, strerror(errno), len); 65 | strlcat(buf, fmt + r + 2, len); 66 | 67 | return buf; 68 | } 69 | 70 | void 71 | vdlog(int level __unused, struct syslog_data *sd __unused, 72 | const char *fmt, va_list ap) 73 | { 74 | char buf[BUFSIZ]; 75 | 76 | // fprintf(stderr, "%s: ", getprogname()); 77 | vfprintf(stderr, expandm(buf, sizeof(buf), fmt), ap); 78 | fprintf(stderr, "\n"); 79 | } 80 | 81 | void 82 | dlog(int level, const char *fmt, ...) 83 | { 84 | va_list ap; 85 | 86 | va_start(ap, fmt); 87 | vdlog(level, NULL, fmt, ap); 88 | va_end(ap); 89 | } 90 | 91 | const char * 92 | fmttime(char *b, size_t l, time_t t) 93 | { 94 | struct tm tm; 95 | if (localtime_r(&t, &tm) == NULL) 96 | snprintf(b, l, "*%jd*", (intmax_t)t); 97 | else 98 | strftime(b, l, "%Y/%m/%d %H:%M:%S", &tm); 99 | return b; 100 | } 101 | 102 | const char * 103 | fmtydhms(char *b, size_t l, time_t t) 104 | { 105 | time_t s, m, h, d, y; 106 | int z; 107 | size_t o; 108 | 109 | s = t % 60; 110 | t /= 60; 111 | 112 | m = t % 60; 113 | t /= 60; 114 | 115 | h = t % 24; 116 | t /= 24; 117 | 118 | d = t % 365; 119 | t /= 365; 120 | 121 | y = t; 122 | 123 | z = 0; 124 | o = 0; 125 | #define APPEND(a) \ 126 | if (a) { \ 127 | z = snprintf(b + o, l - o, "%jd%s", (intmax_t)a, __STRING(a)); \ 128 | if (z == -1) \ 129 | return b; \ 130 | o += (size_t)z; \ 131 | if (o >= l) \ 132 | return b; \ 133 | } 134 | APPEND(y) 135 | APPEND(d) 136 | APPEND(h) 137 | APPEND(m) 138 | APPEND(s) 139 | return b; 140 | } 141 | 142 | ssize_t 143 | blhexdump(char *buf, size_t len, const char *str, const void *b, size_t l) 144 | { 145 | size_t z, cz; 146 | int r; 147 | const unsigned char *p = b; 148 | const unsigned char *e = p + l; 149 | 150 | r = snprintf(buf, len, "%s: ", str); 151 | if (r == -1) 152 | return -1; 153 | if ((cz = z = (size_t)r) >= len) 154 | cz = len; 155 | 156 | while (p < e) { 157 | r = snprintf(buf + cz, len - cz, "%.2x", *p++); 158 | if (r == -1) 159 | return -1; 160 | if ((cz = (z += (size_t)r)) >= len) 161 | cz = len; 162 | } 163 | return (ssize_t)z; 164 | } 165 | -------------------------------------------------------------------------------- /diff/ssh.diff: -------------------------------------------------------------------------------- 1 | --- /dev/null 2015-01-22 23:10:33.000000000 -0500 2 | +++ dist/pfilter.c 2015-01-22 23:46:03.000000000 -0500 3 | @@ -0,0 +1,32 @@ 4 | +#include "namespace.h" 5 | +#include "includes.h" 6 | +#include "ssh.h" 7 | +#include "packet.h" 8 | +#include "log.h" 9 | +#include "pfilter.h" 10 | +#include 11 | + 12 | +static struct blocklist *blstate; 13 | + 14 | +void 15 | +pfilter_init(void) 16 | +{ 17 | + blstate = blocklist_open(); 18 | +} 19 | + 20 | +void 21 | +pfilter_notify(int a) 22 | +{ 23 | + int fd; 24 | + if (blstate == NULL) 25 | + pfilter_init(); 26 | + if (blstate == NULL) 27 | + return; 28 | + // XXX: 3? 29 | + fd = packet_connection_is_on_socket() ? packet_get_connection_in() : 3; 30 | + (void)blocklist_r(blstate, a, fd, "ssh"); 31 | + if (a == 0) { 32 | + blocklist_close(blstate); 33 | + blstate = NULL; 34 | + } 35 | +} 36 | --- /dev/null 2015-01-20 21:14:44.000000000 -0500 37 | +++ dist/pfilter.h 2015-01-20 20:16:20.000000000 -0500 38 | @@ -0,0 +1,3 @@ 39 | + 40 | +void pfilter_notify(int); 41 | +void pfilter_init(void); 42 | Index: bin/sshd/Makefile 43 | =================================================================== 44 | RCS file: /cvsroot/src/crypto/external/bsd/openssh/bin/sshd/Makefile,v 45 | retrieving revision 1.10 46 | diff -u -u -r1.10 Makefile 47 | --- bin/sshd/Makefile 19 Oct 2014 16:30:58 -0000 1.10 48 | +++ bin/sshd/Makefile 22 Jan 2015 21:39:21 -0000 49 | @@ -15,7 +15,7 @@ 50 | auth2-none.c auth2-passwd.c auth2-pubkey.c \ 51 | monitor_mm.c monitor.c monitor_wrap.c \ 52 | kexdhs.c kexgexs.c kexecdhs.c sftp-server.c sftp-common.c \ 53 | - roaming_common.c roaming_serv.c sandbox-rlimit.c 54 | + roaming_common.c roaming_serv.c sandbox-rlimit.c pfilter.c 55 | 56 | COPTS.auth-options.c= -Wno-pointer-sign 57 | COPTS.ldapauth.c= -Wno-format-nonliteral # XXX: should fix 58 | @@ -68,3 +68,6 @@ 59 | 60 | LDADD+= -lwrap 61 | DPADD+= ${LIBWRAP} 62 | + 63 | +LDADD+= -lblocklist 64 | +DPADD+= ${LIBBLOCKLIST} 65 | diff -ru openssh-7.7p1/auth-pam.c dist/auth-pam.c 66 | --- openssh-7.7p1/auth-pam.c 2018-04-02 01:38:28.000000000 -0400 67 | +++ dist/auth-pam.c 2018-05-23 11:56:22.206661484 -0400 68 | @@ -103,6 +103,7 @@ 69 | #include "ssh-gss.h" 70 | #endif 71 | #include "monitor_wrap.h" 72 | +#include "pfilter.h" 73 | 74 | extern ServerOptions options; 75 | extern Buffer loginmsg; 76 | @@ -526,6 +527,7 @@ 77 | ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, &buffer); 78 | else 79 | ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer); 80 | + pfilter_notify(1); 81 | buffer_free(&buffer); 82 | pthread_exit(NULL); 83 | 84 | @@ -804,6 +806,7 @@ 85 | free(msg); 86 | return (0); 87 | } 88 | + pfilter_notify(1); 89 | error("PAM: %s for %s%.100s from %.100s", msg, 90 | sshpam_authctxt->valid ? "" : "illegal user ", 91 | sshpam_authctxt->user, 92 | diff -ru openssh-7.7p1/auth2.c dist/auth2.c 93 | --- openssh-7.7p1/auth2.c 2018-04-02 01:38:28.000000000 -0400 94 | +++ dist/auth2.c 2018-05-23 11:57:31.022197317 -0400 95 | @@ -51,6 +51,7 @@ 96 | #include "dispatch.h" 97 | #include "pathnames.h" 98 | #include "buffer.h" 99 | +#include "pfilter.h" 100 | 101 | #ifdef GSSAPI 102 | #include "ssh-gss.h" 103 | @@ -242,6 +243,7 @@ 104 | } else { 105 | /* Invalid user, fake password information */ 106 | authctxt->pw = fakepw(); 107 | + pfilter_notify(1); 108 | #ifdef SSH_AUDIT_EVENTS 109 | PRIVSEP(audit_event(SSH_INVALID_USER)); 110 | #endif 111 | Only in dist: pfilter.c 112 | Only in dist: pfilter.h 113 | diff -ru openssh-7.7p1/sshd.c dist/sshd.c 114 | --- openssh-7.7p1/sshd.c 2018-04-02 01:38:28.000000000 -0400 115 | +++ dist/sshd.c 2018-05-23 11:59:39.573197347 -0400 116 | @@ -122,6 +122,7 @@ 117 | #include "auth-options.h" 118 | #include "version.h" 119 | #include "ssherr.h" 120 | +#include "pfilter.h" 121 | 122 | /* Re-exec fds */ 123 | #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) 124 | @@ -346,6 +347,7 @@ 125 | static void 126 | grace_alarm_handler(int sig) 127 | { 128 | + pfilter_notify(1); 129 | if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0) 130 | kill(pmonitor->m_pid, SIGALRM); 131 | 132 | @@ -1835,6 +1837,8 @@ 133 | if (test_flag) 134 | exit(0); 135 | 136 | + pfilter_init(); 137 | + 138 | /* 139 | * Clear out any supplemental groups we may have inherited. This 140 | * prevents inadvertent creation of files with bad modes (in the 141 | @@ -2280,6 +2284,9 @@ 142 | { 143 | struct ssh *ssh = active_state; /* XXX */ 144 | 145 | + if (i == 255) 146 | + pfilter_notify(1); 147 | + 148 | if (the_authctxt) { 149 | do_cleanup(ssh, the_authctxt); 150 | if (use_privsep && privsep_is_preauth && 151 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | # $NetBSD: README,v 1.3 2024/02/09 00:53:30 wiz Exp $ 2 | 3 | This package contains library that can be used by network daemons to 4 | communicate with a packet filter via a daemon to enforce opening and 5 | closing ports dynamically based on policy. 6 | 7 | The interface to the packet filter is in libexec/blocklistd-helper 8 | (this is currently designed for npf) and the configuration file 9 | (inspired from inetd.conf) is in etc/blocklistd.conf. 10 | 11 | On NetBSD you can find an example npf.conf and blocklistd.conf in 12 | /usr/share/examples/blocklistd; you need to adjust the interface 13 | in npf.conf and copy both files to /etc; then you just enable 14 | blocklistd=YES in /etc/rc.conf, start it up, and you are all set. 15 | 16 | There is also a startup file in etc/rc.d/blocklistd 17 | 18 | Patches to various daemons to add blocklisting capabilities are in the 19 | "diff" directory: 20 | - OpenSSH: diff/ssh.diff [tcp socket example] 21 | - Bind: diff/named.diff [both tcp and udp] 22 | - ftpd: diff/ftpd.diff [tcp] 23 | 24 | These patches have been applied to NetBSD-current. 25 | 26 | The network daemon (for example sshd) communicates to blocklistd, via 27 | a Unix socket like syslog. The library calls are simple and everything 28 | is handled by the library. In the simplest form the only thing the 29 | daemon needs to do is to call: 30 | 31 | blocklist(action, acceptedfd, message); 32 | 33 | Where: 34 | action = 0 -> successful login clear blocklist state 35 | 1 -> failed login, add to the failed count 36 | acceptedfd -> the file descriptor where the server is 37 | connected to the remote client. It is used 38 | to determine the listening socket, and the 39 | remote address. This allows any program to 40 | contact the blocklist daemon, since the verification 41 | if the program has access to the listening 42 | socket is done by virtue that the port 43 | number is retrieved from the kernel. 44 | message -> an optional string that is used in debugging logs. 45 | 46 | Unfortunately there is no way to get information about the "peer" 47 | from a udp socket, because there is no connection and that information 48 | is kept with the server. In that case the daemon can provide the 49 | peer information to blocklistd via: 50 | 51 | blocklist_sa(action, acceptedfd, sockaddr, sockaddr_len, message); 52 | 53 | The configuration file contains entries of the form: 54 | 55 | # Blocklist rule 56 | # host/Port type protocol owner name nfail disable 57 | 192.168.1.1:ssh stream tcp * -int 10 1m 58 | 8.8.8.8:ssh stream tcp * -ext 6 60m 59 | ssh stream tcp6 * * 6 60m 60 | http stream tcp * * 6 60m 61 | 62 | Here note that owner is * because the connection is done from the 63 | child ssh socket which runs with user privs. We treat IPv4 connections 64 | differently by maintaining two different rules one for the external 65 | interface and one from the internal We also register for both tcp 66 | and tcp6 since those are different listening sockets and addresses; 67 | we don't bother with IPv6 and separate rules. We use nfail = 6, 68 | because ssh allows 3 password attempts per connection, and this 69 | will let us have 2 connections before blocking. Finally we block 70 | for an hour; we could block forever too by specifying * in the 71 | duration column. 72 | 73 | blocklistd and the library use syslog(3) to report errors. The 74 | blocklist filter state is persisted automatically in /var/db/blocklistd.db 75 | so that if the daemon is restarted, it remembers what connections 76 | is currently handling. To start from a fresh state (if you restart 77 | npf too for example), you can use -f. To watch the daemon at work, 78 | you can use -d. 79 | 80 | The current control file is designed for npf, and it uses the 81 | dynamic rule feature. You need to create a dynamic rule in your 82 | /etc/npf.conf on the group referring to the interface you want to block 83 | called blocklistd as follows: 84 | 85 | ext_if=bge0 86 | int_if=sk0 87 | 88 | group "external" on $ext_if { 89 | ... 90 | ruleset "blocklistd-ext" 91 | ruleset "blocklistd" 92 | ... 93 | } 94 | 95 | group "internal" on $int_if { 96 | ... 97 | ruleset "blocklistd-int" 98 | ... 99 | } 100 | 101 | You can use 'blocklistctl dump -a' to list all the current entries 102 | in the database; the ones that have nfail / where urrent 103 | >= otal, should have an id associated with them; this means that 104 | there is a packet filter rule added for that entry. For npf, you 105 | can examine the packet filter dynamic rule entries using 'npfctl 106 | rule list'. The number of current entries can exceed 107 | the total. This happens because entering packet filter rules is 108 | asynchronous; there could be other connection before the rule 109 | becomes activated. 110 | 111 | Enjoy, 112 | 113 | christos 114 | -------------------------------------------------------------------------------- /bin/blocklistctl.8: -------------------------------------------------------------------------------- 1 | .\" $NetBSD: blocklistctl.8,v 1.6 2025/10/26 13:49:22 christos Exp $ 2 | .\" 3 | .\" Copyright (c) 2015 The NetBSD Foundation, Inc. 4 | .\" All rights reserved. 5 | .\" 6 | .\" This code is derived from software contributed to The NetBSD Foundation 7 | .\" by Christos Zoulas. 8 | .\" 9 | .\" Redistribution and use in source and binary forms, with or without 10 | .\" modification, are permitted provided that the following conditions 11 | .\" are met: 12 | .\" 1. Redistributions of source code must retain the above copyright 13 | .\" notice, this list of conditions and the following disclaimer. 14 | .\" 2. Redistributions in binary form must reproduce the above copyright 15 | .\" notice, this list of conditions and the following disclaimer in the 16 | .\" documentation and/or other materials provided with the distribution. 17 | .\" 18 | .\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 | .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | .\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 | .\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 | .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | .\" POSSIBILITY OF SUCH DAMAGE. 29 | .\" 30 | .Dd October 25, 2025 31 | .Dt BLOCKLISTCTL 8 32 | .Os 33 | .Sh NAME 34 | .Nm blocklistctl 35 | .Nd display and change the state of the blocklistd database 36 | .Sh SYNOPSIS 37 | .Nm 38 | .Cm dump 39 | .Op Fl abdnrw 40 | .Op Fl D Ar dbname 41 | .Sh DESCRIPTION 42 | .Nm 43 | is a program used to display and change the state of the 44 | .Xr blocklistd 8 45 | database. 46 | The following sub-commands are supported: 47 | .Ss dump 48 | The following options are available for the 49 | .Cm dump 50 | sub-command: 51 | .Bl -tag -width indent 52 | .It Fl a 53 | Show all database entries, by default it shows only the active ones. 54 | Inactive entries will be shown with a last-access (or, with 55 | .Fl r , 56 | the remaining) time of 57 | .Ql never . 58 | .It Fl b 59 | Show only the blocked entries. 60 | .It Fl D Ar dbname 61 | Specify the location of the 62 | .Ic blocklistd 63 | database file to use. 64 | The default is 65 | .Pa /var/db/blocklistd.db . 66 | .It Fl d 67 | Increase debugging level. 68 | .It Fl n 69 | Don't display a header. 70 | .It Fl r 71 | Show the remaining blocked time instead of the last activity time. 72 | .It Fl w 73 | Normally the width of addresses is good for IPv4, the 74 | .Fl w 75 | flag, makes the display wide enough for IPv6 addresses. 76 | .El 77 | .Pp 78 | The output of the 79 | .Cm dump 80 | sub-command consists of a header (unless 81 | .Fl n 82 | was given) and one line for each record in the database, where each line 83 | has the following columns: 84 | .Bl -tag -width indent 85 | .It Ql rulename 86 | The packet filter rule name associated with the database entry, 87 | usually 88 | .Dv blocklistd . 89 | .It Ql address/ma:port 90 | The remote address, mask, and local port number of the client connection 91 | associated with the database entry. 92 | .It Ql id 93 | column will show the identifier for the packet filter rule associated 94 | with the database entry, though this may only be the word 95 | .Ql OK 96 | for packet filters which do not create a unique identifier for each rule. 97 | .It Ql nfail 98 | The number of 99 | .Em failures 100 | reported for the client on the noted port, as well as the number of 101 | failures allowed before blocking (or, with 102 | .Fl a , 103 | an asterisk 104 | .Aq * ) 105 | .It So last access Sc | So remaining time Sc 106 | The last time a the client was reported as attempting access, or, with 107 | .Fl r , 108 | the time remaining before the rule blocking the client will be removed. 109 | .El 110 | .Sh SEE ALSO 111 | .Xr blocklistd 8 112 | .Sh NOTES 113 | Sometimes the reported number of failed attempts can exceed the number 114 | of attempts that 115 | .Xr blocklistd 8 116 | is configured to block. 117 | This can happen either because the rule has been removed manually, or 118 | because there were more attempts in flight while the rule block was being 119 | added. 120 | This condition is normal; in that case 121 | .Xr blocklistd 8 122 | will first attempt to remove the existing rule, and then it will re-add 123 | it to make sure that there is only one rule active. 124 | .Sh HISTORY 125 | .Nm 126 | first appeared in 127 | .Nx 7 . 128 | .Fx 129 | support for 130 | .Nm 131 | was implemented in 132 | .Fx 11 . 133 | .Sh AUTHORS 134 | .An Christos Zoulas 135 | -------------------------------------------------------------------------------- /bin/run.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: run.c,v 1.3 2025/02/11 17:48:30 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifdef HAVE_CONFIG_H 32 | #include "config.h" 33 | #endif 34 | 35 | #ifdef HAVE_SYS_CDEFS_H 36 | #include 37 | #endif 38 | __RCSID("$NetBSD: run.c,v 1.3 2025/02/11 17:48:30 christos Exp $"); 39 | 40 | #include 41 | #ifdef HAVE_LIBUTIL_H 42 | #include 43 | #endif 44 | #ifdef HAVE_UTIL_H 45 | #include 46 | #endif 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #include "run.h" 57 | #include "conf.h" 58 | #include "internal.h" 59 | #include "support.h" 60 | 61 | extern char **environ; 62 | 63 | static char * 64 | run(const char *cmd, const char *name, ...) 65 | { 66 | const char *argv[20]; 67 | size_t i; 68 | va_list ap; 69 | FILE *fp; 70 | char buf[10240], *res; 71 | 72 | argv[0] = "control"; 73 | argv[1] = cmd; 74 | argv[2] = name; 75 | va_start(ap, name); 76 | for (i = 3; i < __arraycount(argv) && 77 | (argv[i] = va_arg(ap, char *)) != NULL; i++) 78 | continue; 79 | va_end(ap); 80 | 81 | if (debug) { 82 | size_t z; 83 | int r; 84 | 85 | r = snprintf(buf, sizeof(buf), "run %s [", controlprog); 86 | if (r == -1 || (z = (size_t)r) >= sizeof(buf)) 87 | z = sizeof(buf); 88 | for (i = 0; argv[i]; i++) { 89 | r = snprintf(buf + z, sizeof(buf) - z, "%s%s", 90 | argv[i], argv[i + 1] ? " " : ""); 91 | if (r == -1 || (z += (size_t)r) >= sizeof(buf)) 92 | z = sizeof(buf); 93 | } 94 | (*lfun)(LOG_DEBUG, "%s]", buf); 95 | } 96 | 97 | fp = popenve(controlprog, __UNCONST(argv), environ, "r"); 98 | if (fp == NULL) { 99 | (*lfun)(LOG_ERR, "popen %s failed (%m)", controlprog); 100 | return NULL; 101 | } 102 | if (fgets(buf, sizeof(buf), fp) != NULL) 103 | res = strdup(buf); 104 | else 105 | res = NULL; 106 | pclose(fp); 107 | if (debug) 108 | (*lfun)(LOG_DEBUG, "%s returns %s", cmd, res); 109 | return res; 110 | } 111 | 112 | void 113 | run_flush(const struct conf *c) 114 | { 115 | free(run("flush", c->c_name, NULL)); 116 | } 117 | 118 | int 119 | run_change(const char *how, const struct conf *c, char *id, size_t len) 120 | { 121 | const char *prname; 122 | char poname[64], adname[128], maskname[32], *rv; 123 | size_t off; 124 | 125 | switch (c->c_proto) { 126 | case -1: 127 | prname = ""; 128 | break; 129 | case IPPROTO_TCP: 130 | prname = "tcp"; 131 | break; 132 | case IPPROTO_UDP: 133 | prname = "udp"; 134 | break; 135 | default: 136 | (*lfun)(LOG_ERR, "%s: bad protocol %d (line %zu)", __func__, 137 | c->c_proto, c->c_lineno); 138 | return -1; 139 | } 140 | 141 | if (c->c_port != -1) 142 | snprintf(poname, sizeof(poname), "%d", c->c_port); 143 | else 144 | poname[0] = '\0'; 145 | 146 | snprintf(maskname, sizeof(maskname), "%d", c->c_lmask); 147 | sockaddr_snprintf(adname, sizeof(adname), "%a", (const void *)&c->c_ss); 148 | 149 | rv = run(how, c->c_name, prname, adname, maskname, poname, id, NULL); 150 | if (rv == NULL) 151 | return -1; 152 | if (len != 0) { 153 | rv[strcspn(rv, "\n")] = '\0'; 154 | off = strncmp(rv, "OK ", 3) == 0 ? 3 : 0; 155 | strlcpy(id, rv + off, len); 156 | } 157 | free(rv); 158 | return 0; 159 | } 160 | -------------------------------------------------------------------------------- /bin/blocklistctl.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: blocklistctl.c,v 1.5 2025/10/25 16:56:10 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifdef HAVE_CONFIG_H 32 | #include "config.h" 33 | #endif 34 | 35 | #ifdef HAVE_SYS_CDEFS_H 36 | #include 37 | #endif 38 | __RCSID("$NetBSD: blocklistctl.c,v 1.5 2025/10/25 16:56:10 christos Exp $"); 39 | 40 | #include 41 | #include 42 | #ifdef HAVE_LIBUTIL_H 43 | #include 44 | #endif 45 | #ifdef HAVE_UTIL_H 46 | #include 47 | #endif 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #include "conf.h" 57 | #include "state.h" 58 | #include "internal.h" 59 | #include "support.h" 60 | 61 | static __dead void 62 | usage(int c) 63 | { 64 | if (c == 0) 65 | warnx("Missing/unknown command"); 66 | else if (c != '?') 67 | warnx("Unknown option `%c'", (char)c); 68 | fprintf(stderr, 69 | "Usage: %s dump [-abdnrw] [-D dbname]\n", getprogname()); 70 | exit(EXIT_FAILURE); 71 | } 72 | 73 | static const char * 74 | star(char *buf, size_t len, int val) 75 | { 76 | if (val == -1) 77 | return "*"; 78 | snprintf(buf, len, "%d", val); 79 | return buf; 80 | } 81 | 82 | int 83 | main(int argc, char *argv[]) 84 | { 85 | const char *dbname = _PATH_BLSTATE; 86 | DB *db; 87 | struct conf c; 88 | struct dbinfo dbi; 89 | unsigned int i; 90 | struct timespec ts; 91 | int all, blocked, remain, wide, noheader; 92 | int o; 93 | 94 | noheader = wide = blocked = all = remain = 0; 95 | lfun = dlog; 96 | 97 | if (argc == 1 || strcmp(argv[1], "dump") != 0) 98 | usage(0); 99 | 100 | argc--; 101 | argv++; 102 | 103 | while ((o = getopt(argc, argv, "abD:dnrw")) != -1) 104 | switch (o) { 105 | case 'a': 106 | all = 1; 107 | blocked = 0; 108 | break; 109 | case 'b': 110 | blocked = 1; 111 | break; 112 | case 'D': 113 | dbname = optarg; 114 | break; 115 | case 'd': 116 | debug++; 117 | break; 118 | case 'n': 119 | noheader = 1; 120 | break; 121 | case 'r': 122 | remain = 1; 123 | break; 124 | case 'w': 125 | wide = 1; 126 | break; 127 | default: 128 | usage(o); 129 | } 130 | 131 | db = state_open(dbname, O_RDONLY, 0); 132 | if (db == NULL) 133 | err(EXIT_FAILURE, "Can't open `%s'", dbname); 134 | 135 | clock_gettime(CLOCK_REALTIME, &ts); 136 | wide = wide ? 8 * 4 + 7 : 4 * 3 + 3; 137 | if (!noheader) 138 | printf("rulename\t%*.*s/ma:port\tid\tnfail\t%s\n", wide, wide, 139 | "address", remain ? "remaining time" : "last access"); 140 | for (i = 1; state_iterate(db, &c, &dbi, i) != 0; i = 0) { 141 | char buf[BUFSIZ]; 142 | char mbuf[64], pbuf[64]; 143 | if (!all) { 144 | if (blocked) { 145 | if (c.c_nfail == -1 || dbi.count < c.c_nfail) 146 | continue; 147 | } else { 148 | if (dbi.count >= c.c_nfail) 149 | continue; 150 | } 151 | } 152 | sockaddr_snprintf(buf, sizeof(buf), "%a", (void *)&c.c_ss); 153 | printf("%s\t%*.*s/%s:%s\t", c.c_name, wide, wide, buf, 154 | star(mbuf, sizeof(mbuf), c.c_lmask), 155 | star(pbuf, sizeof(pbuf), c.c_port)); 156 | if (c.c_duration == -1) { 157 | strlcpy(buf, "never", sizeof(buf)); 158 | } else { 159 | if (remain) 160 | fmtydhms(buf, sizeof(buf), 161 | c.c_duration - (ts.tv_sec - dbi.last)); 162 | else 163 | fmttime(buf, sizeof(buf), dbi.last); 164 | } 165 | printf("%s\t%d/%s\t%-s\n", dbi.id, dbi.count, 166 | star(mbuf, sizeof(mbuf), c.c_nfail), buf); 167 | } 168 | state_close(db); 169 | return EXIT_SUCCESS; 170 | } 171 | -------------------------------------------------------------------------------- /port/pidfile.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: pidfile.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Jason R. Thorpe, Matthias Scheler and Julio Merino. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifdef HAVE_CONFIG_H 32 | #include "config.h" 33 | #endif 34 | 35 | #ifdef HAVE_SYS_CDEFS_H 36 | #include 37 | #endif 38 | #if defined(LIBC_SCCS) && !defined(lint) 39 | __RCSID("$NetBSD: pidfile.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); 40 | #endif 41 | 42 | #include 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #ifdef HAVE_LIBUTIL_H 51 | #include 52 | #endif 53 | #ifdef HAVE_UTIL_H 54 | #include 55 | #endif 56 | 57 | static pid_t pidfile_pid; 58 | static char *pidfile_path; 59 | 60 | /* Deletes an existent pidfile iff it was created by this process. */ 61 | static void 62 | pidfile_cleanup(void) 63 | { 64 | 65 | if ((pidfile_path != NULL) && (pidfile_pid == getpid())) 66 | (void) unlink(pidfile_path); 67 | } 68 | 69 | /* Registers an atexit(3) handler to delete the pidfile we have generated. 70 | * We only register the handler when we create a pidfile, so we can assume 71 | * that the pidfile exists. 72 | * 73 | * Returns 0 on success or -1 if the handler could not be registered. */ 74 | static int 75 | register_atexit_handler(void) 76 | { 77 | static bool done = false; 78 | 79 | if (!done) { 80 | if (atexit(pidfile_cleanup) < 0) 81 | return -1; 82 | done = true; 83 | } 84 | 85 | return 0; 86 | } 87 | 88 | /* Given a new pidfile name in 'path', deletes any previously-created pidfile 89 | * if the previous file differs to the new one. 90 | * 91 | * If a previous file is deleted, returns 1, which means that a new pidfile 92 | * must be created. Otherwise, this returns 0, which means that the existing 93 | * file does not need to be touched. */ 94 | static int 95 | cleanup_old_pidfile(const char* path) 96 | { 97 | if (pidfile_path != NULL) { 98 | if (strcmp(pidfile_path, path) != 0) { 99 | pidfile_cleanup(); 100 | 101 | free(pidfile_path); 102 | pidfile_path = NULL; 103 | 104 | return 1; 105 | } else 106 | return 0; 107 | } else 108 | return 1; 109 | } 110 | 111 | /* Constructs a name for a pidfile in the default location (/var/run). If 112 | * 'basename' is NULL, uses the name of the current program for the name of 113 | * the pidfile. 114 | * 115 | * Returns a pointer to a dynamically-allocatd string containing the absolute 116 | * path to the pidfile; NULL on failure. */ 117 | static char * 118 | generate_varrun_path(const char *bname) 119 | { 120 | char *path; 121 | 122 | if (bname == NULL) 123 | bname = getprogname(); 124 | 125 | /* _PATH_VARRUN includes trailing / */ 126 | if (asprintf(&path, "%s%s.pid", _PATH_VARRUN, bname) == -1) 127 | return NULL; 128 | return path; 129 | } 130 | 131 | /* Creates a pidfile with the provided name. The new pidfile is "registered" 132 | * in the global variables pidfile_path and pidfile_pid so that any further 133 | * call to pidfile(3) can check if we are recreating the same file or a new 134 | * one. 135 | * 136 | * Returns 0 on success or -1 if there is any error. */ 137 | static int 138 | create_pidfile(const char* path) 139 | { 140 | FILE *f; 141 | 142 | if (register_atexit_handler() == -1) 143 | return -1; 144 | 145 | if (cleanup_old_pidfile(path) == 0) 146 | return 0; 147 | 148 | pidfile_path = strdup(path); 149 | if (pidfile_path == NULL) 150 | return -1; 151 | 152 | if ((f = fopen(path, "w")) == NULL) { 153 | free(pidfile_path); 154 | pidfile_path = NULL; 155 | return -1; 156 | } 157 | 158 | pidfile_pid = getpid(); 159 | 160 | (void) fprintf(f, "%d\n", pidfile_pid); 161 | (void) fclose(f); 162 | 163 | return 0; 164 | } 165 | 166 | int 167 | pidfile(const char *path) 168 | { 169 | 170 | if (path == NULL || strchr(path, '/') == NULL) { 171 | char *default_path; 172 | 173 | if ((default_path = generate_varrun_path(path)) == NULL) 174 | return -1; 175 | 176 | if (create_pidfile(default_path) == -1) { 177 | free(default_path); 178 | return -1; 179 | } 180 | 181 | free(default_path); 182 | return 0; 183 | } else 184 | return create_pidfile(path); 185 | } 186 | -------------------------------------------------------------------------------- /lib/libblocklist.3: -------------------------------------------------------------------------------- 1 | .\" $NetBSD: libblocklist.3,v 1.7 2025/02/05 20:14:30 christos Exp $ 2 | .\" 3 | .\" Copyright (c) 2015 The NetBSD Foundation, Inc. 4 | .\" All rights reserved. 5 | .\" 6 | .\" This code is derived from software contributed to The NetBSD Foundation 7 | .\" by Christos Zoulas. 8 | .\" 9 | .\" Redistribution and use in source and binary forms, with or without 10 | .\" modification, are permitted provided that the following conditions 11 | .\" are met: 12 | .\" 1. Redistributions of source code must retain the above copyright 13 | .\" notice, this list of conditions and the following disclaimer. 14 | .\" 2. Redistributions in binary form must reproduce the above copyright 15 | .\" notice, this list of conditions and the following disclaimer in the 16 | .\" documentation and/or other materials provided with the distribution. 17 | .\" 18 | .\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 | .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | .\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 | .\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 | .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | .\" POSSIBILITY OF SUCH DAMAGE. 29 | .\" 30 | .Dd February 5, 2025 31 | .Dt LIBBLOCKLIST 3 32 | .Os 33 | .Sh NAME 34 | .Nm blocklist_open , 35 | .Nm blocklist_open2 , 36 | .Nm blocklist_close , 37 | .Nm blocklist_r , 38 | .Nm blocklist , 39 | .Nm blocklist_sa , 40 | .Nm blocklist_sa_r 41 | .Nd Blocklistd notification library 42 | .Sh LIBRARY 43 | .Lb libblocklist 44 | .Sh SYNOPSIS 45 | .In blocklist.h 46 | .Ft struct blocklist * 47 | .Fn blocklist_open "void" 48 | .Ft struct blocklist * 49 | .Fn blocklist_open2 "void (*logger)(int, struct syslog_data *, va_list)" 50 | .Ft void 51 | .Fn blocklist_close "struct blocklist *cookie" 52 | .Ft int 53 | .Fn blocklist "int action" "int fd" "const char *msg" 54 | .Ft int 55 | .Fn blocklist_r "struct blocklist *cookie" "int action" "int fd" "const char *msg" 56 | .Ft int 57 | .Fn blocklist_sa "int action" "int fd" "const struct sockaddr *sa" "socklen_t salen" "const char *msg" 58 | .Ft int 59 | .Fn blocklist_sa_r "struct blocklist *cookie" "int action" "int fd" "const struct sockaddr *sa" "socklen_t salen" "const char *msg" 60 | .Sh DESCRIPTION 61 | These functions can be used by daemons to notify 62 | .Xr blocklistd 8 63 | about successful and failed remote connections so that blocklistd can 64 | block or release port access to prevent Denial of Service attacks. 65 | .Pp 66 | The function 67 | .Fn blocklist_open 68 | creates the necessary state to communicate with 69 | .Xr blocklistd 8 70 | and returns a pointer to it, or 71 | .Dv NULL 72 | on failure. 73 | .Pp 74 | The function 75 | .Fn blocklist_open2 76 | is similar to 77 | .Fn blocklist_open 78 | but allows a 79 | .Fa logger 80 | to be specified. 81 | If the 82 | .Fa logger 83 | is 84 | .Dv NULL , 85 | then no logging is performed. 86 | .Pp 87 | The 88 | .Fn blocklist_close 89 | function frees all memory and resources used. 90 | .Pp 91 | The 92 | .Fn blocklist 93 | function sends a message to 94 | .Xr blocklistd 8 , 95 | with an integer 96 | .Ar action 97 | argument specifying the type of notification, 98 | a file descriptor 99 | .Ar fd 100 | specifying the accepted file descriptor connected to the client, 101 | and an optional message in the 102 | .Ar msg 103 | argument. 104 | .Pp 105 | The 106 | .Ar action 107 | parameter can take these values: 108 | .Bl -tag -width ".Dv BLOCKLIST_ABUSIVE_BEHAVIOR" 109 | .It Va BLOCKLIST_BAD_USER 110 | The sending daemon has determined the username presented for 111 | authentication is invalid. 112 | This is considered as one failure count. 113 | .It Va BLOCKLIST_AUTH_FAIL 114 | There was an unsuccessful authentication attempt. 115 | This is considered as two failure counts together. 116 | .It Va BLOCKLIST_ABUSIVE_BEHAVIOR 117 | The sending daemon has detected abusive behavior from the remote system. 118 | This is considered as a total immediate failure. 119 | The remote address will be blocked as soon as possible. 120 | .It Va BLOCKLIST_AUTH_OK 121 | A valid user successfully authenticated. 122 | Any entry for the remote address will be removed as soon as possible. 123 | .El 124 | .Pp 125 | The 126 | .Fn blocklist_r 127 | function is more efficient because it keeps the blocklist state around. 128 | .Pp 129 | The 130 | .Fn blocklist_sa 131 | and 132 | .Fn blocklist_sa_r 133 | functions can be used with unconnected sockets, where 134 | .Xr getpeername 2 135 | will not work, the server will pass the peer name in the message. 136 | .Pp 137 | In all cases the file descriptor passed in the 138 | .Fa fd 139 | argument must be pointing to a valid socket so that 140 | .Xr blocklistd 8 141 | can establish ownership of the local endpoint 142 | using 143 | .Xr getsockname 2 . 144 | .Pp 145 | By default, 146 | .Xr syslogd 8 147 | is used for message logging. 148 | The internal 149 | .Fn bl_create 150 | function can be used to create the required internal 151 | state and specify a custom logging function. 152 | .Sh RETURN VALUES 153 | The function 154 | .Fn blocklist_open 155 | returns a cookie on success and 156 | .Dv NULL 157 | on failure setting 158 | .Dv errno 159 | to an appropriate value. 160 | .Pp 161 | The functions 162 | .Fn blocklist , 163 | .Fn blocklist_sa , 164 | and 165 | .Fn blocklist_sa_r 166 | return 167 | .Dv 0 168 | on success and 169 | .Dv \-1 170 | on failure setting 171 | .Dv errno 172 | to an appropriate value. 173 | .Sh SEE ALSO 174 | .Xr blocklistd.conf 5 , 175 | .Xr blocklistd 8 176 | .Sh AUTHORS 177 | .An Christos Zoulas 178 | -------------------------------------------------------------------------------- /bin/state.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: state.c,v 1.3 2025/10/25 18:43:51 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifdef HAVE_CONFIG_H 32 | #include "config.h" 33 | #endif 34 | 35 | #ifdef HAVE_SYS_CDEFS_H 36 | #include 37 | #endif 38 | __RCSID("$NetBSD: state.c,v 1.3 2025/10/25 18:43:51 christos Exp $"); 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include "bl.h" 50 | #include "internal.h" 51 | #include "conf.h" 52 | #include "support.h" 53 | #include "state.h" 54 | 55 | static HASHINFO openinfo = { 56 | 4096, /* bsize */ 57 | 32, /* ffactor */ 58 | 256, /* nelem */ 59 | 8 * 1024 * 1024,/* cachesize */ 60 | NULL, /* hash() */ 61 | 0 /* lorder */ 62 | }; 63 | 64 | int 65 | state_close(DB *db) 66 | { 67 | if (db == NULL) 68 | return -1; 69 | if ((*db->close)(db) == -1) { 70 | (*lfun)(LOG_ERR, "%s: can't close db (%m)", __func__); 71 | return -1; 72 | } 73 | return 0; 74 | } 75 | 76 | DB * 77 | state_open(const char *dbname, int flags, mode_t perm) 78 | { 79 | DB *db; 80 | 81 | #ifdef __APPLE__ 82 | flags &= O_CREAT|O_EXCL|O_EXLOCK|O_NONBLOCK|O_RDONLY| 83 | O_RDWR|O_SHLOCK|O_TRUNC; 84 | #endif 85 | db = dbopen(dbname, flags, perm, DB_HASH, &openinfo); 86 | if (db == NULL) { 87 | if (errno == ENOENT && (flags & O_CREAT) == 0) 88 | return NULL; 89 | (*lfun)(LOG_ERR, "%s: can't open `%s' (%m)", __func__, dbname); 90 | } 91 | return db; 92 | } 93 | 94 | static int 95 | state_sizecheck(const DBT *t) 96 | { 97 | if (sizeof(struct conf) == t->size) 98 | return 0; 99 | (*lfun)(LOG_ERR, "Key size mismatch %zu != %zu", sizeof(struct conf), 100 | t->size); 101 | return -1; 102 | } 103 | 104 | static void 105 | dumpkey(const struct conf *k) 106 | { 107 | char buf[10240]; 108 | blhexdump(buf, sizeof(buf), __func__, k, sizeof(*k)); 109 | (*lfun)(LOG_DEBUG, "%s", buf); 110 | (*lfun)(LOG_DEBUG, "%s: %s", __func__, 111 | conf_print(buf, sizeof(buf), "", "", k)); 112 | 113 | } 114 | 115 | int 116 | state_del(DB *db, const struct conf *c) 117 | { 118 | int rv; 119 | DBT k; 120 | 121 | if (db == NULL) 122 | return -1; 123 | 124 | k.data = __UNCONST(c); 125 | k.size = sizeof(*c); 126 | 127 | switch (rv = (*db->del)(db, &k, 0)) { 128 | case 0: 129 | case 1: 130 | if (debug > 1) { 131 | (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 132 | (*db->sync)(db, 0); 133 | } 134 | return rv; 135 | default: 136 | (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); 137 | return -1; 138 | } 139 | } 140 | 141 | int 142 | state_get(DB *db, const struct conf *c, struct dbinfo *dbi) 143 | { 144 | int rv; 145 | DBT k, v; 146 | 147 | if (db == NULL) 148 | return -1; 149 | 150 | k.data = __UNCONST(c); 151 | k.size = sizeof(*c); 152 | 153 | switch (rv = (*db->get)(db, &k, &v, 0)) { 154 | case 0: 155 | case 1: 156 | if (rv) 157 | memset(dbi, 0, sizeof(*dbi)); 158 | else 159 | memcpy(dbi, v.data, sizeof(*dbi)); 160 | if (debug > 1) 161 | (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 162 | return 0; 163 | default: 164 | (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); 165 | return -1; 166 | } 167 | } 168 | 169 | int 170 | state_put(DB *db, const struct conf *c, const struct dbinfo *dbi) 171 | { 172 | int rv; 173 | DBT k, v; 174 | 175 | if (db == NULL) 176 | return -1; 177 | 178 | k.data = __UNCONST(c); 179 | k.size = sizeof(*c); 180 | v.data = __UNCONST(dbi); 181 | v.size = sizeof(*dbi); 182 | 183 | switch (rv = (*db->put)(db, &k, &v, 0)) { 184 | case 0: 185 | if (debug > 1) { 186 | (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 187 | (*db->sync)(db, 0); 188 | } 189 | return 0; 190 | case 1: 191 | errno = EEXIST; 192 | /*FALLTHROUGH*/ 193 | default: 194 | (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); 195 | return -1; 196 | } 197 | } 198 | 199 | int 200 | state_iterate(DB *db, struct conf *c, struct dbinfo *dbi, unsigned int first) 201 | { 202 | int rv; 203 | DBT k, v; 204 | 205 | if (db == NULL) { 206 | (*lfun)(LOG_ERR, "%s: called with no database file", __func__); 207 | return -1; 208 | } 209 | 210 | first = first ? R_FIRST : R_NEXT; 211 | 212 | switch (rv = (*db->seq)(db, &k, &v, first)) { 213 | case 0: 214 | if (state_sizecheck(&k) == -1) 215 | return -1; 216 | memcpy(c, k.data, sizeof(*c)); 217 | if (debug > 2) 218 | dumpkey(c); 219 | memcpy(dbi, v.data, sizeof(*dbi)); 220 | if (debug > 1) 221 | (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 222 | return 1; 223 | case 1: 224 | if (debug > 1) 225 | (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); 226 | return 0; 227 | default: 228 | (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); 229 | return -1; 230 | } 231 | } 232 | 233 | int 234 | state_sync(DB *db) 235 | { 236 | return (*db->sync)(db, 0); 237 | } 238 | -------------------------------------------------------------------------------- /test/srvtest.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: srvtest.c,v 1.2 2025/02/11 17:43:16 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifdef HAVE_CONFIG_H 32 | #include "config.h" 33 | #endif 34 | 35 | #ifdef HAVE_SYS_CDEFS_H 36 | #include 37 | #endif 38 | __RCSID("$NetBSD: srvtest.c,v 1.2 2025/02/11 17:43:16 christos Exp $"); 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #include "blocklist.h" 54 | #ifdef BLDEBUG 55 | #include "bl.h" 56 | static void *b; 57 | #endif 58 | 59 | #ifndef INFTIM 60 | #define INFTIM -1 61 | #endif 62 | 63 | static void 64 | process_tcp(int afd) 65 | { 66 | ssize_t n; 67 | char buffer[256]; 68 | 69 | memset(buffer, 0, sizeof(buffer)); 70 | 71 | if ((n = read(afd, buffer, sizeof(buffer))) == -1) 72 | err(1, "read"); 73 | buffer[sizeof(buffer) - 1] = '\0'; 74 | printf("%s: sending %d %s\n", getprogname(), afd, buffer); 75 | #ifdef BLDEBUG 76 | blocklist_r(b, 1, afd, buffer); 77 | #else 78 | blocklist(1, afd, buffer); 79 | #endif 80 | exit(0); 81 | } 82 | 83 | static void 84 | process_udp(int afd) 85 | { 86 | ssize_t n; 87 | char buffer[256]; 88 | struct sockaddr_storage ss; 89 | socklen_t slen; 90 | 91 | memset(buffer, 0, sizeof(buffer)); 92 | 93 | slen = (socklen_t)sizeof(ss); 94 | memset(&ss, 0, sizeof(ss)); 95 | if ((n = recvfrom(afd, buffer, sizeof(buffer), 0, (void *)&ss, 96 | &slen)) == -1) 97 | err(1, "recvfrom"); 98 | buffer[sizeof(buffer) - 1] = '\0'; 99 | printf("%s: sending %d %s\n", getprogname(), afd, buffer); 100 | blocklist_sa(1, afd, (void *)&ss, slen, buffer); 101 | exit(0); 102 | } 103 | static int 104 | cr(int af, int type, in_port_t p) 105 | { 106 | int sfd; 107 | struct sockaddr_storage ss; 108 | socklen_t slen; 109 | sfd = socket(af == AF_INET ? PF_INET : PF_INET6, type, 0); 110 | if (sfd == -1) 111 | err(1, "socket"); 112 | 113 | p = htons(p); 114 | memset(&ss, 0, sizeof(ss)); 115 | if (af == AF_INET) { 116 | struct sockaddr_in *s = (void *)&ss; 117 | s->sin_family = AF_INET; 118 | slen = sizeof(*s); 119 | s->sin_port = p; 120 | } else { 121 | struct sockaddr_in6 *s6 = (void *)&ss; 122 | s6->sin6_family = AF_INET6; 123 | slen = sizeof(*s6); 124 | s6->sin6_port = p; 125 | } 126 | #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 127 | ss.ss_len = (uint8_t)slen; 128 | #endif 129 | 130 | if (bind(sfd, (const void *)&ss, slen) == -1) 131 | err(1, "bind"); 132 | 133 | if (type != SOCK_DGRAM) 134 | if (listen(sfd, 5) == -1) 135 | err(1, "listen"); 136 | return sfd; 137 | } 138 | 139 | static void 140 | handle(int type, int sfd) 141 | { 142 | struct sockaddr_storage ss; 143 | socklen_t alen = sizeof(ss); 144 | int afd; 145 | 146 | if (type != SOCK_DGRAM) { 147 | if ((afd = accept(sfd, (void *)&ss, &alen)) == -1) 148 | err(1, "accept"); 149 | } else 150 | afd = sfd; 151 | 152 | /* Create child process */ 153 | switch (fork()) { 154 | case -1: 155 | err(1, "fork"); 156 | case 0: 157 | if (type == SOCK_DGRAM) 158 | process_udp(afd); 159 | else 160 | process_tcp(afd); 161 | break; 162 | default: 163 | close(afd); 164 | break; 165 | } 166 | } 167 | 168 | static __dead void 169 | usage(int c) 170 | { 171 | warnx("Unknown option `%c'", (char)c); 172 | fprintf(stderr, "Usage: %s [-u] [-p ]" 173 | #ifdef BLDEBUG 174 | " [-s ]" 175 | #endif 176 | "\n", getprogname()); 177 | exit(EXIT_FAILURE); 178 | } 179 | 180 | int 181 | main(int argc, char *argv[]) 182 | { 183 | #ifdef __linux__ 184 | #define NUMFD 1 185 | #else 186 | #define NUMFD 2 187 | #endif 188 | struct pollfd pfd[NUMFD]; 189 | int type = SOCK_STREAM, c; 190 | in_port_t port = 6161; 191 | #ifdef BLDEBUG 192 | char *sockpath = "blsock"; 193 | const char *optstr = "up:s:"; 194 | #else 195 | const char *optstr = "up:"; 196 | #endif 197 | 198 | signal(SIGCHLD, SIG_IGN); 199 | 200 | while ((c = getopt(argc, argv, optstr)) != -1) 201 | switch (c) { 202 | case 'u': 203 | type = SOCK_DGRAM; 204 | break; 205 | case 'p': 206 | port = (in_port_t)atoi(optarg); 207 | break; 208 | #ifdef BLDEBUG 209 | case 's': 210 | sockpath = (char *)optarg; 211 | break; 212 | #endif 213 | default: 214 | usage(c); 215 | } 216 | 217 | #ifdef BLDEBUG 218 | b = bl_create(false, sockpath, vsyslog_r); 219 | #endif 220 | 221 | 222 | pfd[0].fd = cr(AF_INET, type, port); 223 | pfd[0].events = POLLIN; 224 | #if NUMFD > 1 225 | pfd[1].fd = cr(AF_INET6, type, port); 226 | pfd[1].events = POLLIN; 227 | #endif 228 | 229 | for (;;) { 230 | if (poll(pfd, __arraycount(pfd), INFTIM) == -1) 231 | err(1, "poll"); 232 | for (size_t i = 0; i < __arraycount(pfd); i++) { 233 | if ((pfd[i].revents & POLLIN) == 0) 234 | continue; 235 | handle(type, pfd[i].fd); 236 | } 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /port/fparseln.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: fparseln.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1997 Christos Zoulas. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | #ifdef HAVE_CONFIG_H 27 | #include "config.h" 28 | #endif 29 | 30 | #ifdef HAVE_SYS_CDEFS_H 31 | #include 32 | #endif 33 | #if defined(LIBC_SCCS) && !defined(lint) 34 | __RCSID("$NetBSD: fparseln.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); 35 | #endif /* LIBC_SCCS and not lint */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #if ! HAVE_FPARSELN || BROKEN_FPARSELN 44 | 45 | #define FLOCKFILE(fp) 46 | #define FUNLOCKFILE(fp) 47 | 48 | #if defined(_REENTRANT) && !HAVE_NBTOOL_CONFIG_H 49 | #define __fgetln(f, l) __fgetstr(f, l, '\n') 50 | #else 51 | #define __fgetln(f, l) fgetln(f, l) 52 | #endif 53 | 54 | static int isescaped(const char *, const char *, int); 55 | 56 | /* isescaped(): 57 | * Return true if the character in *p that belongs to a string 58 | * that starts in *sp, is escaped by the escape character esc. 59 | */ 60 | static int 61 | isescaped(const char *sp, const char *p, int esc) 62 | { 63 | const char *cp; 64 | size_t ne; 65 | 66 | /* No escape character */ 67 | if (esc == '\0') 68 | return 0; 69 | 70 | /* Count the number of escape characters that precede ours */ 71 | for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++) 72 | continue; 73 | 74 | /* Return true if odd number of escape characters */ 75 | return (ne & 1) != 0; 76 | } 77 | 78 | 79 | /* fparseln(): 80 | * Read a line from a file parsing continuations ending in \ 81 | * and eliminating trailing newlines, or comments starting with 82 | * the comment char. 83 | */ 84 | char * 85 | fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags) 86 | { 87 | static const char dstr[3] = { '\\', '\\', '#' }; 88 | 89 | size_t s, len; 90 | char *buf; 91 | char *ptr, *cp; 92 | int cnt; 93 | char esc, con, nl, com; 94 | 95 | len = 0; 96 | buf = NULL; 97 | cnt = 1; 98 | 99 | if (str == NULL) 100 | str = dstr; 101 | 102 | esc = str[0]; 103 | con = str[1]; 104 | com = str[2]; 105 | /* 106 | * XXX: it would be cool to be able to specify the newline character, 107 | * but unfortunately, fgetln does not let us 108 | */ 109 | nl = '\n'; 110 | 111 | FLOCKFILE(fp); 112 | 113 | while (cnt) { 114 | cnt = 0; 115 | 116 | if (lineno) 117 | (*lineno)++; 118 | 119 | if ((ptr = __fgetln(fp, &s)) == NULL) 120 | break; 121 | 122 | if (s && com) { /* Check and eliminate comments */ 123 | for (cp = ptr; cp < ptr + s; cp++) 124 | if (*cp == com && !isescaped(ptr, cp, esc)) { 125 | s = cp - ptr; 126 | cnt = s == 0 && buf == NULL; 127 | break; 128 | } 129 | } 130 | 131 | if (s && nl) { /* Check and eliminate newlines */ 132 | cp = &ptr[s - 1]; 133 | 134 | if (*cp == nl) 135 | s--; /* forget newline */ 136 | } 137 | 138 | if (s && con) { /* Check and eliminate continuations */ 139 | cp = &ptr[s - 1]; 140 | 141 | if (*cp == con && !isescaped(ptr, cp, esc)) { 142 | s--; /* forget continuation char */ 143 | cnt = 1; 144 | } 145 | } 146 | 147 | if (s == 0) { 148 | /* 149 | * nothing to add, skip realloc except in case 150 | * we need a minimal buf to return an empty line 151 | */ 152 | if (cnt || buf != NULL) 153 | continue; 154 | } 155 | 156 | if ((cp = realloc(buf, len + s + 1)) == NULL) { 157 | FUNLOCKFILE(fp); 158 | free(buf); 159 | return NULL; 160 | } 161 | buf = cp; 162 | 163 | (void) memcpy(buf + len, ptr, s); 164 | len += s; 165 | buf[len] = '\0'; 166 | } 167 | 168 | FUNLOCKFILE(fp); 169 | 170 | if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL && 171 | strchr(buf, esc) != NULL) { 172 | ptr = cp = buf; 173 | while (cp[0] != '\0') { 174 | int skipesc; 175 | 176 | while (cp[0] != '\0' && cp[0] != esc) 177 | *ptr++ = *cp++; 178 | if (cp[0] == '\0' || cp[1] == '\0') 179 | break; 180 | 181 | skipesc = 0; 182 | if (cp[1] == com) 183 | skipesc += (flags & FPARSELN_UNESCCOMM); 184 | if (cp[1] == con) 185 | skipesc += (flags & FPARSELN_UNESCCONT); 186 | if (cp[1] == esc) 187 | skipesc += (flags & FPARSELN_UNESCESC); 188 | if (cp[1] != com && cp[1] != con && cp[1] != esc) 189 | skipesc = (flags & FPARSELN_UNESCREST); 190 | 191 | if (skipesc) 192 | cp++; 193 | else 194 | *ptr++ = *cp++; 195 | *ptr++ = *cp++; 196 | } 197 | *ptr = '\0'; 198 | len = strlen(buf); 199 | } 200 | 201 | if (size) 202 | *size = len; 203 | return buf; 204 | } 205 | 206 | #ifdef TEST 207 | 208 | int main(int, char **); 209 | 210 | int 211 | main(int argc, char **argv) 212 | { 213 | char *ptr; 214 | size_t size, line; 215 | 216 | line = 0; 217 | while ((ptr = fparseln(stdin, &size, &line, NULL, 218 | FPARSELN_UNESCALL)) != NULL) 219 | printf("line %d (%d) |%s|\n", line, size, ptr); 220 | return 0; 221 | } 222 | 223 | /* 224 | 225 | # This is a test 226 | line 1 227 | line 2 \ 228 | line 3 # Comment 229 | line 4 \# Not comment \\\\ 230 | 231 | # And a comment \ 232 | line 5 \\\ 233 | line 6 234 | 235 | */ 236 | 237 | #endif /* TEST */ 238 | #endif /* ! HAVE_FPARSELN || BROKEN_FPARSELN */ 239 | -------------------------------------------------------------------------------- /bin/blocklistd.conf.5: -------------------------------------------------------------------------------- 1 | .\" $NetBSD: blocklistd.conf.5,v 1.7 2025/02/11 17:47:05 christos Exp $ 2 | .\" 3 | .\" Copyright (c) 2015, 2025 The NetBSD Foundation, Inc. 4 | .\" All rights reserved. 5 | .\" 6 | .\" This code is derived from software contributed to The NetBSD Foundation 7 | .\" by Christos Zoulas. 8 | .\" 9 | .\" Redistribution and use in source and binary forms, with or without 10 | .\" modification, are permitted provided that the following conditions 11 | .\" are met: 12 | .\" 1. Redistributions of source code must retain the above copyright 13 | .\" notice, this list of conditions and the following disclaimer. 14 | .\" 2. Redistributions in binary form must reproduce the above copyright 15 | .\" notice, this list of conditions and the following disclaimer in the 16 | .\" documentation and/or other materials provided with the distribution. 17 | .\" 18 | .\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 | .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | .\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 | .\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 | .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | .\" POSSIBILITY OF SUCH DAMAGE. 29 | .\" 30 | .Dd February 5, 2025 31 | .Dt BLOCKLISTD.CONF 5 32 | .Os 33 | .Sh NAME 34 | .Nm blocklistd.conf 35 | .Nd configuration file format for blocklistd 36 | .Sh DESCRIPTION 37 | The 38 | .Nm 39 | file contains configuration entries for 40 | .Xr blocklistd 8 41 | in a fashion similar to 42 | .Xr inetd.conf 5 . 43 | Only one entry per line is permitted. 44 | Every entry must have all fields populated. 45 | Each field can be separated by a tab or a space. 46 | Comments are denoted by a 47 | .Dq # 48 | at the beginning of a line. 49 | .Pp 50 | There are two kinds of configuration lines, 51 | .Va [local] 52 | and 53 | .Va [remote] . 54 | By default, configuration lines are 55 | .Va [local] , 56 | i.e. the address specified refers to the addresses on the local machine. 57 | To switch to between 58 | .Va [local] 59 | and 60 | .Va [remote] 61 | configuration lines you can specify the stanzas: 62 | .Dq [local] 63 | and 64 | .Dq [remote] . 65 | .Pp 66 | On 67 | .Va [local] 68 | and 69 | .Va [remote] 70 | lines 71 | .Dq * 72 | means use the default, or wildcard match. 73 | In addition, for 74 | .Va [remote] 75 | lines 76 | .Dq = 77 | means use the values from the matched 78 | .Va [local] 79 | configuration line. 80 | .Pp 81 | The first four fields, 82 | .Va location , 83 | .Va type , 84 | .Va proto , 85 | and 86 | .Va owner 87 | are used to match the 88 | .Va [local] 89 | or 90 | .Va [remote] 91 | addresses, whereas the last 3 fields 92 | .Va name , 93 | .Va nfail , 94 | and 95 | .Va disable 96 | are used to modify the filtering action. 97 | .Pp 98 | The first field denotes the 99 | .Va location 100 | as an address, mask, and port. 101 | The syntax for the 102 | .Va location 103 | is: 104 | .Bd -literal -offset indent 105 | [
|][/][:] 106 | .Ed 107 | .Pp 108 | The 109 | .Dv address 110 | can be an IPv4 address in numeric format, an IPv6 address 111 | in numeric format and enclosed by square brackets, or an interface name. 112 | Mask modifiers are not allowed on interfaces because interfaces 113 | can have multiple addresses in different protocols where the mask has a 114 | different size. 115 | .Pp 116 | The 117 | .Dv mask 118 | is always numeric, but the 119 | .Dv port 120 | can be either numeric or symbolic. 121 | .Pp 122 | The second field is the socket 123 | .Va type : 124 | .Dv stream , 125 | .Dv dgram , 126 | or numeric. 127 | The third field is the 128 | .Va protocol : 129 | .Dv tcp , 130 | .Dv udp , 131 | .Dv tcp6 , 132 | .Dv udp6 , 133 | or numeric. 134 | The fourth field is the effective user 135 | .Va ( owner ) 136 | of the daemon process reporting the event, 137 | either as a username or a userid. 138 | .Pp 139 | The rest of the fields control the behavior of the filter. 140 | .Pp 141 | The 142 | .Va name 143 | field, is the name of the packet filter rule to be used. 144 | If the 145 | .Va name 146 | starts with a hyphen 147 | .Pq Dq - , 148 | then the default rulename is prepended to the given name. 149 | If the 150 | .Dv name 151 | contains a 152 | .Dq / , 153 | the remaining portion of the name is interpreted as the mask to be 154 | applied to the address specified in the rule, causing a single rule violation to 155 | block the entire subnet for the configured prefix. 156 | .Pp 157 | The 158 | .Va nfail 159 | field contains the number of failed attempts before access is blocked, 160 | defaulting to 161 | .Dq * 162 | meaning never, and the last field 163 | .Va duration 164 | specifies the amount of time since the last access that the blocking 165 | rule should be active, defaulting to 166 | .Dq * 167 | meaning forever. 168 | The default unit for 169 | .Va duration 170 | is seconds, but one can specify suffixes for different units, such as 171 | .Dq m 172 | for minutes 173 | .Dq h 174 | for hours and 175 | .Dq d 176 | for days. 177 | .Pp 178 | Matching is done first by checking the 179 | .Va [local] 180 | rules individually, in the order of the most specific to the least specific. 181 | If a match is found, then the matching 182 | .Va [remote] 183 | rules are applied. 184 | The 185 | .Va name , 186 | .Va nfail , 187 | and 188 | .Va duration 189 | fields can be altered by the 190 | .Va [remote] 191 | rule that matched. 192 | .Pp 193 | The 194 | .Va [remote] 195 | rules can be used for allowing specific addresses, changing the mask 196 | size (via 197 | .Va name ) , 198 | the rule that the packet filter uses (also via 199 | .Va name ) , 200 | the number of failed attempts (via 201 | .Va nfail ) , 202 | or the duration to block (via 203 | .Va duration ) . 204 | .Sh FILES 205 | .Bl -tag -width /etc/blocklistd.conf -compact 206 | .It Pa /etc/blocklistd.conf 207 | Configuration file. 208 | .El 209 | .Sh EXAMPLES 210 | .Bd -literal -offset 8n 211 | # Block ssh, after 3 attempts for 6 hours on the bnx0 interface 212 | [local] 213 | # location type proto owner name nfail duration 214 | bnx0:ssh * * * * 3 6h 215 | [remote] 216 | # Never block 1.2.3.4 217 | 1.2.3.4:ssh * * * * * * 218 | # Never block the example IPv6 subnet either 219 | [2001:db8::]/32:ssh * * * * * * 220 | # For addresses coming from 8.8.0.0/16 block whole /24 networks instead 221 | # individual hosts, but keep the rest of the blocking parameters the same. 222 | 8.8.0.0/16:ssh * * * /24 = = 223 | .Ed 224 | .Sh SEE ALSO 225 | .Xr blocklistctl 8 , 226 | .Xr blocklistd 8 227 | .Sh HISTORY 228 | .Nm 229 | first appeared in 230 | .Nx 7 . 231 | .Fx 232 | support for 233 | .Nm 234 | was implemented in 235 | .Fx 11 . 236 | .Sh AUTHORS 237 | .An Christos Zoulas 238 | -------------------------------------------------------------------------------- /diff/named.diff: -------------------------------------------------------------------------------- 1 | --- /dev/null 2015-01-22 01:48:00.000000000 -0500 2 | +++ dist/bin/named/pfilter.c 2015-01-22 01:35:16.000000000 -0500 3 | @@ -0,0 +1,42 @@ 4 | +#include 5 | + 6 | +#include 7 | +#include 8 | +#include 9 | +#include 10 | + 11 | +#include 12 | + 13 | +#include "pfilter.h" 14 | + 15 | +static struct blocklist *blstate; 16 | + 17 | +void 18 | +pfilter_open(void) 19 | +{ 20 | + if (blstate == NULL) 21 | + blstate = blocklist_open(); 22 | +} 23 | + 24 | +#define TCP_CLIENT(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0) 25 | + 26 | +void 27 | +pfilter_notify(isc_result_t res, ns_client_t *client, const char *msg) 28 | +{ 29 | + isc_socket_t *socket; 30 | + 31 | + pfilter_open(); 32 | + 33 | + if (TCP_CLIENT(client)) 34 | + socket = client->tcpsocket; 35 | + else { 36 | + socket = client->udpsocket; 37 | + if (!client->peeraddr_valid) 38 | + return; 39 | + } 40 | + if (socket == NULL) 41 | + return; 42 | + blocklist_sa_r(blstate, 43 | + res != ISC_R_SUCCESS, isc_socket_getfd(socket), 44 | + &client->peeraddr.type.sa, client->peeraddr.length, msg); 45 | +} 46 | --- /dev/null 2015-01-22 01:48:00.000000000 -0500 47 | +++ dist/bin/named/pfilter.h 2015-01-22 01:16:56.000000000 -0500 48 | @@ -0,0 +1,2 @@ 49 | +void pfilter_open(void); 50 | +void pfilter_notify(isc_result_t, ns_client_t *, const char *); 51 | Index: bin/named/Makefile 52 | =================================================================== 53 | RCS file: /cvsroot/src/external/bsd/bind/bin/named/Makefile,v 54 | retrieving revision 1.8 55 | diff -u -u -r1.8 Makefile 56 | --- bin/named/Makefile 31 Dec 2013 20:23:12 -0000 1.8 57 | +++ bin/named/Makefile 23 Jan 2015 21:37:09 -0000 58 | @@ -33,7 +33,9 @@ 59 | lwaddr.c lwdclient.c lwderror.c \ 60 | lwdgabn.c lwdgnba.c lwdgrbn.c lwdnoop.c lwresd.c lwsearch.c \ 61 | main.c notify.c query.c server.c sortlist.c statschannel.c \ 62 | - tkeyconf.c tsigconf.c \ 63 | + pfilter.c tkeyconf.c tsigconf.c \ 64 | update.c xfrout.c zoneconf.c ${SRCS_UNIX} 65 | 66 | +LDADD+=-lblocklist 67 | +DPADD+=${LIBBLOCKLIST} 68 | .include 69 | Index: dist/bin/named/client.c 70 | =================================================================== 71 | RCS file: /cvsroot/src/external/bsd/bind/dist/bin/named/client.c,v 72 | retrieving revision 1.11 73 | diff -u -u -r1.11 client.c 74 | --- dist/bin/named/client.c 10 Dec 2014 04:37:51 -0000 1.11 75 | +++ dist/bin/named/client.c 23 Jan 2015 21:37:09 -0000 76 | @@ -65,6 +65,8 @@ 77 | #include 78 | #include 79 | 80 | +#include "pfilter.h" 81 | + 82 | /*** 83 | *** Client 84 | ***/ 85 | @@ -3101,6 +3103,7 @@ 86 | result = ns_client_checkaclsilent(client, sockaddr ? &netaddr : NULL, 87 | acl, default_allow); 88 | 89 | + pfilter_notify(result, client, opname); 90 | if (result == ISC_R_SUCCESS) 91 | ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 92 | NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), 93 | Index: dist/bin/named/main.c 94 | =================================================================== 95 | RCS file: /cvsroot/src/external/bsd/bind/dist/bin/named/main.c,v 96 | retrieving revision 1.15 97 | diff -u -u -r1.15 main.c 98 | --- dist/bin/named/main.c 10 Dec 2014 04:37:51 -0000 1.15 99 | +++ dist/bin/named/main.c 23 Jan 2015 21:37:09 -0000 100 | @@ -83,6 +83,9 @@ 101 | #ifdef HAVE_LIBXML2 102 | #include 103 | #endif 104 | + 105 | +#include "pfilter.h" 106 | + 107 | /* 108 | * Include header files for database drivers here. 109 | */ 110 | @@ -1206,6 +1209,8 @@ 111 | 112 | parse_command_line(argc, argv); 113 | 114 | + pfilter_open(); 115 | + 116 | /* 117 | * Warn about common configuration error. 118 | */ 119 | Index: dist/bin/named/query.c 120 | =================================================================== 121 | RCS file: /cvsroot/src/external/bsd/bind/dist/bin/named/query.c,v 122 | retrieving revision 1.17 123 | diff -u -u -r1.17 query.c 124 | --- dist/bin/named/query.c 10 Dec 2014 04:37:52 -0000 1.17 125 | +++ dist/bin/named/query.c 23 Jan 2015 21:37:09 -0000 126 | @@ -65,6 +65,8 @@ 127 | #include 128 | #include 129 | 130 | +#include "pfilter.h" 131 | + 132 | #if 0 133 | /* 134 | * It has been recommended that DNS64 be changed to return excluded 135 | @@ -762,6 +764,8 @@ 136 | } 137 | 138 | result = ns_client_checkaclsilent(client, NULL, queryacl, ISC_TRUE); 139 | + if (result != ISC_R_SUCCESS) 140 | + pfilter_notify(result, client, "validatezonedb"); 141 | if ((options & DNS_GETDB_NOLOG) == 0) { 142 | char msg[NS_CLIENT_ACLMSGSIZE("query")]; 143 | if (result == ISC_R_SUCCESS) { 144 | @@ -1026,6 +1030,8 @@ 145 | result = ns_client_checkaclsilent(client, NULL, 146 | client->view->cacheacl, 147 | ISC_TRUE); 148 | + if (result == ISC_R_SUCCESS) 149 | + pfilter_notify(result, client, "cachedb"); 150 | if (result == ISC_R_SUCCESS) { 151 | /* 152 | * We were allowed by the "allow-query-cache" ACL. 153 | Index: dist/bin/named/update.c 154 | =================================================================== 155 | RCS file: /cvsroot/src/external/bsd/bind/dist/bin/named/update.c,v 156 | retrieving revision 1.9 157 | diff -u -u -r1.9 update.c 158 | --- dist/bin/named/update.c 10 Dec 2014 04:37:52 -0000 1.9 159 | +++ dist/bin/named/update.c 23 Jan 2015 21:37:09 -0000 160 | @@ -59,6 +59,8 @@ 161 | #include 162 | #include 163 | 164 | +#include "pfilter.h" 165 | + 166 | /*! \file 167 | * \brief 168 | * This module implements dynamic update as in RFC2136. 169 | @@ -307,6 +309,7 @@ 170 | 171 | result = ns_client_checkaclsilent(client, NULL, queryacl, ISC_TRUE); 172 | if (result != ISC_R_SUCCESS) { 173 | + pfilter_notify(result, client, "queryacl"); 174 | dns_name_format(zonename, namebuf, sizeof(namebuf)); 175 | dns_rdataclass_format(client->view->rdclass, classbuf, 176 | sizeof(classbuf)); 177 | @@ -324,6 +327,7 @@ 178 | sizeof(classbuf)); 179 | 180 | result = DNS_R_REFUSED; 181 | + pfilter_notify(result, client, "updateacl"); 182 | ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, 183 | NS_LOGMODULE_UPDATE, ISC_LOG_INFO, 184 | "update '%s/%s' denied", namebuf, classbuf); 185 | @@ -362,6 +366,7 @@ 186 | msg = "disabled"; 187 | } else { 188 | result = ns_client_checkaclsilent(client, NULL, acl, ISC_FALSE); 189 | + pfilter_notify(result, client, "updateacl"); 190 | if (result == ISC_R_SUCCESS) { 191 | level = ISC_LOG_DEBUG(3); 192 | msg = "approved"; 193 | Index: dist/bin/named/xfrout.c 194 | =================================================================== 195 | RCS file: /cvsroot/src/external/bsd/bind/dist/bin/named/xfrout.c,v 196 | retrieving revision 1.7 197 | diff -u -u -r1.7 xfrout.c 198 | --- dist/bin/named/xfrout.c 10 Dec 2014 04:37:52 -0000 1.7 199 | +++ dist/bin/named/xfrout.c 23 Jan 2015 21:37:09 -0000 200 | @@ -54,6 +54,8 @@ 201 | #include 202 | #include 203 | 204 | +#include "pfilter.h" 205 | + 206 | /*! \file 207 | * \brief 208 | * Outgoing AXFR and IXFR. 209 | @@ -822,6 +824,7 @@ 210 | &client->peeraddr, 211 | &db); 212 | 213 | + pfilter_notify(result, client, "zonexfr"); 214 | if (result == ISC_R_NOPERM) { 215 | char _buf1[DNS_NAME_FORMATSIZE]; 216 | char _buf2[DNS_RDATACLASS_FORMATSIZE]; 217 | -------------------------------------------------------------------------------- /port/popenve.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: popenve.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1988, 1993 5 | * The Regents of the University of California. All rights reserved. 6 | * 7 | * This code is derived from software written by Ken Arnold and 8 | * published in UNIX Review, Vol. 6, No. 8. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 3. Neither the name of the University nor the names of its contributors 19 | * may be used to endorse or promote products derived from this software 20 | * without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 | * SUCH DAMAGE. 33 | */ 34 | 35 | #ifdef HAVE_CONFIG_H 36 | #include "config.h" 37 | #endif 38 | 39 | #ifdef HAVE_SYS_CDEFS_H 40 | #include 41 | #endif 42 | #if defined(LIBC_SCCS) && !defined(lint) 43 | #if 0 44 | static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95"; 45 | #else 46 | __RCSID("$NetBSD: popenve.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); 47 | #endif 48 | #endif /* LIBC_SCCS and not lint */ 49 | 50 | #include 51 | #include 52 | #include 53 | 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | 64 | #ifdef __weak_alias 65 | __weak_alias(popen,_popen) 66 | __weak_alias(pclose,_pclose) 67 | #endif 68 | 69 | static struct pid { 70 | struct pid *next; 71 | FILE *fp; 72 | #ifdef _REENTRANT 73 | int fd; 74 | #endif 75 | pid_t pid; 76 | } *pidlist; 77 | 78 | #ifdef _REENTRANT 79 | static rwlock_t pidlist_lock = RWLOCK_INITIALIZER; 80 | #endif 81 | 82 | static struct pid * 83 | pdes_get(int *pdes, const char **type) 84 | { 85 | struct pid *cur; 86 | int flags = strchr(*type, 'e') ? O_CLOEXEC : 0; 87 | int serrno; 88 | 89 | if (strchr(*type, '+')) { 90 | #ifndef SOCK_CLOEXEC 91 | #define SOCK_CLOEXEC 0 92 | #endif 93 | int stype = flags ? (SOCK_STREAM | SOCK_CLOEXEC) : SOCK_STREAM; 94 | *type = "r+"; 95 | if (socketpair(AF_LOCAL, stype, 0, pdes) < 0) 96 | return NULL; 97 | #if SOCK_CLOEXEC == 0 98 | fcntl(pdes[0], F_SETFD, FD_CLOEXEC); 99 | fcntl(pdes[1], F_SETFD, FD_CLOEXEC); 100 | #endif 101 | } else { 102 | *type = strrchr(*type, 'r') ? "r" : "w"; 103 | #if SOCK_CLOEXEC != 0 104 | if (pipe2(pdes, flags) == -1) 105 | return NULL; 106 | #else 107 | if (pipe(pdes) == -1) 108 | return NULL; 109 | fcntl(pdes[0], F_SETFL, fcntl(pdes[0], F_GETFL) | flags); 110 | fcntl(pdes[1], F_SETFL, fcntl(pdes[1], F_GETFL) | flags); 111 | #endif 112 | } 113 | 114 | if ((cur = malloc(sizeof(*cur))) != NULL) 115 | return cur; 116 | serrno = errno; 117 | (void)close(pdes[0]); 118 | (void)close(pdes[1]); 119 | errno = serrno; 120 | return NULL; 121 | } 122 | 123 | static void 124 | pdes_child(int *pdes, const char *type) 125 | { 126 | struct pid *old; 127 | 128 | /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams 129 | from previous popen() calls that remain open in the 130 | parent process are closed in the new child process. */ 131 | for (old = pidlist; old; old = old->next) 132 | #ifdef _REENTRANT 133 | (void)close(old->fd); /* don't allow a flush */ 134 | #else 135 | (void)close(fileno(old->fp)); /* don't allow a flush */ 136 | #endif 137 | 138 | if (type[0] == 'r') { 139 | (void)close(pdes[0]); 140 | if (pdes[1] != STDOUT_FILENO) { 141 | (void)dup2(pdes[1], STDOUT_FILENO); 142 | (void)close(pdes[1]); 143 | } 144 | if (type[1] == '+') 145 | (void)dup2(STDOUT_FILENO, STDIN_FILENO); 146 | } else { 147 | (void)close(pdes[1]); 148 | if (pdes[0] != STDIN_FILENO) { 149 | (void)dup2(pdes[0], STDIN_FILENO); 150 | (void)close(pdes[0]); 151 | } 152 | } 153 | } 154 | 155 | static void 156 | pdes_parent(int *pdes, struct pid *cur, pid_t pid, const char *type) 157 | { 158 | FILE *iop; 159 | 160 | /* Parent; assume fdopen can't fail. */ 161 | if (*type == 'r') { 162 | iop = fdopen(pdes[0], type); 163 | #ifdef _REENTRANT 164 | cur->fd = pdes[0]; 165 | #endif 166 | (void)close(pdes[1]); 167 | } else { 168 | iop = fdopen(pdes[1], type); 169 | #ifdef _REENTRANT 170 | cur->fd = pdes[1]; 171 | #endif 172 | (void)close(pdes[0]); 173 | } 174 | 175 | /* Link into list of file descriptors. */ 176 | cur->fp = iop; 177 | cur->pid = pid; 178 | cur->next = pidlist; 179 | pidlist = cur; 180 | } 181 | 182 | static void 183 | pdes_error(int *pdes, struct pid *cur) 184 | { 185 | free(cur); 186 | (void)close(pdes[0]); 187 | (void)close(pdes[1]); 188 | } 189 | 190 | FILE * 191 | popenve(const char *cmd, char *const *argv, char *const *envp, const char *type) 192 | { 193 | struct pid *cur; 194 | int pdes[2], serrno; 195 | pid_t pid; 196 | 197 | if ((cur = pdes_get(pdes, &type)) == NULL) 198 | return NULL; 199 | 200 | #ifdef _REENTRANT 201 | (void)rwlock_rdlock(&pidlist_lock); 202 | #endif 203 | switch (pid = vfork()) { 204 | case -1: /* Error. */ 205 | serrno = errno; 206 | #ifdef _REENTRANT 207 | (void)rwlock_unlock(&pidlist_lock); 208 | #endif 209 | pdes_error(pdes, cur); 210 | errno = serrno; 211 | return NULL; 212 | /* NOTREACHED */ 213 | case 0: /* Child. */ 214 | pdes_child(pdes, type); 215 | execve(cmd, argv, envp); 216 | _exit(127); 217 | /* NOTREACHED */ 218 | } 219 | 220 | pdes_parent(pdes, cur, pid, type); 221 | 222 | #ifdef _REENTRANT 223 | (void)rwlock_unlock(&pidlist_lock); 224 | #endif 225 | 226 | return cur->fp; 227 | } 228 | 229 | /* 230 | * pclose -- 231 | * Pclose returns -1 if stream is not associated with a `popened' command, 232 | * if already `pclosed', or waitpid returns an error. 233 | */ 234 | int 235 | pcloseve(FILE *iop) 236 | { 237 | struct pid *cur, *last; 238 | int pstat; 239 | pid_t pid; 240 | 241 | #ifdef _REENTRANT 242 | rwlock_wrlock(&pidlist_lock); 243 | #endif 244 | 245 | /* Find the appropriate file pointer. */ 246 | for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 247 | if (cur->fp == iop) 248 | break; 249 | if (cur == NULL) { 250 | #ifdef _REENTRANT 251 | (void)rwlock_unlock(&pidlist_lock); 252 | #endif 253 | errno = ESRCH; 254 | return -1; 255 | } 256 | 257 | (void)fclose(iop); 258 | 259 | /* Remove the entry from the linked list. */ 260 | if (last == NULL) 261 | pidlist = cur->next; 262 | else 263 | last->next = cur->next; 264 | 265 | #ifdef _REENTRANT 266 | (void)rwlock_unlock(&pidlist_lock); 267 | #endif 268 | 269 | do { 270 | pid = waitpid(cur->pid, &pstat, 0); 271 | } while (pid == -1 && errno == EINTR); 272 | 273 | free(cur); 274 | 275 | return pid == -1 ? -1 : pstat; 276 | } 277 | -------------------------------------------------------------------------------- /libexec/blocklistd-helper: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #echo "run $@" 1>&2 3 | #set -x 4 | # $1 command 5 | # $2 rulename 6 | # $3 protocol 7 | # $4 address 8 | # $5 mask 9 | # $6 port 10 | # $7 id 11 | 12 | pf= 13 | if [ -f "/etc/ipfw-blocklist.rc" ]; then 14 | pf="ipfw" 15 | . /etc/ipfw-blocklist.rc 16 | ipfw_offset=${ipfw_offset:-2000} 17 | fi 18 | 19 | if [ -z "$pf" ]; then 20 | for f in npf pf ipfilter ipfw; do 21 | if [ -x /etc/rc.d/$f ]; then 22 | if /etc/rc.d/$f status >/dev/null 2>&1; then 23 | pf="$f" 24 | break 25 | fi 26 | elif [ -f "/etc/$f.conf" ]; then 27 | # xxx assume a config file means it can be enabled -- 28 | # and the first one wins! 29 | pf="$f" 30 | break 31 | fi 32 | done 33 | fi 34 | 35 | if [ -z "$pf" -a -x "/sbin/iptables" ]; then 36 | pf="iptables" 37 | fi 38 | 39 | if [ -z "$pf" ]; then 40 | echo "$0: Unsupported packet filter" 1>&2 41 | exit 1 42 | fi 43 | 44 | flags= 45 | if [ -n "$3" ]; then 46 | raw_proto="$3" 47 | proto="proto $3" 48 | if [ $3 = "tcp" ]; then 49 | flags="flags S/SAFR" 50 | fi 51 | fi 52 | 53 | if [ -n "$6" ]; then 54 | raw_port="$6" 55 | port="port $6" 56 | fi 57 | 58 | addr="$4" 59 | mask="$5" 60 | case "$4" in 61 | ::ffff:*.*.*.*) 62 | if [ "$5" = 128 ]; then 63 | mask=32 64 | addr=${4#::ffff:} 65 | fi;; 66 | esac 67 | 68 | case "$1" in 69 | add) 70 | case "$pf" in 71 | ipfilter) 72 | # N.B.: If you reload /etc/ipf.conf then you need to stop and 73 | # restart blocklistd (and make sure blocklistd_flags="-r"). 74 | # This should normally already be implemented in 75 | # /etc/rc.d/ipfilter, but if then not add the following lines to 76 | # the end of the ipfilter_reload() function: 77 | # 78 | # if checkyesnox blocklistd; then 79 | # /etc/rc.d/blocklistd restart 80 | # fi 81 | # 82 | # XXX we assume the following rule is present in /etc/ipf.conf: 83 | # (should we check? -- it probably cannot be added dynamically) 84 | # 85 | # block in proto tcp/udp from any to any head blocklistd 86 | # 87 | # where "blocklistd" is the default rulename (i.e. "$2") 88 | # 89 | # This rule can come before any rule that logs connections, 90 | # etc., and should be followed by final rules such as: 91 | # 92 | # # log all as-yet unblocked incoming TCP connection 93 | # # attempts 94 | # log in proto tcp from any to any flags S/SAFR 95 | # # last "pass" match wins for all non-blocked packets 96 | # pass in all 97 | # pass out all 98 | # 99 | # I.e. a "pass" rule which will be the final match and override 100 | # the "block". This way the rules added by blocklistd will 101 | # actually block packets, and prevent logging of them as 102 | # connections, because they include the "quick" flag. 103 | # 104 | # N.b.: $port is not included/used in rules -- abusers are cut 105 | # off completely from all services! 106 | # 107 | # Note RST packets are not returned for blocked SYN packets of 108 | # active attacks, so the port will not appear to be closed. 109 | # This will probably give away the fact that a firewall has been 110 | # triggered to block connections, but it prevents generating 111 | # extra outbound traffic, and it may also slow down the attacker 112 | # somewhat. 113 | # 114 | # Note also that we don't block all packets, just new attempts 115 | # to open connections (see $flags above). This allows us to do 116 | # counterespionage against the attacker (or continue to make use 117 | # of any other services that might be on the same subnet as the 118 | # supposed attacker). However it does not kill any active 119 | # connections -- we rely on the reporting daemon to do its own 120 | # protection and cleanup. 121 | # 122 | # N.B.: The rule generated here must exactly match the 123 | # corresponding rule generated for the "rem" command below! 124 | # 125 | echo block in log quick $proto \ 126 | from $addr/$mask to any $flags group $2 | \ 127 | /sbin/ipf -A -f - >/dev/null 2>&1 && echo OK 128 | ;; 129 | 130 | ipfw) 131 | # use $ipfw_offset+$port for rule number 132 | rule=$(($ipfw_offset + $6)) 133 | tname="port$6" 134 | /sbin/ipfw table $tname create type addr 2>/dev/null 135 | /sbin/ipfw -q table $tname add "$addr/$mask" 136 | # if rule number $rule does not already exist, create it 137 | /sbin/ipfw show $rule >/dev/null 2>&1 || \ 138 | /sbin/ipfw add $rule drop $3 from \ 139 | table"("$tname")" to any dst-port $6 >/dev/null && \ 140 | echo OK 141 | ;; 142 | 143 | iptables) 144 | if ! /sbin/iptables --list "$2" >/dev/null 2>&1; then 145 | /sbin/iptables --new-chain "$2" 146 | fi 147 | /sbin/iptables --append INPUT --proto "$raw_proto" \ 148 | --dport "$raw_port" --jump "$2" 149 | /sbin/iptables --append "$2" --proto "$raw_proto" \ 150 | --source "$addr/$mask" --dport "$raw_port" --jump DROP 151 | echo OK 152 | ;; 153 | 154 | npf) 155 | /sbin/npfctl rule "$2" add block in final $proto from \ 156 | "$addr/$mask" to any $port 157 | ;; 158 | 159 | pf) 160 | # if the filtering rule does not exist, create it 161 | /sbin/pfctl -a "$2/$6" -sr 2>/dev/null | \ 162 | grep -q "" || \ 163 | echo "block in quick $proto from to any $port" | \ 164 | /sbin/pfctl -a "$2/$6" -f - 165 | # insert $ip/$mask into per-protocol/port anchored table 166 | /sbin/pfctl -qa "$2/$6" -t "port$6" -T add "$addr/$mask" && \ 167 | /sbin/pfctl -qk "$addr" && echo OK 168 | ;; 169 | 170 | esac 171 | ;; 172 | rem) 173 | case "$pf" in 174 | ipfilter) 175 | # N.B.: The rule generated here must exactly match the 176 | # corresponding rule generated for the "add" command above! 177 | # 178 | echo block in log quick $proto \ 179 | from $addr/$mask to any $flags group $2 | \ 180 | /sbin/ipf -A -r -f - >/dev/null 2>&1 && echo OK 181 | ;; 182 | 183 | ipfw) 184 | /sbin/ipfw table "port$6" delete "$addr/$mask" 2>/dev/null && \ 185 | echo OK 186 | ;; 187 | 188 | iptables) 189 | if /sbin/iptables --list "$2" >/dev/null 2>&1; then 190 | /sbin/iptables --delete "$2" --proto "$raw_proto" \ 191 | --source "$addr/$mask" --dport "$raw_port" \ 192 | --jump DROP 193 | fi 194 | echo OK 195 | ;; 196 | 197 | npf) 198 | /sbin/npfctl rule "$2" rem-id "$7" 199 | ;; 200 | 201 | pf) 202 | /sbin/pfctl -qa "$2/$6" -t "port$6" -T delete "$addr/$mask" && \ 203 | echo OK 204 | ;; 205 | 206 | esac 207 | ;; 208 | flush) 209 | case "$pf" in 210 | ipfilter) 211 | # 212 | # N.B. WARNING: This is obviously not reentrant! 213 | # 214 | # First we flush all the rules from the inactive set, then we 215 | # reload the ones that do not belong to the group "$2", and 216 | # finally we swap the active and inactive rule sets. 217 | # 218 | /sbin/ipf -I -F a 219 | # 220 | # "ipf -I -F a" also flushes active accounting rules! 221 | # 222 | # Note that accounting rule groups are unique to accounting 223 | # rules and have nothing to do with filter rules, though of 224 | # course theoretically one could use the same group name for 225 | # them too. 226 | # 227 | # In theory anyone using any such accounting rules should have a 228 | # wrapper /etc/rc.conf.d/blocklistd script (and corresponding 229 | # /etc/rc.conf.d/ipfilter script) that will record and 230 | # consolidate the values accumulated by such accounting rules 231 | # before they are flushed, since otherwise their counts will be 232 | # lost forever. 233 | # 234 | /usr/sbin/ipfstat -io | fgrep -v "group $2" | \ 235 | /sbin/ipf -I -f - >/dev/null 2>&1 236 | # 237 | # This MUST be done last and separately as "-s" is executed 238 | # _while_ the command arguments are being processed! 239 | # 240 | /sbin/ipf -s && echo OK 241 | ;; 242 | 243 | ipfw) 244 | /sbin/ipfw table "port$6" flush 2>/dev/null && echo OK 245 | ;; 246 | 247 | iptables) 248 | if /sbin/iptables --list "$2" >/dev/null 2>&1; then 249 | /sbin/iptables --flush "$2" 250 | fi 251 | echo OK 252 | ;; 253 | 254 | npf) 255 | /sbin/npfctl rule "$2" flush 256 | ;; 257 | 258 | pf) 259 | # dynamically determine which anchors exist 260 | for anchor in $(/sbin/pfctl -a "$2" -s Anchors 2> /dev/null); do 261 | /sbin/pfctl -a "$anchor" -t "port${anchor##*/}" -T flush 262 | /sbin/pfctl -a "$anchor" -F rules 263 | done 264 | echo OK 265 | ;; 266 | esac 267 | ;; 268 | *) 269 | echo "$0: Unknown command '$1'" 1>&2 270 | exit 1 271 | ;; 272 | esac 273 | -------------------------------------------------------------------------------- /bin/blocklistd.8: -------------------------------------------------------------------------------- 1 | .\" $NetBSD: blocklistd.8,v 1.8 2025/02/25 22:13:34 christos Exp $ 2 | .\" 3 | .\" Copyright (c) 2015 The NetBSD Foundation, Inc. 4 | .\" All rights reserved. 5 | .\" 6 | .\" This code is derived from software contributed to The NetBSD Foundation 7 | .\" by Christos Zoulas. 8 | .\" 9 | .\" Redistribution and use in source and binary forms, with or without 10 | .\" modification, are permitted provided that the following conditions 11 | .\" are met: 12 | .\" 1. Redistributions of source code must retain the above copyright 13 | .\" notice, this list of conditions and the following disclaimer. 14 | .\" 2. Redistributions in binary form must reproduce the above copyright 15 | .\" notice, this list of conditions and the following disclaimer in the 16 | .\" documentation and/or other materials provided with the distribution. 17 | .\" 18 | .\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 | .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | .\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 | .\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 | .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | .\" POSSIBILITY OF SUCH DAMAGE. 29 | .\" 30 | .Dd February 25, 2025 31 | .Dt BLOCKLISTD 8 32 | .Os 33 | .Sh NAME 34 | .Nm blocklistd 35 | .Nd block and release ports on demand to avoid DoS abuse 36 | .Sh SYNOPSIS 37 | .Nm 38 | .Op Fl dfrv 39 | .Op Fl C Ar controlprog 40 | .Op Fl c Ar configfile 41 | .Op Fl D Ar dbfile 42 | .Op Fl P Ar sockpathsfile 43 | .Op Fl R Ar rulename 44 | .Op Fl s Ar sockpath 45 | .Op Fl t Ar timeout 46 | .Sh DESCRIPTION 47 | .Nm 48 | is a daemon similar to 49 | .Xr syslogd 8 50 | that listens to sockets at paths specified in the 51 | .Ar sockpathsfile 52 | for notifications from other daemons about successful or failed connection 53 | attempts. 54 | If no such file is specified, then it only listens to the socket path 55 | specified by 56 | .Ar sockpath 57 | or if that is not specified to 58 | .Pa /var/run/blocklistd.sock . 59 | Each notification contains an (action, port, protocol, address, owner) tuple 60 | that identifies the remote connection and the action. 61 | This tuple is consulted against entries from the 62 | .Ar configfile , 63 | with the syntax specified in 64 | .Xr blocklistd.conf 5 . 65 | If an entry is matched, a state entry is created for that tuple. 66 | Each entry contains a number of tries limit and a duration. 67 | .Pp 68 | If 69 | .Ar configfile 70 | is a directory, or a directory exists with the same name as 71 | .Ar configfile 72 | with 73 | .Qq .d 74 | appended to it, each file in the directory will be read as configuration file. 75 | If 76 | .Ar configfile 77 | exists as a file it will be processed before the contents of the 78 | .Ar configfile Ns .d 79 | directory if that also exists. 80 | .Pp 81 | The way 82 | .Nm 83 | does configuration entry matching is by having the client side pass the 84 | file descriptor associated with the connection the client wants to blocklist 85 | as well as passing socket credentials. 86 | .Pp 87 | The file descriptor is used to retrieve information (address and port) 88 | about the remote side with 89 | .Xr getpeername 2 90 | and the local side with 91 | .Xr getsockname 2 . 92 | .Pp 93 | By examining the port of the local side, 94 | .Nm 95 | can determine if the client program 96 | .Dq owns 97 | the port. 98 | By examining the optional address portion on the local side, it can match 99 | interfaces. 100 | By examining the remote address, it can match specific allow or deny rules. 101 | .Pp 102 | Finally 103 | .Nm 104 | can examine the socket credentials to match the user in the configuration file. 105 | .Pp 106 | While this works well for TCP sockets, it cannot be relied on for unbound 107 | UDP sockets. 108 | It is also less meaningful when it comes to connections using non-privileged 109 | ports. 110 | On the other hand, if we receive a request that has a local endpoint indicating 111 | a UDP privileged port, we can presume that the client was privileged to be 112 | able to acquire that port. 113 | .Pp 114 | Once an entry is matched 115 | .Nm 116 | can perform various actions. 117 | If the action is 118 | .Dq add 119 | and the number of tries limit is reached, then a 120 | control script 121 | .Ar controlprog 122 | is invoked with arguments: 123 | .Bd -literal -offset indent 124 | control add
125 | .Ed 126 | .Pp 127 | and should invoke a packet filter command to block the connection 128 | specified by the arguments. 129 | The 130 | .Ar rulename 131 | argument can be set from the command line (default 132 | .Dv blocklistd ) . 133 | The script could print a numerical id to stdout as a handle for 134 | the rule that can be used later to remove that connection, but 135 | that is not required as all information to remove the rule is 136 | kept. 137 | .Pp 138 | If the action is 139 | .Dq rem 140 | Then the same control script is invoked as: 141 | .Bd -literal -offset indent 142 | control rem
143 | .Ed 144 | .Pp 145 | where 146 | .Ar id 147 | is the number returned from the 148 | .Dq add 149 | action. 150 | .Pp 151 | .Nm 152 | maintains a database of known connections in 153 | .Ar dbfile . 154 | On startup it reads entries from that file, and updates its internal state. 155 | .Pp 156 | .Nm 157 | checks the list of active entries every 158 | .Ar timeout 159 | seconds (default 160 | .Dv 15 ) 161 | and removes entries and block rules using the control program as necessary. 162 | .Pp 163 | The following options are available: 164 | .Bl -tag -width indent 165 | .It Fl C Ar controlprog 166 | Use 167 | .Ar controlprog 168 | to communicate with the packet filter, instead of the default, which is 169 | .Pa /libexec/blocklistd-helper . 170 | The following arguments are passed to the control program: 171 | .Bl -tag -width protocol 172 | .It action 173 | The action to perform: 174 | .Dv add , 175 | .Dv rem , 176 | or 177 | .Dv flush ; 178 | to add, remove or flush a firewall rule. 179 | .It name 180 | The rule name. 181 | .It protocol 182 | The optional protocol name (can be empty): 183 | .Dv tcp , 184 | .Dv tcp6 , 185 | .Dv udp , 186 | .Dv udp6 . 187 | .It address 188 | The IPv4 or IPv6 numeric address to be blocked or released. 189 | .It mask 190 | The numeric mask to be applied to the blocked or released address 191 | .It port 192 | The optional numeric port to be blocked (can be empty). 193 | .It id 194 | For packet filters that support removal of rules by rule identifier, the 195 | identifier of the rule to be removed. 196 | The add command is expected to return the rule identifier string to stdout. 197 | .El 198 | .It Fl c Ar configuration 199 | The name of the configuration file to read. 200 | The default when 201 | .Fl c 202 | is not given is 203 | .Pa /etc/blocklistd.conf . 204 | .It Fl D Ar dbfile 205 | The Berkeley DB file where 206 | .Nm 207 | stores its state. 208 | It defaults to 209 | .Pa /var/db/blocklistd.db . 210 | .It Fl d 211 | Normally, 212 | .Nm 213 | disassociates itself from the terminal unless the 214 | .Fl d 215 | flag is specified, in which case it stays in the foreground. 216 | .It Fl f 217 | Truncate the state database and flush all the rules named 218 | .Ar rulename 219 | are deleted by invoking the control script as: 220 | .Bd -literal -offset indent 221 | control flush 222 | .Ed 223 | .It Fl P Ar sockpathsfile 224 | A file containing a list of pathnames, one per line that 225 | .Nm 226 | will create sockets to listen to. 227 | This is useful for chrooted environments. 228 | .It Fl R Ar rulename 229 | Specify the default rule name for the packet filter rules, usually 230 | .Dv blocklistd . 231 | .It Fl r 232 | Re-read the firewall rules from the internal database, then 233 | remove and re-add them. 234 | This helps for packet filters that do not retain state across reboots. 235 | .It Fl s Ar sockpath 236 | Add 237 | .Ar sockpath 238 | to the list of Unix sockets 239 | .Nm 240 | listens to. 241 | .It Fl t Ar timeout 242 | The interval in seconds 243 | .Nm 244 | polls the state file to update the rules. 245 | .It Fl v 246 | Cause 247 | .Nm 248 | to print 249 | diagnostic messages to 250 | .Dv stdout 251 | instead of 252 | .Xr syslogd 8 . 253 | .El 254 | .Sh SIGNAL HANDLING 255 | .Nm 256 | deals with the following signals: 257 | .Bl -tag -width "USR2" 258 | .It Dv HUP 259 | Receipt of this signal causes 260 | .Nm 261 | to re-read the configuration file. 262 | .It Dv INT , Dv TERM & Dv QUIT 263 | These signals tell 264 | .Nm 265 | to exit in an orderly fashion. 266 | .It Dv USR1 267 | This signal tells 268 | .Nm 269 | to increase the internal debugging level by 1. 270 | .It Dv USR2 271 | This signal tells 272 | .Nm 273 | to decrease the internal debugging level by 1. 274 | .El 275 | .Sh FILES 276 | .Bl -tag -width /libexec/blocklistd-helper -compact 277 | .It Pa /libexec/blocklistd-helper 278 | Shell script invoked to interface with the packet filter. 279 | .It Pa /etc/blocklistd.conf 280 | Configuration file. 281 | .It Pa /var/db/blocklistd.db 282 | Database of current connection entries. 283 | .It Pa /var/run/blocklistd.sock 284 | Socket to receive connection notifications. 285 | .El 286 | .Sh SEE ALSO 287 | .Xr blocklistd.conf 5 , 288 | .Xr blocklistctl 8 , 289 | .Xr npfctl 8 , 290 | .Xr syslogd 8 291 | .Sh HISTORY 292 | .Nm 293 | first appeared in 294 | .Nx 7 . 295 | .Fx 296 | support for 297 | .Nm 298 | was implemented in 299 | .Fx 11 . 300 | .Sh AUTHORS 301 | .An Christos Zoulas 302 | -------------------------------------------------------------------------------- /port/sockaddr_snprintf.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: sockaddr_snprintf.c,v 1.2 2025/02/11 17:48:30 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2004 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifdef HAVE_CONFIG_H 32 | #include "config.h" 33 | #endif 34 | 35 | #ifdef HAVE_SYS_CDEFS_H 36 | #include 37 | #endif 38 | #if defined(LIBC_SCCS) && !defined(lint) 39 | __RCSID("$NetBSD: sockaddr_snprintf.c,v 1.2 2025/02/11 17:48:30 christos Exp $"); 40 | #endif /* LIBC_SCCS and not lint */ 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include 48 | #ifdef __linux__ 49 | #undef HAVE_NETATALK_AT_H 50 | #endif 51 | #ifdef HAVE_NETATALK_AT_H 52 | #include 53 | #endif 54 | #ifdef HAVE_NET_IF_DL_H 55 | #include 56 | #endif 57 | 58 | #include 59 | #include 60 | #include 61 | #include 62 | #ifdef HAVE_LIBUTIL_H 63 | #include 64 | #endif 65 | #ifdef HAVE_UTIL_H 66 | #include 67 | #endif 68 | #include 69 | 70 | #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 71 | #define SLEN(a) (a)->a ## _len 72 | #else 73 | static socklen_t 74 | socklen(u_int af) 75 | { 76 | switch (af) { 77 | case AF_INET: 78 | return sizeof(struct sockaddr_in); 79 | case AF_INET6: 80 | return sizeof(struct sockaddr_in6); 81 | case AF_LOCAL: 82 | return sizeof(struct sockaddr_un); 83 | #ifdef HAVE_NET_IF_DL_H 84 | case AF_LINK: 85 | return sizeof(struct sockaddr_dl); 86 | #endif 87 | #ifdef HAVE_NETATALK_AT_H 88 | case AF_APPLETALK: 89 | return sizeof(struct sockaddr_at); 90 | #endif 91 | default: 92 | return sizeof(struct sockaddr_storage); 93 | } 94 | } 95 | 96 | #define SLEN(a) socklen((a)->a ## _family) 97 | #endif 98 | 99 | #ifdef HAVE_NETATALK_AT_H 100 | static int 101 | debug_at(char *str, size_t len, const struct sockaddr_at *sat) 102 | { 103 | return snprintf(str, len, "sat_len=%u, sat_family=%u, sat_port=%u, " 104 | "sat_addr.s_net=%u, sat_addr.s_node=%u, " 105 | "sat_range.r_netrange.nr_phase=%u, " 106 | "sat_range.r_netrange.nr_firstnet=%u, " 107 | "sat_range.r_netrange.nr_lastnet=%u", 108 | SLEN(sat), sat->sat_family, sat->sat_port, 109 | sat->sat_addr.s_net, sat->sat_addr.s_node, 110 | sat->sat_range.r_netrange.nr_phase, 111 | sat->sat_range.r_netrange.nr_firstnet, 112 | sat->sat_range.r_netrange.nr_lastnet); 113 | } 114 | #endif 115 | 116 | static int 117 | debug_in(char *str, size_t len, const struct sockaddr_in *sin) 118 | { 119 | return snprintf(str, len, "sin_len=%u, sin_family=%u, sin_port=%u, " 120 | "sin_addr.s_addr=%08x", 121 | SLEN(sin), sin->sin_family, sin->sin_port, 122 | sin->sin_addr.s_addr); 123 | } 124 | 125 | static int 126 | debug_in6(char *str, size_t len, const struct sockaddr_in6 *sin6) 127 | { 128 | const uint8_t *s = sin6->sin6_addr.s6_addr; 129 | 130 | return snprintf(str, len, "sin6_len=%u, sin6_family=%u, sin6_port=%u, " 131 | "sin6_flowinfo=%u, " 132 | "sin6_addr=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:" 133 | "%02x:%02x:%02x:%02x:%02x:%02x, sin6_scope_id=%u", 134 | SLEN(sin6), sin6->sin6_family, sin6->sin6_port, 135 | sin6->sin6_flowinfo, s[0x0], s[0x1], s[0x2], s[0x3], s[0x4], s[0x5], 136 | s[0x6], s[0x7], s[0x8], s[0x9], s[0xa], s[0xb], s[0xc], s[0xd], 137 | s[0xe], s[0xf], sin6->sin6_scope_id); 138 | } 139 | 140 | static int 141 | debug_un(char *str, size_t len, const struct sockaddr_un *sun) 142 | { 143 | return snprintf(str, len, "sun_len=%u, sun_family=%u, sun_path=%*s", 144 | SLEN(sun), sun->sun_family, (int)sizeof(sun->sun_path), 145 | sun->sun_path); 146 | } 147 | 148 | #ifdef HAVE_NET_IF_DL_H 149 | static int 150 | debug_dl(char *str, size_t len, const struct sockaddr_dl *sdl) 151 | { 152 | const uint8_t *s = (const void *)sdl->sdl_data; 153 | 154 | return snprintf(str, len, "sdl_len=%u, sdl_family=%u, sdl_index=%u, " 155 | "sdl_type=%u, sdl_nlen=%u, sdl_alen=%u, sdl_slen=%u, sdl_data=" 156 | "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", 157 | SLEN(sdl), sdl->sdl_family, sdl->sdl_index, 158 | sdl->sdl_type, sdl->sdl_nlen, sdl->sdl_alen, sdl->sdl_slen, 159 | s[0x0], s[0x1], s[0x2], s[0x3], s[0x4], s[0x5], 160 | s[0x6], s[0x7], s[0x8], s[0x9], s[0xa], s[0xb]); 161 | } 162 | #endif 163 | 164 | int 165 | sockaddr_snprintf(char * const sbuf, const size_t len, const char * const fmt, 166 | const struct sockaddr * const sa) 167 | { 168 | const void *a = NULL; 169 | char abuf[1024], nbuf[1024], *addr = NULL; 170 | 171 | char Abuf[1024], pbuf[32], *name = NULL, *port = NULL; 172 | char *ebuf = &sbuf[len - 1], *buf = sbuf; 173 | const char *ptr, *s; 174 | int p = -1; 175 | #ifdef HAVE_NETATALK_AT_H 176 | const struct sockaddr_at *sat = NULL; 177 | #endif 178 | const struct sockaddr_in *sin4 = NULL; 179 | const struct sockaddr_in6 *sin6 = NULL; 180 | const struct sockaddr_un *sun = NULL; 181 | #ifdef HAVE_NET_IF_DL_H 182 | const struct sockaddr_dl *sdl = NULL; 183 | char *w = NULL; 184 | #endif 185 | int na = 1; 186 | 187 | #define ADDC(c) do { if (buf < ebuf) *buf++ = c; else buf++; } \ 188 | while (/*CONSTCOND*/0) 189 | #define ADDS(p) do { for (s = p; *s; s++) ADDC(*s); } \ 190 | while (/*CONSTCOND*/0) 191 | #define ADDNA() do { if (na) ADDS("N/A"); } \ 192 | while (/*CONSTCOND*/0) 193 | 194 | switch (sa->sa_family) { 195 | case AF_UNSPEC: 196 | goto done; 197 | #ifdef HAVE_NETATALK_AT_H 198 | case AF_APPLETALK: 199 | sat = ((const struct sockaddr_at *)(const void *)sa); 200 | p = ntohs(sat->sat_port); 201 | (void)snprintf(addr = abuf, sizeof(abuf), "%u.%u", 202 | ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node); 203 | (void)snprintf(port = pbuf, sizeof(pbuf), "%d", p); 204 | break; 205 | #endif 206 | case AF_LOCAL: 207 | sun = ((const struct sockaddr_un *)(const void *)sa); 208 | (void)strlcpy(addr = abuf, sun->sun_path, sizeof(abuf)); 209 | break; 210 | case AF_INET: 211 | sin4 = ((const struct sockaddr_in *)(const void *)sa); 212 | p = ntohs(sin4->sin_port); 213 | a = &sin4->sin_addr; 214 | break; 215 | case AF_INET6: 216 | sin6 = ((const struct sockaddr_in6 *)(const void *)sa); 217 | p = ntohs(sin6->sin6_port); 218 | a = &sin6->sin6_addr; 219 | break; 220 | #ifdef HAVE_NET_IF_DL_H 221 | case AF_LINK: 222 | sdl = ((const struct sockaddr_dl *)(const void *)sa); 223 | (void)strlcpy(addr = abuf, link_ntoa(sdl), sizeof(abuf)); 224 | if ((w = strchr(addr, ':')) != NULL) { 225 | *w++ = '\0'; 226 | addr = w; 227 | } 228 | break; 229 | #endif 230 | default: 231 | errno = EAFNOSUPPORT; 232 | return -1; 233 | } 234 | 235 | if (addr == abuf) 236 | name = addr; 237 | 238 | if (a && getnameinfo(sa, (socklen_t)SLEN(sa), addr = abuf, 239 | (unsigned int)sizeof(abuf), NULL, 0, 240 | NI_NUMERICHOST|NI_NUMERICSERV) != 0) 241 | return -1; 242 | 243 | for (ptr = fmt; *ptr; ptr++) { 244 | if (*ptr != '%') { 245 | ADDC(*ptr); 246 | continue; 247 | } 248 | next_char: 249 | switch (*++ptr) { 250 | case '?': 251 | na = 0; 252 | goto next_char; 253 | case 'a': 254 | ADDS(addr); 255 | break; 256 | case 'p': 257 | if (p != -1) { 258 | (void)snprintf(nbuf, sizeof(nbuf), "%d", p); 259 | ADDS(nbuf); 260 | } else 261 | ADDNA(); 262 | break; 263 | case 'f': 264 | (void)snprintf(nbuf, sizeof(nbuf), "%d", sa->sa_family); 265 | ADDS(nbuf); 266 | break; 267 | case 'l': 268 | (void)snprintf(nbuf, sizeof(nbuf), "%d", SLEN(sa)); 269 | ADDS(nbuf); 270 | break; 271 | case 'A': 272 | if (name) 273 | ADDS(name); 274 | else if (!a) 275 | ADDNA(); 276 | else { 277 | getnameinfo(sa, (socklen_t)SLEN(sa), 278 | name = Abuf, 279 | (unsigned int)sizeof(nbuf), NULL, 0, 0); 280 | ADDS(name); 281 | } 282 | break; 283 | case 'P': 284 | if (port) 285 | ADDS(port); 286 | else if (p == -1) 287 | ADDNA(); 288 | else { 289 | getnameinfo(sa, (socklen_t)SLEN(sa), NULL, 0, 290 | port = pbuf, 291 | (unsigned int)sizeof(pbuf), 0); 292 | ADDS(port); 293 | } 294 | break; 295 | case 'I': 296 | #ifdef HAVE_NET_IF_DL_H 297 | if (sdl && addr != abuf) { 298 | ADDS(abuf); 299 | } else 300 | #endif 301 | { 302 | ADDNA(); 303 | } 304 | break; 305 | case 'F': 306 | if (sin6) { 307 | (void)snprintf(nbuf, sizeof(nbuf), "%d", 308 | sin6->sin6_flowinfo); 309 | ADDS(nbuf); 310 | break; 311 | } else { 312 | ADDNA(); 313 | } 314 | break; 315 | case 'S': 316 | if (sin6) { 317 | (void)snprintf(nbuf, sizeof(nbuf), "%d", 318 | sin6->sin6_scope_id); 319 | ADDS(nbuf); 320 | break; 321 | } else { 322 | ADDNA(); 323 | } 324 | break; 325 | case 'R': 326 | #ifdef HAVE_NETATALK_AT_H 327 | if (sat) { 328 | const struct netrange *n = 329 | &sat->sat_range.r_netrange; 330 | (void)snprintf(nbuf, sizeof(nbuf), 331 | "%d:[%d,%d]", n->nr_phase , n->nr_firstnet, 332 | n->nr_lastnet); 333 | ADDS(nbuf); 334 | } else 335 | #endif 336 | { 337 | ADDNA(); 338 | } 339 | break; 340 | case 'D': 341 | switch (sa->sa_family) { 342 | #ifdef HAVE_NETATALK_AT_H 343 | case AF_APPLETALK: 344 | debug_at(nbuf, sizeof(nbuf), sat); 345 | break; 346 | #endif 347 | case AF_LOCAL: 348 | debug_un(nbuf, sizeof(nbuf), sun); 349 | break; 350 | case AF_INET: 351 | debug_in(nbuf, sizeof(nbuf), sin4); 352 | break; 353 | case AF_INET6: 354 | debug_in6(nbuf, sizeof(nbuf), sin6); 355 | break; 356 | #ifdef HAVE_NET_IF_DL_H 357 | case AF_LINK: 358 | debug_dl(nbuf, sizeof(nbuf), sdl); 359 | break; 360 | #endif 361 | default: 362 | abort(); 363 | } 364 | ADDS(nbuf); 365 | break; 366 | default: 367 | ADDC('%'); 368 | if (na == 0) 369 | ADDC('?'); 370 | if (*ptr == '\0') 371 | goto done; 372 | /*FALLTHROUGH*/ 373 | case '%': 374 | ADDC(*ptr); 375 | break; 376 | } 377 | na = 1; 378 | } 379 | done: 380 | if (buf < ebuf) 381 | *buf = '\0'; 382 | else if (len != 0) 383 | sbuf[len - 1] = '\0'; 384 | return (int)(buf - sbuf); 385 | } 386 | -------------------------------------------------------------------------------- /lib/bl.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: bl.c,v 1.9 2025/03/30 01:53:59 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifdef HAVE_CONFIG_H 32 | #include "config.h" 33 | #endif 34 | 35 | #ifdef HAVE_SYS_CDEFS_H 36 | #include 37 | #endif 38 | __RCSID("$NetBSD: bl.c,v 1.9 2025/03/30 01:53:59 christos Exp $"); 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #ifdef _REENTRANT 59 | #include 60 | #endif 61 | 62 | #if defined(SO_RECVUCRED) 63 | #include 64 | #endif 65 | 66 | #include "bl.h" 67 | 68 | typedef struct { 69 | uint32_t bl_len; 70 | uint32_t bl_version; 71 | uint32_t bl_type; 72 | uint32_t bl_salen; 73 | struct sockaddr_storage bl_ss; 74 | char bl_data[]; 75 | } bl_message_t; 76 | 77 | struct blocklist { 78 | #ifdef _REENTRANT 79 | pthread_mutex_t b_mutex; 80 | # define BL_INIT(b) pthread_mutex_init(&b->b_mutex, NULL) 81 | # define BL_LOCK(b) pthread_mutex_lock(&b->b_mutex) 82 | # define BL_UNLOCK(b) pthread_mutex_unlock(&b->b_mutex) 83 | #else 84 | # define BL_INIT(b) do {} while(/*CONSTCOND*/0) 85 | # define BL_LOCK(b) BL_INIT(b) 86 | # define BL_UNLOCK(b) BL_INIT(b) 87 | #endif 88 | int b_fd; 89 | int b_connected; 90 | struct sockaddr_un b_sun; 91 | struct syslog_data b_syslog_data; 92 | void (*b_fun)(int, struct syslog_data *, const char *, va_list); 93 | bl_info_t b_info; 94 | }; 95 | 96 | #define BL_VERSION 1 97 | 98 | bool 99 | bl_isconnected(bl_t b) 100 | { 101 | return b->b_connected == 0; 102 | } 103 | 104 | int 105 | bl_getfd(bl_t b) 106 | { 107 | return b->b_fd; 108 | } 109 | 110 | static void 111 | bl_reset(bl_t b, bool locked) 112 | { 113 | int serrno = errno; 114 | if (!locked) 115 | BL_LOCK(b); 116 | close(b->b_fd); 117 | errno = serrno; 118 | b->b_fd = -1; 119 | b->b_connected = -1; 120 | if (!locked) 121 | BL_UNLOCK(b); 122 | } 123 | 124 | static void 125 | bl_log(bl_t b, int level, const char *fmt, ...) 126 | { 127 | va_list ap; 128 | int serrno = errno; 129 | 130 | if (b->b_fun == NULL) 131 | return; 132 | 133 | va_start(ap, fmt); 134 | (*b->b_fun)(level, &b->b_syslog_data, fmt, ap); 135 | va_end(ap); 136 | errno = serrno; 137 | } 138 | 139 | static int 140 | bl_init(bl_t b, bool srv) 141 | { 142 | static int one = 1; 143 | /* AF_UNIX address of local logger */ 144 | mode_t om; 145 | int rv, serrno; 146 | struct sockaddr_un *sun = &b->b_sun; 147 | 148 | #ifndef SOCK_NONBLOCK 149 | #define SOCK_NONBLOCK 0 150 | #endif 151 | #ifndef SOCK_CLOEXEC 152 | #define SOCK_CLOEXEC 0 153 | #endif 154 | #ifndef SOCK_NOSIGPIPE 155 | #define SOCK_NOSIGPIPE 0 156 | #endif 157 | 158 | BL_LOCK(b); 159 | 160 | if (b->b_fd == -1) { 161 | b->b_fd = socket(PF_LOCAL, 162 | SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK|SOCK_NOSIGPIPE, 0); 163 | if (b->b_fd == -1) { 164 | bl_log(b, LOG_ERR, "%s: socket failed (%s)", 165 | __func__, strerror(errno)); 166 | BL_UNLOCK(b); 167 | return -1; 168 | } 169 | #if SOCK_CLOEXEC == 0 170 | fcntl(b->b_fd, F_SETFD, FD_CLOEXEC); 171 | #endif 172 | #if SOCK_NONBLOCK == 0 173 | fcntl(b->b_fd, F_SETFL, fcntl(b->b_fd, F_GETFL) | O_NONBLOCK); 174 | #endif 175 | #if SOCK_NOSIGPIPE == 0 176 | #ifdef SO_NOSIGPIPE 177 | int o = 1; 178 | setsockopt(b->b_fd, SOL_SOCKET, SO_NOSIGPIPE, &o, sizeof(o)); 179 | #else 180 | signal(SIGPIPE, SIG_IGN); 181 | #endif 182 | #endif 183 | } 184 | 185 | if (bl_isconnected(b)) { 186 | BL_UNLOCK(b); 187 | return 0; 188 | } 189 | 190 | /* 191 | * We try to connect anyway even when we are a server to verify 192 | * that no other server is listening to the socket. If we succeed 193 | * to connect and we are a server, someone else owns it. 194 | */ 195 | rv = connect(b->b_fd, (const void *)sun, (socklen_t)sizeof(*sun)); 196 | if (rv == 0) { 197 | if (srv) { 198 | bl_log(b, LOG_ERR, 199 | "%s: another daemon is handling `%s'", 200 | __func__, sun->sun_path); 201 | goto out; 202 | } 203 | } else { 204 | if (!srv) { 205 | /* 206 | * If the daemon is not running, we just try a 207 | * connect, so leave the socket alone until it does 208 | * and only log once. 209 | */ 210 | if (b->b_connected != 1) { 211 | bl_log(b, LOG_DEBUG, 212 | "%s: connect failed for `%s' (%s)", 213 | __func__, sun->sun_path, strerror(errno)); 214 | b->b_connected = 1; 215 | } 216 | BL_UNLOCK(b); 217 | return -1; 218 | } 219 | bl_log(b, LOG_DEBUG, "Connected to blocklist server", __func__); 220 | } 221 | 222 | if (srv) { 223 | (void)unlink(sun->sun_path); 224 | om = umask(0); 225 | rv = bind(b->b_fd, (const void *)sun, (socklen_t)sizeof(*sun)); 226 | serrno = errno; 227 | (void)umask(om); 228 | errno = serrno; 229 | if (rv == -1) { 230 | bl_log(b, LOG_ERR, "%s: bind failed for `%s' (%s)", 231 | __func__, sun->sun_path, strerror(errno)); 232 | goto out; 233 | } 234 | } 235 | 236 | b->b_connected = 0; 237 | #define GOT_FD 1 238 | #if defined(LOCAL_CREDS) 239 | #define CRED_LEVEL 0 240 | #define CRED_NAME LOCAL_CREDS 241 | #define CRED_SC_UID(x) (x)->sc_euid 242 | #define CRED_SC_GID(x) (x)->sc_egid 243 | #define CRED_MESSAGE SCM_CREDS 244 | #define CRED_SIZE SOCKCREDSIZE(NGROUPS_MAX) 245 | #define CRED_TYPE struct sockcred 246 | #define GOT_CRED 2 247 | #elif defined(SO_PASSCRED) 248 | #define CRED_LEVEL SOL_SOCKET 249 | #define CRED_NAME SO_PASSCRED 250 | #define CRED_SC_UID(x) (x)->uid 251 | #define CRED_SC_GID(x) (x)->gid 252 | #define CRED_MESSAGE SCM_CREDENTIALS 253 | #define CRED_SIZE sizeof(struct ucred) 254 | #define CRED_TYPE struct ucred 255 | #define GOT_CRED 2 256 | #elif defined(SO_RECVUCRED) 257 | #define CRED_LEVEL SOL_SOCKET 258 | #define CRED_NAME SO_RECVUCRED 259 | #define CRED_SC_UID(x) ucred_geteuid(x) 260 | #define CRED_SC_GID(x) ucred_getegid(x) 261 | #define CRED_MESSAGE SCM_UCRED 262 | #define CRED_SIZE ucred_size() 263 | #define CRED_TYPE ucred_t 264 | #define GOT_CRED 2 265 | #else 266 | #define GOT_CRED 0 267 | /* 268 | * getpeereid() and LOCAL_PEERCRED don't help here 269 | * because we are not a stream socket! 270 | */ 271 | #define CRED_SIZE 0 272 | #define CRED_TYPE void * __unused 273 | #endif 274 | 275 | #ifdef CRED_LEVEL 276 | if (setsockopt(b->b_fd, CRED_LEVEL, CRED_NAME, 277 | &one, (socklen_t)sizeof(one)) == -1) { 278 | bl_log(b, LOG_ERR, "%s: setsockopt %s " 279 | "failed (%s)", __func__, __STRING(CRED_NAME), 280 | strerror(errno)); 281 | goto out; 282 | } 283 | #endif 284 | 285 | BL_UNLOCK(b); 286 | return 0; 287 | out: 288 | bl_reset(b, true); 289 | BL_UNLOCK(b); 290 | return -1; 291 | } 292 | 293 | bl_t 294 | bl_create(bool srv, const char *path, 295 | void (*fun)(int, struct syslog_data *, const char *, va_list)) 296 | { 297 | static struct syslog_data sd = SYSLOG_DATA_INIT; 298 | bl_t b = calloc(1, sizeof(*b)); 299 | if (b == NULL) 300 | return NULL; 301 | b->b_fun = fun; 302 | b->b_syslog_data = sd; 303 | b->b_fd = -1; 304 | b->b_connected = -1; 305 | BL_INIT(b); 306 | 307 | memset(&b->b_sun, 0, sizeof(b->b_sun)); 308 | b->b_sun.sun_family = AF_LOCAL; 309 | #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 310 | b->b_sun.sun_len = sizeof(b->b_sun); 311 | #endif 312 | strlcpy(b->b_sun.sun_path, 313 | path ? path : _PATH_BLSOCK, sizeof(b->b_sun.sun_path)); 314 | 315 | bl_init(b, srv); 316 | return b; 317 | } 318 | 319 | void 320 | bl_destroy(bl_t b) 321 | { 322 | bl_reset(b, false); 323 | free(b); 324 | } 325 | 326 | static int 327 | bl_getsock(bl_t b, struct sockaddr_storage *ss, const struct sockaddr *sa, 328 | socklen_t slen, const char *ctx) 329 | { 330 | uint8_t family; 331 | 332 | memset(ss, 0, sizeof(*ss)); 333 | 334 | switch (slen) { 335 | case 0: 336 | return 0; 337 | case sizeof(struct sockaddr_in): 338 | family = AF_INET; 339 | break; 340 | case sizeof(struct sockaddr_in6): 341 | family = AF_INET6; 342 | break; 343 | default: 344 | bl_log(b, LOG_ERR, "%s: invalid socket len %u (%s)", 345 | __func__, (unsigned)slen, ctx); 346 | errno = EINVAL; 347 | return -1; 348 | } 349 | 350 | memcpy(ss, sa, slen); 351 | 352 | if (ss->ss_family != family) { 353 | bl_log(b, LOG_INFO, 354 | "%s: correcting socket family %d to %d (%s)", 355 | __func__, ss->ss_family, family, ctx); 356 | ss->ss_family = family; 357 | } 358 | 359 | #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 360 | if (ss->ss_len != slen) { 361 | bl_log(b, LOG_INFO, 362 | "%s: correcting socket len %u to %u (%s)", 363 | __func__, ss->ss_len, (unsigned)slen, ctx); 364 | ss->ss_len = (uint8_t)slen; 365 | } 366 | #endif 367 | return 0; 368 | } 369 | 370 | int 371 | bl_send(bl_t b, bl_type_t e, int pfd, const struct sockaddr *sa, 372 | socklen_t slen, const char *ctx) 373 | { 374 | struct msghdr msg; 375 | struct iovec iov; 376 | union { 377 | char ctrl[CMSG_SPACE(sizeof(int))]; 378 | uint32_t fd; 379 | } ua; 380 | struct cmsghdr *cmsg; 381 | union { 382 | bl_message_t bl; 383 | char buf[512]; 384 | } ub; 385 | size_t ctxlen, tried; 386 | #define NTRIES 5 387 | 388 | ctxlen = strlen(ctx); 389 | if (ctxlen > 128) 390 | ctxlen = 128; 391 | 392 | iov.iov_base = ub.buf; 393 | iov.iov_len = sizeof(bl_message_t) + ctxlen; 394 | ub.bl.bl_len = (uint32_t)iov.iov_len; 395 | ub.bl.bl_version = BL_VERSION; 396 | ub.bl.bl_type = (uint32_t)e; 397 | 398 | if (bl_getsock(b, &ub.bl.bl_ss, sa, slen, ctx) == -1) 399 | return -1; 400 | 401 | 402 | ub.bl.bl_salen = slen; 403 | memcpy(ub.bl.bl_data, ctx, ctxlen); 404 | 405 | msg.msg_name = NULL; 406 | msg.msg_namelen = 0; 407 | msg.msg_iov = &iov; 408 | msg.msg_iovlen = 1; 409 | msg.msg_flags = 0; 410 | 411 | msg.msg_control = ua.ctrl; 412 | msg.msg_controllen = sizeof(ua.ctrl); 413 | 414 | cmsg = CMSG_FIRSTHDR(&msg); 415 | cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 416 | cmsg->cmsg_level = SOL_SOCKET; 417 | cmsg->cmsg_type = SCM_RIGHTS; 418 | 419 | memcpy(CMSG_DATA(cmsg), &pfd, sizeof(pfd)); 420 | 421 | tried = 0; 422 | again: 423 | if (bl_init(b, false) == -1) 424 | return -1; 425 | 426 | if ((sendmsg(b->b_fd, &msg, 0) == -1) && tried++ < NTRIES) { 427 | bl_reset(b, false); 428 | goto again; 429 | } 430 | return tried >= NTRIES ? -1 : 0; 431 | } 432 | 433 | bl_info_t * 434 | bl_recv(bl_t b) 435 | { 436 | struct msghdr msg; 437 | struct iovec iov; 438 | union { 439 | char ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(CRED_SIZE)]; 440 | uint32_t fd; 441 | } ua; 442 | struct cmsghdr *cmsg; 443 | #if GOT_CRED != 0 444 | CRED_TYPE *sc; 445 | #endif 446 | union { 447 | bl_message_t bl; 448 | char buf[512]; 449 | } ub; 450 | int got; 451 | ssize_t rlen; 452 | size_t rem; 453 | bl_info_t *bi = &b->b_info; 454 | 455 | got = 0; 456 | memset(bi, 0, sizeof(*bi)); 457 | 458 | iov.iov_base = ub.buf; 459 | iov.iov_len = sizeof(ub); 460 | 461 | msg.msg_name = NULL; 462 | msg.msg_namelen = 0; 463 | msg.msg_iov = &iov; 464 | msg.msg_iovlen = 1; 465 | msg.msg_flags = 0; 466 | 467 | msg.msg_control = ua.ctrl; 468 | msg.msg_controllen = sizeof(ua.ctrl); 469 | 470 | rlen = recvmsg(b->b_fd, &msg, 0); 471 | if (rlen == -1) { 472 | bl_log(b, LOG_ERR, "%s: recvmsg failed (%s)", __func__, 473 | strerror(errno)); 474 | return NULL; 475 | } 476 | 477 | for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 478 | if (cmsg->cmsg_level != SOL_SOCKET) { 479 | bl_log(b, LOG_ERR, 480 | "%s: unexpected cmsg_level %d", 481 | __func__, cmsg->cmsg_level); 482 | continue; 483 | } 484 | switch (cmsg->cmsg_type) { 485 | case SCM_RIGHTS: 486 | if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) { 487 | int *fd = (void *)CMSG_DATA(cmsg); 488 | size_t len = cmsg->cmsg_len / sizeof(int); 489 | bl_log(b, LOG_ERR, 490 | "%s: unexpected cmsg_len %d != %zu", 491 | __func__, cmsg->cmsg_len, 492 | CMSG_LEN(sizeof(int))); 493 | 494 | for (size_t i = 0; i < len; i++) 495 | (void)close(fd[i]); 496 | continue; 497 | } 498 | memcpy(&bi->bi_fd, CMSG_DATA(cmsg), sizeof(bi->bi_fd)); 499 | got |= GOT_FD; 500 | break; 501 | #ifdef CRED_MESSAGE 502 | case CRED_MESSAGE: 503 | sc = (void *)CMSG_DATA(cmsg); 504 | bi->bi_uid = CRED_SC_UID(sc); 505 | bi->bi_gid = CRED_SC_GID(sc); 506 | got |= GOT_CRED; 507 | break; 508 | #endif 509 | default: 510 | bl_log(b, LOG_ERR, 511 | "%s: unexpected cmsg_type %d", 512 | __func__, cmsg->cmsg_type); 513 | continue; 514 | } 515 | 516 | } 517 | 518 | if (got != (GOT_CRED|GOT_FD)) { 519 | bl_log(b, LOG_ERR, "message missing %s %s", 520 | #if GOT_CRED != 0 521 | (got & GOT_CRED) == 0 ? "cred" : 522 | #endif 523 | "", (got & GOT_FD) == 0 ? "fd" : ""); 524 | return NULL; 525 | } 526 | 527 | rem = (size_t)rlen; 528 | if (rem < sizeof(ub.bl)) { 529 | bl_log(b, LOG_ERR, "message too short %zd", rlen); 530 | return NULL; 531 | } 532 | rem -= sizeof(ub.bl); 533 | 534 | if (ub.bl.bl_version != BL_VERSION) { 535 | bl_log(b, LOG_ERR, "bad version %d", ub.bl.bl_version); 536 | return NULL; 537 | } 538 | 539 | bi->bi_type = ub.bl.bl_type; 540 | bi->bi_slen = ub.bl.bl_salen; 541 | bi->bi_ss = ub.bl.bl_ss; 542 | #ifndef CRED_MESSAGE 543 | bi->bi_uid = -1; 544 | bi->bi_gid = -1; 545 | #endif 546 | if (rem == 0) 547 | bi->bi_msg[0] = '\0'; 548 | else { 549 | rem = MIN(sizeof(bi->bi_msg) - 1, rem); 550 | memcpy(bi->bi_msg, ub.bl.bl_data, rem); 551 | bi->bi_msg[rem] = '\0'; 552 | } 553 | return bi; 554 | } 555 | -------------------------------------------------------------------------------- /bin/blocklistd.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: blocklistd.c,v 1.14 2025/12/15 15:51:37 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Christos Zoulas. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | #ifdef HAVE_CONFIG_H 32 | #include "config.h" 33 | #endif 34 | 35 | #ifdef HAVE_SYS_CDEFS_H 36 | #include 37 | #endif 38 | __RCSID("$NetBSD: blocklistd.c,v 1.14 2025/12/15 15:51:37 christos Exp $"); 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | #ifdef HAVE_LIBUTIL_H 45 | #include 46 | #endif 47 | #ifdef HAVE_UTIL_H 48 | #include 49 | #endif 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | 70 | #include "bl.h" 71 | #include "internal.h" 72 | #include "conf.h" 73 | #include "run.h" 74 | #include "state.h" 75 | #include "support.h" 76 | 77 | static const char *configfile = _PATH_BLCONF; 78 | static DB *state; 79 | static const char *dbfile = _PATH_BLSTATE; 80 | static sig_atomic_t readconf; 81 | static sig_atomic_t done; 82 | static int vflag; 83 | 84 | static void 85 | sigusr1(int n __unused) 86 | { 87 | debug++; 88 | } 89 | 90 | static void 91 | sigusr2(int n __unused) 92 | { 93 | debug--; 94 | } 95 | 96 | static void 97 | sighup(int n __unused) 98 | { 99 | readconf++; 100 | } 101 | 102 | static void 103 | sigdone(int n __unused) 104 | { 105 | done++; 106 | } 107 | 108 | static __dead void 109 | usage(int c) 110 | { 111 | if (c != '?') 112 | warnx("Unknown option `%c'", (char)c); 113 | fprintf(stderr, "Usage: %s [-vdfr] [-c ] [-R ] " 114 | "[-P ] [-C ] [-D ] " 115 | "[-s ] [-t ]\n", getprogname()); 116 | exit(EXIT_FAILURE); 117 | } 118 | 119 | static int 120 | getremoteaddress(bl_info_t *bi, struct sockaddr_storage *rss, socklen_t *rsl) 121 | { 122 | *rsl = sizeof(*rss); 123 | memset(rss, 0, *rsl); 124 | 125 | if (getpeername(bi->bi_fd, (void *)rss, rsl) != -1) 126 | return 0; 127 | 128 | if (errno != ENOTCONN) { 129 | (*lfun)(LOG_ERR, "getpeername failed (%m)"); 130 | return -1; 131 | } 132 | 133 | if (bi->bi_slen == 0) { 134 | (*lfun)(LOG_ERR, "unconnected socket with no peer in message"); 135 | return -1; 136 | } 137 | 138 | switch (bi->bi_ss.ss_family) { 139 | case AF_INET: 140 | *rsl = sizeof(struct sockaddr_in); 141 | break; 142 | case AF_INET6: 143 | *rsl = sizeof(struct sockaddr_in6); 144 | break; 145 | default: 146 | (*lfun)(LOG_ERR, "bad client passed socket family %u", 147 | (unsigned)bi->bi_ss.ss_family); 148 | return -1; 149 | } 150 | 151 | if (*rsl != bi->bi_slen) { 152 | (*lfun)(LOG_ERR, "bad client passed socket length %u != %u", 153 | (unsigned)*rsl, (unsigned)bi->bi_slen); 154 | return -1; 155 | } 156 | 157 | memcpy(rss, &bi->bi_ss, *rsl); 158 | 159 | #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 160 | if (*rsl != rss->ss_len) { 161 | (*lfun)(LOG_ERR, 162 | "bad client passed socket internal length %u != %u", 163 | (unsigned)*rsl, (unsigned)rss->ss_len); 164 | return -1; 165 | } 166 | #endif 167 | return 0; 168 | } 169 | 170 | static void 171 | process(bl_t bl) 172 | { 173 | struct sockaddr_storage rss; 174 | socklen_t rsl; 175 | char rbuf[BUFSIZ]; 176 | bl_info_t *bi; 177 | struct conf c; 178 | struct dbinfo dbi; 179 | struct timespec ts; 180 | 181 | memset(&dbi, 0, sizeof(dbi)); 182 | memset(&c, 0, sizeof(c)); 183 | if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { 184 | (*lfun)(LOG_ERR, "clock_gettime failed (%m)"); 185 | return; 186 | } 187 | 188 | if ((bi = bl_recv(bl)) == NULL) { 189 | (*lfun)(LOG_ERR, "no message (%m)"); 190 | return; 191 | } 192 | 193 | if (getremoteaddress(bi, &rss, &rsl) == -1) 194 | goto out; 195 | 196 | if (debug || bi->bi_msg[0]) { 197 | sockaddr_snprintf(rbuf, sizeof(rbuf), "%a:%p", (void *)&rss); 198 | (*lfun)(bi->bi_msg[0] ? LOG_INFO : LOG_DEBUG, 199 | "processing type=%d fd=%d remote=%s msg=\"%s\" " 200 | "uid=%lu gid=%lu", 201 | bi->bi_type, bi->bi_fd, rbuf, 202 | bi->bi_msg, (unsigned long)bi->bi_uid, 203 | (unsigned long)bi->bi_gid); 204 | } 205 | 206 | if (conf_find(bi->bi_fd, bi->bi_uid, &rss, &c) == NULL) { 207 | (*lfun)(LOG_DEBUG, "no rule matched"); 208 | goto out; 209 | } 210 | 211 | 212 | if (state_get(state, &c, &dbi) == -1) 213 | goto out; 214 | 215 | if (debug) { 216 | char b1[128], b2[128]; 217 | (*lfun)(LOG_DEBUG, "%s: initial db state for %s: count=%d/%d " 218 | "last=%s now=%s", __func__, rbuf, dbi.count, c.c_nfail, 219 | fmttime(b1, sizeof(b1), dbi.last), 220 | fmttime(b2, sizeof(b2), ts.tv_sec)); 221 | } 222 | 223 | switch (bi->bi_type) { 224 | case BL_ABUSE: 225 | /* 226 | * If the application has signaled abusive behavior, set the 227 | * number of fails to be two less than the configured limit. 228 | * Fall through to the normal BL_ADD and BL_BADUSER processing, 229 | * which will increment the failure count to the threshold, and 230 | * block the abusive address. 231 | */ 232 | if (c.c_nfail != -1) 233 | dbi.count = c.c_nfail - 2; 234 | /*FALLTHROUGH*/ 235 | case BL_ADD: 236 | dbi.count++; /* will become += 2 */ 237 | /*FALLTHROUGH*/ 238 | case BL_BADUSER: 239 | dbi.count++; 240 | dbi.last = ts.tv_sec; 241 | if (c.c_nfail != -1 && dbi.count >= c.c_nfail) { 242 | /* 243 | * No point in re-adding the rule. 244 | * It might exist already due to latency in processing 245 | * and removing the rule is the wrong thing to do as 246 | * it allows a window to attack again. 247 | */ 248 | if (dbi.id[0] == '\0') { 249 | int res = run_change("add", &c, 250 | dbi.id, sizeof(dbi.id)); 251 | if (res == -1) 252 | goto out; 253 | } 254 | sockaddr_snprintf(rbuf, sizeof(rbuf), "%a", 255 | (void *)&rss); 256 | (*lfun)(LOG_INFO, 257 | "blocked %s/%d:%d for %d seconds", 258 | rbuf, c.c_lmask, c.c_port, c.c_duration); 259 | } 260 | break; 261 | case BL_DELETE: 262 | if (dbi.last == 0) 263 | goto out; 264 | dbi.count = 0; 265 | dbi.last = 0; 266 | break; 267 | default: 268 | (*lfun)(LOG_ERR, "unknown message %d", bi->bi_type); 269 | } 270 | state_put(state, &c, &dbi); 271 | 272 | out: 273 | close(bi->bi_fd); 274 | 275 | if (debug) { 276 | char b1[128], b2[128]; 277 | (*lfun)(LOG_DEBUG, "%s: final db state for %s: count=%d/%d " 278 | "last=%s now=%s", __func__, rbuf, dbi.count, c.c_nfail, 279 | fmttime(b1, sizeof(b1), dbi.last), 280 | fmttime(b2, sizeof(b2), ts.tv_sec)); 281 | } 282 | } 283 | 284 | static void 285 | update_interfaces(void) 286 | { 287 | struct ifaddrs *oifas, *nifas; 288 | 289 | if (getifaddrs(&nifas) == -1) 290 | return; 291 | 292 | oifas = ifas; 293 | ifas = nifas; 294 | 295 | if (oifas) 296 | freeifaddrs(oifas); 297 | } 298 | 299 | static void 300 | update(void) 301 | { 302 | struct timespec ts; 303 | struct conf c; 304 | struct dbinfo dbi; 305 | unsigned int f, n; 306 | char buf[128]; 307 | void *ss = &c.c_ss; 308 | 309 | if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { 310 | (*lfun)(LOG_ERR, "clock_gettime failed (%m)"); 311 | return; 312 | } 313 | 314 | again: 315 | for (n = 0, f = 1; state_iterate(state, &c, &dbi, f) == 1; 316 | f = 0, n++) 317 | { 318 | time_t when = c.c_duration + dbi.last; 319 | if (debug > 1) { 320 | char b1[64], b2[64]; 321 | sockaddr_snprintf(buf, sizeof(buf), "%a:%p", ss); 322 | (*lfun)(LOG_DEBUG, "%s:[%u] %s count=%d duration=%d " 323 | "last=%s " "now=%s", __func__, n, buf, dbi.count, 324 | c.c_duration, fmttime(b1, sizeof(b1), dbi.last), 325 | fmttime(b2, sizeof(b2), ts.tv_sec)); 326 | } 327 | if (c.c_duration == -1 || when >= ts.tv_sec) 328 | continue; 329 | if (dbi.id[0]) { 330 | run_change("rem", &c, dbi.id, 0); 331 | sockaddr_snprintf(buf, sizeof(buf), "%a", ss); 332 | (*lfun)(LOG_INFO, "released %s/%d:%d after %d seconds", 333 | buf, c.c_lmask, c.c_port, c.c_duration); 334 | } 335 | if (state_del(state, &c) == 0) 336 | goto again; 337 | } 338 | } 339 | 340 | static void 341 | addfd(struct pollfd **pfdp, bl_t **blp, size_t *nfd, size_t *maxfd, 342 | const char *path) 343 | { 344 | bl_t bl = bl_create(true, path, vflag ? vdlog : vsyslog_r); 345 | if (bl == NULL || !bl_isconnected(bl)) 346 | exit(EXIT_FAILURE); 347 | if (*nfd >= *maxfd) { 348 | *maxfd += 10; 349 | *blp = realloc(*blp, sizeof(**blp) * *maxfd); 350 | if (*blp == NULL) 351 | err(EXIT_FAILURE, "malloc"); 352 | *pfdp = realloc(*pfdp, sizeof(**pfdp) * *maxfd); 353 | if (*pfdp == NULL) 354 | err(EXIT_FAILURE, "malloc"); 355 | } 356 | 357 | (*pfdp)[*nfd].fd = bl_getfd(bl); 358 | (*pfdp)[*nfd].events = POLLIN; 359 | (*blp)[*nfd] = bl; 360 | *nfd += 1; 361 | } 362 | 363 | static void 364 | uniqueadd(struct conf ***listp, size_t *nlist, size_t *mlist, struct conf *c) 365 | { 366 | struct conf **list = *listp; 367 | 368 | if (c->c_name[0] == '\0') 369 | return; 370 | for (size_t i = 0; i < *nlist; i++) { 371 | if (strcmp(list[i]->c_name, c->c_name) == 0) 372 | return; 373 | } 374 | if (*nlist == *mlist) { 375 | *mlist += 10; 376 | void *p = realloc(*listp, *mlist * sizeof(*list)); 377 | if (p == NULL) 378 | err(EXIT_FAILURE, "Can't allocate for rule list"); 379 | list = *listp = p; 380 | } 381 | list[(*nlist)++] = c; 382 | } 383 | 384 | static void 385 | rules_flush(void) 386 | { 387 | struct conf **list; 388 | size_t nlist, mlist; 389 | 390 | list = NULL; 391 | mlist = nlist = 0; 392 | for (size_t i = 0; i < rconf.cs_n; i++) 393 | uniqueadd(&list, &nlist, &mlist, &rconf.cs_c[i]); 394 | for (size_t i = 0; i < lconf.cs_n; i++) 395 | uniqueadd(&list, &nlist, &mlist, &lconf.cs_c[i]); 396 | 397 | for (size_t i = 0; i < nlist; i++) 398 | run_flush(list[i]); 399 | free(list); 400 | } 401 | 402 | static void 403 | rules_restore(void) 404 | { 405 | DB *db; 406 | struct conf c; 407 | struct dbinfo dbi; 408 | unsigned int f; 409 | 410 | db = state_open(dbfile, O_RDONLY, 0); 411 | if (db == NULL) { 412 | (*lfun)(LOG_ERR, "Can't open `%s' to restore state (%m)", 413 | dbfile); 414 | return; 415 | } 416 | for (f = 1; state_iterate(db, &c, &dbi, f) == 1; f = 0) { 417 | if (dbi.id[0] == '\0') 418 | continue; 419 | (void)run_change("add", &c, dbi.id, sizeof(dbi.id)); 420 | state_put(state, &c, &dbi); 421 | } 422 | state_close(db); 423 | state_sync(state); 424 | } 425 | 426 | int 427 | main(int argc, char *argv[]) 428 | { 429 | int c, tout, flags, flush, restore, ret; 430 | const char *spath, **blsock; 431 | size_t nblsock, maxblsock; 432 | 433 | setprogname(argv[0]); 434 | 435 | spath = NULL; 436 | blsock = NULL; 437 | maxblsock = nblsock = 0; 438 | flush = 0; 439 | restore = 0; 440 | tout = 0; 441 | flags = O_RDWR|O_EXCL|O_CLOEXEC; 442 | while ((c = getopt(argc, argv, "C:c:D:dfP:rR:s:t:v")) != -1) { 443 | switch (c) { 444 | case 'C': 445 | controlprog = optarg; 446 | break; 447 | case 'c': 448 | configfile = optarg; 449 | break; 450 | case 'D': 451 | dbfile = optarg; 452 | break; 453 | case 'd': 454 | debug++; 455 | break; 456 | case 'f': 457 | flush++; 458 | break; 459 | case 'P': 460 | spath = optarg; 461 | break; 462 | case 'R': 463 | rulename = optarg; 464 | break; 465 | case 'r': 466 | restore++; 467 | break; 468 | case 's': 469 | if (nblsock >= maxblsock) { 470 | maxblsock += 10; 471 | void *p = realloc(blsock, 472 | sizeof(*blsock) * maxblsock); 473 | if (p == NULL) 474 | err(EXIT_FAILURE, 475 | "Can't allocate memory for %zu sockets", 476 | maxblsock); 477 | blsock = p; 478 | } 479 | blsock[nblsock++] = optarg; 480 | break; 481 | case 't': 482 | tout = atoi(optarg) * 1000; 483 | break; 484 | case 'v': 485 | vflag++; 486 | break; 487 | default: 488 | usage(c); 489 | } 490 | } 491 | 492 | argc -= optind; 493 | if (argc) 494 | usage('?'); 495 | 496 | signal(SIGHUP, sighup); 497 | signal(SIGINT, sigdone); 498 | signal(SIGQUIT, sigdone); 499 | signal(SIGTERM, sigdone); 500 | signal(SIGUSR1, sigusr1); 501 | signal(SIGUSR2, sigusr2); 502 | 503 | openlog(getprogname(), LOG_PID, LOG_DAEMON); 504 | 505 | if (debug) { 506 | lfun = dlog; 507 | if (tout == 0) 508 | tout = 5000; 509 | } else { 510 | if (tout == 0) 511 | tout = 15000; 512 | } 513 | 514 | update_interfaces(); 515 | conf_parse(configfile); 516 | if (flush) { 517 | rules_flush(); 518 | if (!restore) 519 | flags |= O_TRUNC; 520 | } 521 | 522 | struct pollfd *pfd = NULL; 523 | bl_t *bl = NULL; 524 | size_t nfd = 0; 525 | size_t maxfd = 0; 526 | 527 | for (size_t i = 0; i < nblsock; i++) 528 | addfd(&pfd, &bl, &nfd, &maxfd, blsock[i]); 529 | free(blsock); 530 | 531 | if (spath) { 532 | FILE *fp = fopen(spath, "r"); 533 | char *line; 534 | if (fp == NULL) 535 | err(EXIT_FAILURE, "Can't open `%s'", spath); 536 | for (; (line = fparseln(fp, NULL, NULL, NULL, 0)) != NULL; 537 | free(line)) 538 | addfd(&pfd, &bl, &nfd, &maxfd, line); 539 | fclose(fp); 540 | } 541 | if (nfd == 0) 542 | addfd(&pfd, &bl, &nfd, &maxfd, _PATH_BLSOCK); 543 | 544 | state = state_open(dbfile, flags, 0600); 545 | if (state == NULL) 546 | state = state_open(dbfile, flags | O_CREAT, 0600); 547 | else { 548 | if (restore) { 549 | if (!flush) 550 | rules_flush(); 551 | rules_restore(); 552 | } 553 | } 554 | if (state == NULL) 555 | return EXIT_FAILURE; 556 | 557 | if (!debug) { 558 | if (daemon(0, 0) == -1) 559 | err(EXIT_FAILURE, "daemon failed"); 560 | if (pidfile(NULL) == -1) 561 | err(EXIT_FAILURE, "Can't create pidfile"); 562 | } 563 | 564 | for (size_t t = 0; !done; t++) { 565 | if (readconf) { 566 | readconf = 0; 567 | conf_parse(configfile); 568 | } 569 | ret = poll(pfd, (nfds_t)nfd, tout); 570 | if (debug) 571 | (*lfun)(LOG_DEBUG, "received %d from poll()", ret); 572 | switch (ret) { 573 | case -1: 574 | if (errno == EINTR) 575 | continue; 576 | (*lfun)(LOG_ERR, "poll (%m)"); 577 | return EXIT_FAILURE; 578 | case 0: 579 | state_sync(state); 580 | break; 581 | default: 582 | for (size_t i = 0; i < nfd; i++) 583 | if (pfd[i].revents & POLLIN) 584 | process(bl[i]); 585 | } 586 | if (t % 100 == 0) 587 | state_sync(state); 588 | if (t % 10000 == 0) 589 | update_interfaces(); 590 | update(); 591 | } 592 | state_close(state); 593 | return 0; 594 | } 595 | --------------------------------------------------------------------------------