TODO and ipfilter improvements from Greg A. Woods

This commit is contained in:
christos 2021-03-07 00:46:39 +00:00
parent f525b84e77
commit 0449daef3f
3 changed files with 205 additions and 12 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: TODO,v 1.1.1.1 2020/06/15 01:52:52 christos Exp $
# $NetBSD: TODO,v 1.2 2021/03/07 00:46:39 christos Exp $
- don't poll periodically, find the next timeout
- use the socket also for commands? Or separate socket?
@ -19,3 +19,89 @@
unblock
- do we need an api in blocklistctl to perform maintenance
- fix the blocklistctl output to be more user friendly
- figure out some way to do distributed operation securely (perhaps with
a helper daemon that authenticates local sockets and then communicates
local DB changes to the central server over a secure channel --
perhaps blocklistd-helper can have a back-end that can send updates to
a central server)
- add "blocklistd -l" to enable filter logging on all rules by default
- add some new options in the config file
"/all" - block both TCP and UDP (on the proto field?)
"/log" - enable filter logging (if not the default) (on the name field?)
"/nolog"- disable filter logging (if not the default) (on the name field?)
The latter two probably require a new parameter for blocklistd-helper.
- "blocklistd -f" should (also?) be a blocklistctl function!?!?!
- if blocklistd was started with '-r' then a SIGHUP should also do a
"control flush $rulename" and then re-add all the filter rules?
- should/could /etc/rc.conf.d/ipfilter be created with the following?
reload_postcmd=blocklistd_reload
start_postcmd=blocklistd_start
stop_precmd=blocklistd_stop
blocklistd_reload ()
{
/etc/rc.d/blocklistd reload # IFF SIGHUP does flush/re-add
# /etc/rc.d/blocklistd restart
}
blocklistd_stop ()
{
/etc/rc.d/blocklistd stop
}
blocklistd_start ()
{
/etc/rc.d/blocklistd start
}
or is there a better way?
- figure out some way to do distributed operation securely (perhaps with
a helper daemon that authenticates local sockets and then communicates
local DB changes to the central server over a secure channel --
perhaps blocklistd-helper can have a back-end that can send updates to
a central server)
- add "blocklistd -l" to enable filter logging on all rules by default
- add some new options in the config file
"/all" - block both TCP and UDP (on the proto field?)
"/log" - enable filter logging (if not the default) (on the name field?)
"/nolog"- disable filter logging (if not the default) (on the name field?)
The latter two probably require a new parameter for blocklistd-helper.
- "blocklistd -f" should (also?) be a blocklistctl function!?!?!
- if blocklistd was started with '-r' then a SIGHUP should also do a
"control flush $rulename" and then re-add all the filter rules?
- should/could /etc/rc.conf.d/ipfilter be created with the following?
reload_postcmd=blocklistd_reload
start_postcmd=blocklistd_start
stop_precmd=blocklistd_stop
blocklistd_reload ()
{
/etc/rc.d/blocklistd reload # IFF SIGHUP does flush/re-add
# /etc/rc.d/blocklistd restart
}
blocklistd_stop ()
{
/etc/rc.d/blocklistd stop
}
blocklistd_start ()
{
/etc/rc.d/blocklistd start
}
or is there a better way?

View File

@ -1,10 +1,10 @@
#!/bin/sh
#
# $NetBSD: blocklistd,v 1.1.1.1 2020/06/15 01:52:53 christos Exp $
# $NetBSD: blocklistd,v 1.2 2021/03/07 00:46:39 christos Exp $
#
# PROVIDE: blocklistd
# REQUIRE: npf
# REQUIRE: npf pf ipfilter
# BEFORE: SERVERS
$_rc_subr_loaded . /etc/rc.subr

View File

@ -17,7 +17,7 @@ if [ -f "/etc/ipfw-blocklist.rc" ]; then
fi
if [ -z "$pf" ]; then
for f in npf pf ipf; do
for f in npf pf ipfilter; do
if [ -f "/etc/$f.conf" ]; then
pf="$f"
break
@ -25,16 +25,26 @@ if [ -z "$pf" ]; then
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
@ -52,11 +62,59 @@ 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
# N.B.: If you reload /etc/ipf.conf then you need to stop and
# restart blocklistd (and make sure blocklistd_flags="-r"):
#
# /etc/rc.d/ipfilter reload
# /etc/rc.d/blocklistd restart
#
# XXX we assume the following rule is present in /etc/ipf.conf:
#
# block in proto tcp/udp from any to any head blocklistd
#
# where "blocklistd" is the default rulename (i.e. "$2")
#
# This rule can come before any rule that logs connections,
# etc., and should be followed by final rules such as:
#
# # log all as-yet unblocked incoming TCP connection
# # attempts
# log in proto tcp from any to any flags S/SAFR
# # last "pass" match wins for all non-blocked packets
# pass in all
# pass out all
#
# I.e. a "pass" rule which will be the final match and override
# the "block". This way the rules added by blocklistd will
# actually block packets, and prevent logging of them as
# connections, because they include the "quick" flag.
#
# N.b.: $port is not included -- 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
# 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 generated must exactly match the 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 +127,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 | \
@ -83,40 +154,76 @@ add)
/sbin/pfctl -a "$2/$6" -t "port$6" -T add "$addr/$mask" && \
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
echo block in log quick $proto \
from $addr/$mask to any $flags group $2 | \
/sbin/ipf -A -r -f - >/dev/null 2>&1 && echo OK
;;
ipfw)
/sbin/ipfw table "port$6" delete "$addr/$mask" 2>/dev/null && \
echo OK
;;
iptables)
if /sbin/iptables --list "$2" >/dev/null 2>&1; then
/sbin/iptables --delete "$2" --proto "$raw_proto" \
--source "$addr/$mask" --dport "$raw_port" \
--jump DROP
fi
echo OK
;;
npf)
/sbin/npfctl rule "$2" rem-id "$7"
;;
pf)
/sbin/pfctl -a "$2/$6" -t "port$6" -T delete "$addr/$mask" && \
echo OK
;;
esac
;;
flush)
case "$pf" in
ipf)
#
# XXX this is a slightly convoluted way to remove all the rules
# in the group added for "$2" (i.e. normally by default
# "blocklistd").
#
# N.B. WARNING: This is obviously not reentrant!
#
/sbin/ipf -I -F a
/usr/sbin/ipfstat -io | fgrep -v "group $2" | \
/sbin/ipf -I -f - >/dev/null 2>&1
# XXX this MUST be done last and separately as "-s" is executed
# _while_ the command arguments are being processed!
/sbin/ipf -s && echo OK
/sbin/ipf -Z -I -Fi -s > /dev/null && echo OK
;;
ipfw)
/sbin/ipfw table "port$6" flush 2>/dev/null && echo OK
;;
iptables)
if /sbin/iptables --list "$2" >/dev/null 2>&1; then
/sbin/iptables --flush "$2"
fi
echo OK
;;
npf)
/sbin/npfctl rule "$2" flush
;;
pf)
/sbin/pfctl -a "$2/$6" -t "port$6" -T flush && echo OK
;;