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