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