The branch stable/13 has been updated by jlduran:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=b781ee1e0b8523ff42d798288225d802164abab5

commit b781ee1e0b8523ff42d798288225d802164abab5
Author:     Jose Luis Duran <[email protected]>
AuthorDate: 2025-11-05 15:18:15 +0000
Commit:     Jose Luis Duran <[email protected]>
CommitDate: 2025-11-05 15:18:48 +0000

    blacklist: Update the blacklistd-helper script
    
    Update the blacklistd-helper script, it provides a better mechanism for
    detecting the active packet filter.
    
    This is a direct commit to stable/13, as blacklist has been renamed to
    blocklist.
    
    PR:             290645
---
 contrib/blacklist/libexec/blacklistd-helper | 175 +++++++++++++++++++++++++---
 1 file changed, 156 insertions(+), 19 deletions(-)

diff --git a/contrib/blacklist/libexec/blacklistd-helper 
b/contrib/blacklist/libexec/blacklistd-helper
index 1af320d426b0..fa53c8c84932 100644
--- a/contrib/blacklist/libexec/blacklistd-helper
+++ b/contrib/blacklist/libexec/blacklistd-helper
@@ -17,24 +17,41 @@ if [ -f "/etc/ipfw-blacklist.rc" ]; then
 fi
 
 if [ -z "$pf" ]; then
-       for f in npf pf ipf; do
-               if [ -f "/etc/$f.conf" ]; then
+       for f in npf pf ipfilter ipfw; do
+               if [ -x /etc/rc.d/$f ]; then
+                       if /etc/rc.d/$f status >/dev/null 2>&1; then
+                               pf="$f"
+                               break
+                       fi
+               elif [ -f "/etc/$f.conf" ]; then
+                       # xxx assume a config file means it can be enabled --
+                       # and the first one wins!
                        pf="$f"
                        break
                fi
        done
 fi
 
+if [ -z "$pf" -a -x "/sbin/iptables" ]; then
+       pf="iptables"
+fi
+
 if [ -z "$pf" ]; then
        echo "$0: Unsupported packet filter" 1>&2
        exit 1
 fi
 
+flags=
 if [ -n "$3" ]; then
+       raw_proto="$3"
        proto="proto $3"
+       if [ $3 = "tcp" ]; then
+               flags="flags S/SAFR"
+       fi
 fi
 
 if [ -n "$6" ]; then
+       raw_port="$6"
        port="port $6"
 fi
 
@@ -51,12 +68,65 @@ esac
 case "$1" in
 add)
        case "$pf" in
-       ipf)
-               /sbin/ipfstat -io | /sbin/ipf -I -f - >/dev/null 2>&1
-               echo block in quick $proto from $addr/$mask to \
-                   any port=$6 head port$6 | \
-                   /sbin/ipf -I -f - -s >/dev/null 2>&1 && echo OK
+       ipfilter)
+               # N.B.:  If you reload /etc/ipf.conf then you need to stop and
+               # restart blacklistd (and make sure blacklistd_flags="-r").
+               # This should normally already be implemented in
+               # /etc/rc.d/ipfilter, but if then not add the following lines to
+               # the end of the ipfilter_reload() function:
+               #
+               #       if checkyesnox blacklistd; then
+               #               /etc/rc.d/blacklistd restart
+               #       fi
+               #
+               # XXX we assume the following rule is present in /etc/ipf.conf:
+               # (should we check? -- it probably cannot be added dynamically)
+               #
+               #       block in proto tcp/udp from any to any head blacklistd
+               #
+               # where "blacklistd" is the default rulename (i.e. "$2")
+               #
+               # This rule can come before any rule that logs connections,
+               # etc., and should be followed by final rules such as:
+               #
+               #       # log all as-yet unblocked incoming TCP connection
+               #       # attempts
+               #       log in proto tcp from any to any flags S/SAFR
+               #       # last "pass" match wins for all non-blocked packets
+               #       pass in all
+               #       pass out all
+               #
+               # I.e. a "pass" rule which will be the final match and override
+               # the "block".  This way the rules added by blacklistd will
+               # actually block packets, and prevent logging of them as
+               # connections, because they include the "quick" flag.
+               #
+               # N.b.:  $port is not included/used in rules -- abusers are cut
+               # off completely from all services!
+               #
+               # Note RST packets are not returned for blocked SYN packets of
+               # active attacks, so the port will not appear to be closed.
+               # This will probably give away the fact that a firewall has been
+               # triggered to block connections, but it prevents generating
+               # extra outbound traffic, and it may also slow down the attacker
+               # somewhat.
+               #
+               # Note also that we don't block all packets, just new attempts
+               # to open connections (see $flags above).  This allows us to do
+               # counterespionage against the attacker (or continue to make use
+               # of any other services that might be on the same subnet as the
+               # supposed attacker).  However it does not kill any active
+               # connections -- we rely on the reporting daemon to do its own
+               # protection and cleanup.
+               #
+               # N.B.:  The rule generated here must exactly match the
+               # corresponding rule generated for the "rem" command below!
+               #
+               echo block in log quick $proto \
+                   from $addr/$mask to any $flags group $2 | \
+                   /sbin/ipf -A -f - >/dev/null 2>&1 && echo OK
                ;;
