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