blocklistd-helper revision 1.7 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 else
18 # ipfilter NetBSD, FreeBSD, Linux
19 for f in /etc/ipf.conf /etc/ipf.rules /etc/netscript/ipfilter.conf; do
20 if [ -f "$f" ]; then
21 pf="ipf"
22 break
23 fi
24 done
25 fi
26
27 if [ -z "$pf" ]; then
28 for f in npf pf; do
29 if [ -f "/etc/$f.conf" ]; then
30 pf="$f"
31 break
32 fi
33 done
34 fi
35
36 if [ -z "$pf" -a -x "/sbin/iptables" ]; then
37 pf="iptables"
38 fi
39
40 if [ -z "$pf" ]; then
41 echo "$0: Unsupported packet filter" 1>&2
42 exit 1
43 fi
44
45 flags=
46 if [ -n "$3" ]; then
47 raw_proto="$3"
48 proto="proto $3"
49 if [ $3 = "tcp" ]; then
50 flags="flags S/SAFR"
51 fi
52 fi
53
54 if [ -n "$6" ]; then
55 raw_port="$6"
56 port="port $6"
57 fi
58
59 addr="$4"
60 mask="$5"
61 case "$4" in
62 ::ffff:*.*.*.*)
63 if [ "$5" = 128 ]; then
64 mask=32
65 addr=${4#::ffff:}
66 fi;;
67 esac
68
69 case "$1" in
70 add)
71 case "$pf" in
72 ipf)
73 # N.B.: If you reload /etc/ipf.conf then you need to stop and
74 # restart blocklistd (and make sure blocklistd_flags="-r"):
75 #
76 # /etc/rc.d/ipfilter reload
77 # /etc/rc.d/blocklistd restart
78 #
79 # XXX we assume the following rule is present in /etc/ipf.conf:
80 #
81 # block in proto tcp/udp from any to any head blocklistd
82 #
83 # where "blocklistd" is the default rulename (i.e. "$2")
84 #
85 # This rule can come before any rule that logs connections,
86 # etc., and should be followed by final rules such as:
87 #
88 # # log all as-yet unblocked incoming TCP connection
89 # # attempts
90 # log in proto tcp from any to any flags S/SAFR
91 # # last "pass" match wins for all non-blocked packets
92 # pass in all
93 # pass out all
94 #
95 # I.e. a "pass" rule which will be the final match and override
96 # the "block". This way the rules added by blocklistd will
97 # actually block packets, and prevent logging of them as
98 # connections, because they include the "quick" flag.
99 #
100 # N.b.: $port is not included -- abusers are cut off completely
101 # from all services!
102 #
103 # Note RST packets are not returned for blocked SYN packets of
104 # active attacks, so the port will not appear to be closed.
105 # This will probably give away the fact that a firewall has been
106 # triggered to block connections, but it prevents generating
107 # extra outbound traffic, and it may also slow down the attacker
108 # somewhat.
109 #
110 # Note also that we don't block all packets, just new attempts
111 # to open connections (see $flags above). This allows us to do
112 # counterespionage against the attacker (or continue to make use
113 # of any other services that might be on the same subnet as the
114 # attacker). However it does not kill any active connections --
115 # we rely on the reporting daemon to do its own protection and
116 # cleanup.
117 #
118 # N.B.: The generated must exactly match the rule generated for
119 # the "rem" command below!
120 #
121 echo block in log quick $proto \
122 from $addr/$mask to any $flags group $2 | \
123 /sbin/ipf -A -f - >/dev/null 2>&1 && echo OK
124 ;;
125
126 ipfw)
127 # use $ipfw_offset+$port for rule number
128 rule=$(($ipfw_offset + $6))
129 tname="port$6"
130 /sbin/ipfw table $tname create type addr 2>/dev/null
131 /sbin/ipfw -q table $tname add "$addr/$mask"
132 # if rule number $rule does not already exist, create it
133 /sbin/ipfw show $rule >/dev/null 2>&1 || \
134 /sbin/ipfw add $rule drop $3 from \
135 table"("$tname")" to any dst-port $6 >/dev/null && \
136 echo OK
137 ;;
138
139 iptables)
140 if ! /sbin/iptables --list "$2" >/dev/null 2>&1; then
141 /sbin/iptables --new-chain "$2"
142 fi
143 /sbin/iptables --append INPUT --proto "$raw_proto" \
144 --dport "$raw_port" --jump "$2"
145 /sbin/iptables --append "$2" --proto "$raw_proto" \
146 --source "$addr/$mask" --dport "$raw_port" --jump DROP
147 echo OK
148 ;;
149
150 npf)
151 /sbin/npfctl rule "$2" add block in final $proto from \
152 "$addr/$mask" to any $port
153 ;;
154
155 pf)
156 # if the filtering rule does not exist, create it
157 /sbin/pfctl -a "$2/$6" -sr 2>/dev/null | \
158 grep -q "<port$6>" || \
159 echo "block in quick $proto from <port$6> to any $port" | \
160 /sbin/pfctl -a "$2/$6" -f -
161 # insert $ip/$mask into per-protocol/port anchored table
162 /sbin/pfctl -qa "$2/$6" -t "port$6" -T add "$addr/$mask" && \
163 /sbin/pfctl -qk "$addr" && echo OK
164 ;;
165
166 esac
167 ;;
168 rem)
169 case "$pf" in
170 ipf)
171 echo block in log quick $proto \
172 from $addr/$mask to any $flags group $2 | \
173 /sbin/ipf -A -r -f - >/dev/null 2>&1 && echo OK
174 ;;
175
176 ipfw)
177 /sbin/ipfw table "port$6" delete "$addr/$mask" 2>/dev/null && \
178 echo OK
179 ;;
180
181 iptables)
182 if /sbin/iptables --list "$2" >/dev/null 2>&1; then
183 /sbin/iptables --delete "$2" --proto "$raw_proto" \
184 --source "$addr/$mask" --dport "$raw_port" \
185 --jump DROP
186 fi
187 echo OK
188 ;;
189
190 npf)
191 /sbin/npfctl rule "$2" rem-id "$7"
192 ;;
193
194 pf)
195 /sbin/pfctl -qa "$2/$6" -t "port$6" -T delete "$addr/$mask" && \
196 echo OK
197 ;;
198
199 esac
200 ;;
201 flush)
202 case "$pf" in
203 ipf)
204 #
205 # XXX this is a slightly convoluted way to remove all the rules
206 # in the group added for "$2" (i.e. normally by default
207 # "blocklistd").
208 #
209 # N.B. WARNING: This is obviously not reentrant!
210 #
211 /sbin/ipf -I -F a
212 /usr/sbin/ipfstat -io | fgrep -v "group $2" | \
213 /sbin/ipf -I -f - >/dev/null 2>&1
214 # XXX this MUST be done last and separately as "-s" is executed
215 # _while_ the command arguments are being processed!
216 /sbin/ipf -s && echo OK
217 ;;
218
219 ipfw)
220 /sbin/ipfw table "port$6" flush 2>/dev/null && echo OK
221 ;;
222
223 iptables)
224 if /sbin/iptables --list "$2" >/dev/null 2>&1; then
225 /sbin/iptables --flush "$2"
226 fi
227 echo OK
228 ;;
229
230 npf)
231 /sbin/npfctl rule "$2" flush
232 ;;
233
234 pf)
235 # dynamically determine which anchors exist
236 for anchor in $(/sbin/pfctl -a "$2" -s Anchors); do
237 /sbin/pfctl -a "$anchor" -t "port${anchor##*/}" -T flush
238 /sbin/pfctl -a "$anchor" -F rules
239 done
240 echo OK
241 ;;
242 esac
243 ;;
244 *)
245 echo "$0: Unknown command '$1'" 1>&2
246 exit 1
247 ;;
248 esac
249