+
        ipfw)
                # use $ipfw_offset+$port for rule number
                rule=$(($ipfw_offset + $6))
@@ -69,10 +139,23 @@ add)
                        table"("$tname")" to any dst-port $6 >/dev/null && \
                        echo OK
                ;;
+
+       iptables)
+               if ! /sbin/iptables --list "$2" >/dev/null 2>&1; then
+                       /sbin/iptables --new-chain "$2"
+               fi
+               /sbin/iptables --append INPUT --proto "$raw_proto" \
+                   --dport "$raw_port" --jump "$2"
+               /sbin/iptables --append "$2" --proto "$raw_proto" \
+                   --source "$addr/$mask" --dport "$raw_port" --jump DROP
+               echo OK
+               ;;
+
        npf)
                /sbin/npfctl rule "$2" add block in final $proto from \
                    "$addr/$mask" to any $port
                ;;
+
        pf)
                # if the filtering rule does not exist, create it
                /sbin/pfctl -a "$2/$6" -sr 2>/dev/null | \
@@ -81,48 +164,102 @@ add)
                    /sbin/pfctl -a "$2/$6" -f -
                # insert $ip/$mask into per-protocol/port anchored table
                /sbin/pfctl -qa "$2/$6" -t "port$6" -T add "$addr/$mask" && \
-                   /sbin/pfctl -q -k $addr && echo OK
+                   /sbin/pfctl -qk "$addr" && echo OK
                ;;
+
        esac
        ;;
 rem)
        case "$pf" in
-       ipf)
-               /sbin/ipfstat -io | /sbin/ipf -I -f - >/dev/null 2>&1
-               echo block in quick $proto from $addr/$mask to \
-                   any port=$6 head port$6 | \
-                   /sbin/ipf -I -r -f - -s >/dev/null 2>&1 && echo OK
+       ipfilter)
+               # N.B.:  The rule generated here must exactly match the
+               # corresponding rule generated for the "add" command above!
+               #
+               echo block in log quick $proto \
+                   from $addr/$mask to any $flags group $2 | \
+                   /sbin/ipf -A -r -f - >/dev/null 2>&1 && echo OK
                ;;
+
        ipfw)
                /sbin/ipfw table "port$6" delete "$addr/$mask" 2>/dev/null && \
                    echo OK
                ;;
+
+       iptables)
+               if /sbin/iptables --list "$2" >/dev/null 2>&1; then
+                       /sbin/iptables --delete "$2" --proto "$raw_proto" \
+                           --source "$addr/$mask" --dport "$raw_port" \
+                           --jump DROP
+               fi
+               echo OK
+               ;;
+
        npf)
                /sbin/npfctl rule "$2" rem-id "$7"
                ;;
+
        pf)
                /sbin/pfctl -qa "$2/$6" -t "port$6" -T delete "$addr/$mask" && \
                    echo OK
                ;;
+
        esac
        ;;
 flush)
        case "$pf" in
-       ipf)
-               /sbin/ipf -Z -I -Fi -s > /dev/null && echo OK
+       ipfilter)
+               #
+               # N.B. WARNING:  This is obviously not reentrant!
+               #
+               # First we flush all the rules from the inactive set, then we
+               # reload the ones that do not belong to the group "$2", and
+               # finally we swap the active and inactive rule sets.
+               #
+               /sbin/ipf -I -F a
+               #
+               # "ipf -I -F a" also flushes active accounting rules!
+               #
+               # Note that accounting rule groups are unique to accounting
+               # rules and have nothing to do with filter rules, though of
+               # course theoretically one could use the same group name for
+               # them too.
+               #
+               # In theory anyone using any such accounting rules should have a
+               # wrapper /etc/rc.conf.d/blacklistd script (and corresponding
+               # /etc/rc.conf.d/ipfilter script) that will record and
+               # consolidate the values accumulated by such accounting rules
+               # before they are flushed, since otherwise their counts will be
+               # lost forever.
+               #
+               /usr/sbin/ipfstat -io | fgrep -v "group $2" | \
+                   /sbin/ipf -I -f - >/dev/null 2>&1
+               #
+               # This MUST be done last and separately as "-s" is executed
+               # _while_ the command arguments are being processed!
+               #
+               /sbin/ipf -s && echo OK
                ;;
+
        ipfw)
                /sbin/ipfw table "port$6" flush 2>/dev/null && echo OK
                ;;
+
+       iptables)
+               if /sbin/iptables --list "$2" >/dev/null 2>&1; then
+                       /sbin/iptables --flush "$2"
+               fi
+               echo OK
+               ;;
+
        npf)
                /sbin/npfctl rule "$2" flush
                ;;
+
        pf)
                # dynamically determine which anchors exist
-               anchors=$(/sbin/pfctl -a $2 -s Anchors)
-               for anchor in $anchors; do
-                       /sbin/pfctl -a $anchor -t "port${anchor##*/}" -T flush
-                       /sbin/pfctl -a $anchor -F rules
+               for anchor in $(/sbin/pfctl -a "$2" -s Anchors 2> /dev/null); do
+                       /sbin/pfctl -a "$anchor" -t "port${anchor##*/}" -T flush
+                       /sbin/pfctl -a "$anchor" -F rules
                done
                echo OK
                ;;

Reply via email to