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