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 12pf= 13if [ -f "/etc/ipfw-blacklist.rc" ]; then 14 echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" >&2 15 echo "@ WARNING: rename /etc/ipfw-blacklist.rc to @" >&2 16 echo "@ /etc/ipfw-blocklist.rc @" >&2 17 echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" >&2 18 19 pf="ipfw" 20 . /etc/ipfw-blacklist.rc 21 ipfw_offset=${ipfw_offset:-2000} 22fi 23 24if [ -z "$pf" ]; then 25 for f in npf pf ipfilter ipfw; do 26 if [ -x /etc/rc.d/$f ]; then 27 if /etc/rc.d/$f status >/dev/null 2>&1; then 28 pf="$f" 29 break 30 fi 31 elif [ -f "/etc/$f.conf" ]; then 32 # xxx assume a config file means it can be enabled -- 33 # and the first one wins! 34 pf="$f" 35 break 36 fi 37 done 38fi 39 40if [ -z "$pf" -a -x "/sbin/iptables" ]; then 41 pf="iptables" 42fi 43 44if [ -z "$pf" ]; then 45 echo "$0: Unsupported packet filter" 1>&2 46 exit 1 47fi 48 49flags= 50if [ -n "$3" ]; then 51 raw_proto="$3" 52 proto="proto $3" 53 if [ $3 = "tcp" ]; then 54 flags="flags S/SAFR" 55 fi 56fi 57 58if [ -n "$6" ]; then 59 raw_port="$6" 60 port="port $6" 61fi 62 63addr="$4" 64mask="$5" 65case "$4" in 66::ffff:*.*.*.*) 67 if [ "$5" = 128 ]; then 68 mask=32 69 addr=${4#::ffff:} 70 fi;; 71esac 72 73if [ "$pf" = "pf" ]; then 74 for anchor in $(/sbin/pfctl -s Anchors 2> /dev/null); do 75 if [ "$anchor" = "blacklistd" ]; then 76 echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" >&2 77 echo "@ WARNING: rename the blacklist anchor to blocklist @" >&2 78 echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" >&2 79 fi 80 done 81fi 82 83if [ "$pf" = "ipfilter" ]; then 84 echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" >&2 85 echo "@ WARNING: blacklist has been renamed to blocklist @" >&2 86 echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" >&2 87fi 88 89case "$1" in 90add) 91 case "$pf" in 92 ipfilter) 93 # N.B.: If you reload /etc/ipf.conf then you need to stop and 94 # restart blacklistd (and make sure blacklistd_flags="-r"). 95 # This should normally already be implemented in 96 # /etc/rc.d/ipfilter, but if then not add the following lines to 97 # the end of the ipfilter_reload() function: 98 # 99 # if checkyesnox blacklistd; then 100 # /etc/rc.d/blacklistd restart 101 # fi 102 # 103 # XXX we assume the following rule is present in /etc/ipf.conf: 104 # (should we check? -- it probably cannot be added dynamically) 105 # 106 # block in proto tcp/udp from any to any head blacklistd 107 # 108 # where "blacklistd" is the default rulename (i.e. "$2") 109 # 110 # This rule can come before any rule that logs connections, 111 # etc., and should be followed by final rules such as: 112 # 113 # # log all as-yet unblocked incoming TCP connection 114 # # attempts 115 # log in proto tcp from any to any flags S/SAFR 116 # # last "pass" match wins for all non-blocked packets 117 # pass in all 118 # pass out all 119 # 120 # I.e. a "pass" rule which will be the final match and override 121 # the "block". This way the rules added by blacklistd will 122 # actually block packets, and prevent logging of them as 123 # connections, because they include the "quick" flag. 124 # 125 # N.b.: $port is not included/used in rules -- abusers are cut 126 # off completely from all services! 127 # 128 # Note RST packets are not returned for blocked SYN packets of 129 # active attacks, so the port will not appear to be closed. 130 # This will probably give away the fact that a firewall has been 131 # triggered to block connections, but it prevents generating 132 # extra outbound traffic, and it may also slow down the attacker 133 # somewhat. 134 # 135 # Note also that we don't block all packets, just new attempts 136 # to open connections (see $flags above). This allows us to do 137 # counterespionage against the attacker (or continue to make use 138 # of any other services that might be on the same subnet as the 139 # supposed attacker). However it does not kill any active 140 # connections -- we rely on the reporting daemon to do its own 141 # protection and cleanup. 142 # 143 # N.B.: The rule generated here must exactly match the 144 # corresponding rule generated for the "rem" command below! 145 # 146 echo block in log quick $proto \ 147 from $addr/$mask to any $flags group $2 | \ 148 /sbin/ipf -A -f - >/dev/null 2>&1 && echo OK 149 ;; 150 151 ipfw) 152 # use $ipfw_offset+$port for rule number 153 rule=$(($ipfw_offset + $6)) 154 tname="port$6" 155 /sbin/ipfw table $tname create type addr 2>/dev/null 156 /sbin/ipfw -q table $tname add "$addr/$mask" 157 # if rule number $rule does not already exist, create it 158 /sbin/ipfw show $rule >/dev/null 2>&1 || \ 159 /sbin/ipfw add $rule drop $3 from \ 160 table"("$tname")" to any dst-port $6 >/dev/null && \ 161 echo OK 162 ;; 163 164 iptables) 165 if ! /sbin/iptables --list "$2" >/dev/null 2>&1; then 166 /sbin/iptables --new-chain "$2" 167 fi 168 /sbin/iptables --append INPUT --proto "$raw_proto" \ 169 --dport "$raw_port" --jump "$2" 170 /sbin/iptables --append "$2" --proto "$raw_proto" \ 171 --source "$addr/$mask" --dport "$raw_port" --jump DROP 172 echo OK 173 ;; 174 175 npf) 176 /sbin/npfctl rule "$2" add block in final $proto from \ 177 "$addr/$mask" to any $port 178 ;; 179 180 pf) 181 # if the filtering rule does not exist, create it 182 /sbin/pfctl -a "$2/$6" -sr 2>/dev/null | \ 183 grep -q "<port$6>" || \ 184 echo "block in quick $proto from <port$6> to any $port" | \ 185 /sbin/pfctl -a "$2/$6" -f - 186 # insert $ip/$mask into per-protocol/port anchored table 187 /sbin/pfctl -qa "$2/$6" -t "port$6" -T add "$addr/$mask" && \ 188 /sbin/pfctl -qk "$addr" && echo OK 189 ;; 190 191 esac 192 ;; 193rem) 194 case "$pf" in 195 ipfilter) 196 # N.B.: The rule generated here must exactly match the 197 # corresponding rule generated for the "add" command above! 198 # 199 echo block in log quick $proto \ 200 from $addr/$mask to any $flags group $2 | \ 201 /sbin/ipf -A -r -f - >/dev/null 2>&1 && echo OK 202 ;; 203 204 ipfw) 205 /sbin/ipfw table "port$6" delete "$addr/$mask" 2>/dev/null && \ 206 echo OK 207 ;; 208 209 iptables) 210 if /sbin/iptables --list "$2" >/dev/null 2>&1; then 211 /sbin/iptables --delete "$2" --proto "$raw_proto" \ 212 --source "$addr/$mask" --dport "$raw_port" \ 213 --jump DROP 214 fi 215 echo OK 216 ;; 217 218 npf) 219 /sbin/npfctl rule "$2" rem-id "$7" 220 ;; 221 222 pf) 223 /sbin/pfctl -qa "$2/$6" -t "port$6" -T delete "$addr/$mask" && \ 224 echo OK 225 ;; 226 227 esac 228 ;; 229flush) 230 case "$pf" in 231 ipfilter) 232 # 233 # N.B. WARNING: This is obviously not reentrant! 234 # 235 # First we flush all the rules from the inactive set, then we 236 # reload the ones that do not belong to the group "$2", and 237 # finally we swap the active and inactive rule sets. 238 # 239 /sbin/ipf -I -F a 240 # 241 # "ipf -I -F a" also flushes active accounting rules! 242 # 243 # Note that accounting rule groups are unique to accounting 244 # rules and have nothing to do with filter rules, though of 245 # course theoretically one could use the same group name for 246 # them too. 247 # 248 # In theory anyone using any such accounting rules should have a 249 # wrapper /etc/rc.conf.d/blacklistd script (and corresponding 250 # /etc/rc.conf.d/ipfilter script) that will record and 251 # consolidate the values accumulated by such accounting rules 252 # before they are flushed, since otherwise their counts will be 253 # lost forever. 254 # 255 /usr/sbin/ipfstat -io | fgrep -v "group $2" | \ 256 /sbin/ipf -I -f - >/dev/null 2>&1 257 # 258 # This MUST be done last and separately as "-s" is executed 259 # _while_ the command arguments are being processed! 260 # 261 /sbin/ipf -s && echo OK 262 ;; 263 264 ipfw) 265 /sbin/ipfw table "port$6" flush 2>/dev/null && echo OK 266 ;; 267 268 iptables) 269 if /sbin/iptables --list "$2" >/dev/null 2>&1; then 270 /sbin/iptables --flush "$2" 271 fi 272 echo OK 273 ;; 274 275 npf) 276 /sbin/npfctl rule "$2" flush 277 ;; 278 279 pf) 280 # dynamically determine which anchors exist 281 for anchor in $(/sbin/pfctl -a "$2" -s Anchors 2> /dev/null); do 282 /sbin/pfctl -a "$anchor" -t "port${anchor##*/}" -T flush 2> /dev/null 283 /sbin/pfctl -a "$anchor" -F rules 284 done 285 echo OK 286 ;; 287 esac 288 ;; 289*) 290 echo "$0: Unknown command '$1'" 1>&2 291 exit 1 292 ;; 293esac 294