public
Description: A rigorous set of firewall scripts for BSD ipfw, and Linux iptables
Homepage:
Clone URL: git://github.com/jwiegley/jw.firewall.git
jw.firewall / firewall.iptables
100755 250 lines (208 sloc) 10.908 kb
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
249
250
#!/bin/bash
 
IPTABLES=$1
MYNAME=$2
 
######################################################################
#
# rc.firewall
#
# version 1.13 (2007/11/03) by John Wiegley <admin@johnwiegley.com>
#
# This script is based on a similar firewalling script I wrote for ipfw,
# but has been changed to utilize iptables. Also, it is customized
# solely for running on johnwiegley.com, and does not contain any
# configuration options.
#
# Revision history:
# 1.01: Added port knocking for ssh access.
# 1.02: Lock out ssh port scanners for 5 minutes.
# 1.03: Remove port scanners from lockout after 5 mins good behavior.
# 1.04: Flush the nat table as well as the filter (default) table.
# 1.05: Use hashlimit for connection rate limiting instead of recent.
# 1.06: Extended portscan lockout to an entire day.
# 1.07: Removed an excessive rule.
# 1.08: Commented out rate limiting of Apache.
# 1.09: Increased SSH availability to one day.
# 1.10: Drop ICMP redirect packets.
# 1.11: Decrease SYN flood rate limit to 60 conns per second.
# 1.12: Don't filter based on the connection source port.
# 1.13: Opened up the IMAP/S port 993.
#
######################################################################
 
$IPTABLES -F
$IPTABLES -t nat -F
$IPTABLES -X
 
$IPTABLES -t nat -P PREROUTING ACCEPT
$IPTABLES -t nat -P POSTROUTING ACCEPT
$IPTABLES -t nat -P OUTPUT ACCEPT
 
$IPTABLES -t nat -A POSTROUTING -o eth0 -j MASQUERADE
 
$IPTABLES -P INPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT
$IPTABLES -P OUTPUT ACCEPT
 
if [[ $2 == flush ]]; then
exit 0
fi
 
######################################################################
 
$IPTABLES -P INPUT DROP
$IPTABLES -P FORWARD DROP
$IPTABLES -P OUTPUT ACCEPT
 
# Drop invalid packets immediately
$IPTABLES -A INPUT -m state --state INVALID -j DROP
$IPTABLES -A FORWARD -m state --state INVALID -j DROP
$IPTABLES -A OUTPUT -m state --state INVALID -j DROP
 
# Allow trusted interfaces
$IPTABLES -A INPUT -i lo -j ACCEPT
$IPTABLES -A INPUT -i tun+ -j ACCEPT
$IPTABLES -A FORWARD -i tun+ -j ACCEPT
$IPTABLES -A FORWARD -o tun+ -j ACCEPT
 
# Drop suspicious IP packets
#$IPTABLES -A INPUT -m ipv4options --rr -j DROP
#$IPTABLES -A INPUT -m ipv4options --ts -j DROP
#$IPTABLES -A INPUT -m ipv4options --lsrr -j DROP
#$IPTABLES -A INPUT -m ipv4options --ssrr -j DROP
 
# Drop bogus TCP packets
$IPTABLES -A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
$IPTABLES -A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP
 
# Allow multicast DNS packets. jww (2007-09-09): This may be needed at
# Server Axis for determining server presence. I have to ask them.
$IPTABLES -A INPUT -d 224.0.0.251 -p udp -m udp --dport mdns -j ACCEPT
 
# Reject packets from RFC1918 class networks (i.e., spoofed)
$IPTABLES -A INPUT -i eth0 -s 10.0.0.0/8 -j DROP
$IPTABLES -A INPUT -s 192.168.0.0/16 -j DROP
$IPTABLES -A INPUT -s 169.254.0.0/16 -j DROP
if [[ $MYNAME == "johnwiegley.com" ]]; then
    $IPTABLES -A INPUT -s 172.16.0.0/12 -j DROP
fi
$IPTABLES -A INPUT -s 127.0.0.0/8 -j DROP
 
$IPTABLES -A INPUT -s 224.0.0.0/4 -j DROP
$IPTABLES -A INPUT -d 224.0.0.0/4 -j DROP
$IPTABLES -A INPUT -s 240.0.0.0/5 -j DROP
$IPTABLES -A INPUT -d 240.0.0.0/5 -j DROP
$IPTABLES -A INPUT -s 0.0.0.0/8 -j DROP
$IPTABLES -A INPUT -d 0.0.0.0/8 -j DROP
$IPTABLES -A INPUT -d 239.255.255.0/24 -j DROP
$IPTABLES -A INPUT -d 255.255.255.255 -j DROP
 
# Reject packets spoofed to appear as if from us
if [[ $MYNAME == "johnwiegley.com" ]]; then
    $IPTABLES -A INPUT -s 208.70.150.153 -j DROP
    $IPTABLES -A INPUT -s 208.70.150.154 -j DROP
    $IPTABLES -A INPUT -s 208.70.150.155 -j DROP
    $IPTABLES -A INPUT -s 208.70.150.156 -j DROP
    $IPTABLES -A INPUT -s 208.70.150.157 -j DROP
fi
 
# Allow most ICMP packets to be received (so people can check our
# presence), but restrict the flow to avoid ping flood attacks
$IPTABLES -A INPUT -p icmp -m icmp --icmp-type address-mask-request -j DROP
$IPTABLES -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP
$IPTABLES -A INPUT -p icmp -m icmp --icmp-type redirect -j DROP
$IPTABLES -A INPUT -p icmp -m icmp -m limit --limit 1/second -j ACCEPT
 
# Anyone trying to portscan us at port 139 is locked out for 1 day.
$IPTABLES -A INPUT -m recent --name portscan --rcheck --seconds 86400 -j DROP
$IPTABLES -A FORWARD -m recent --name portscan --rcheck --seconds 86400 -j DROP
$IPTABLES -A INPUT -m recent --name portscan --remove
 
$IPTABLES -A INPUT -p tcp -m tcp -i eth0 --dport 139 \
    -m recent --name portscan --set -j LOG --log-level 4 --log-prefix "Portscan:"
$IPTABLES -A INPUT -p tcp -m tcp -i eth0 --dport 139 \
    -m recent --name portscan --set -j DROP
$IPTABLES -A FORWARD -p tcp -m tcp -i eth0 --dport 139 \
    -m recent --name portscan --set -j LOG --log-level 4 --log-prefix "Portscan:"
$IPTABLES -A FORWARD -p tcp -m tcp -i eth0 --dport 139 \
    -m recent --name portscan --set -j DROP
 
# jww (2007-09-09): I don't think this can be done with iptables alone,
# so I satisfy myself with limiting RST packets instead. Intention:
# Delay RST packets by 0.5 seconds to avoid SMURF attacks, by given the
# next real data packet in the sequence a better chance to arrive first.
$IPTABLES -A INPUT -p tcp -m tcp --tcp-flags RST RST \
    -m limit --limit 2/second --limit-burst 2 -j ACCEPT
 
# If we are using IPsec, these rules allow such packets through
#$IPTABLES -A INPUT -p ah -j ACCEPT
#$IPTABLES -A INPUT -p esp -j ACCEPT
 
# Allow established and related packets
$IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
 
# Discard any left over fragments
$IPTABLES -A INPUT -f -j DROP
 
# Protect against SYN floods by rate limiting the number of new
# connections from any host to 60 per second. This does *not* do rate
# limiting overall, because then someone could easily shut us down by
# saturating the limit.
$IPTABLES -A INPUT -m state --state NEW -p tcp -m tcp --syn \
    -m recent --name synflood --update --seconds 1 --hitcount 60 -j DROP
 
# Reply to unknown "NEW" SYN/ACK packets with a RESET, so we can't be
# used as a middle-man for Sequence Number Prediction based spoof
# attacks.
$IPTABLES -A INPUT -m state --state NEW -p tcp -m tcp \
    --tcp-flags SYN,ACK SYN,ACK -j REJECT --reject-with tcp-reset
 
# Log and drop NEW packets which don't have the SYN bit set
$IPTABLES -A INPUT -m state --state NEW -p tcp -m tcp ! --syn \
    -j LOG --log-level 4 --log-prefix "New !SYN:"
$IPTABLES -A INPUT -m state --state NEW -p tcp -m tcp ! --syn -j DROP
 
# If any packets reach this point that have the ACK bit sent (but not
# SYN), respond with a TCP reset
$IPTABLES -A INPUT -p tcp -m tcp --tcp-flags ACK ACK \
    -j REJECT --reject-with tcp-reset
 
# DNS
$IPTABLES -A INPUT -m state --state NEW -p udp -m udp --dport domain -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -p tcp -m tcp --dport domain -j ACCEPT
 
# OpenVPN
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p udp -m udp --dport 1194 -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport 1195 -j ACCEPT
 
# FTP, but allow only 5 open connections per host, and 5 new connections
# per minute from any given host (to block brute force scans)
#$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
# --dport ftp -m connlimit --connlimit-above 5 -j DROP
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport ftp -m hashlimit \
    --hashlimit 5/min --hashlimit-mode srcip --hashlimit-name ftpusers -j ACCEPT
 
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport rsync -m hashlimit \
    --hashlimit 5/min --hashlimit-mode srcip --hashlimit-name ftpusers -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p udp -m udp --dport rsync -m hashlimit \
    --hashlimit 5/min --hashlimit-mode srcip --hashlimit-name ftpusers -j ACCEPT
 
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport git -m hashlimit \
    --hashlimit 5/min --hashlimit-mode srcip --hashlimit-name gitusers -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p udp -m udp --dport git -m hashlimit \
    --hashlimit 5/min --hashlimit-mode srcip --hashlimit-name gitusers -j ACCEPT
 
# SSH, but allow only 2 new connections per minute from any given host
# (to block brute force scans), and only after knocking first at port
# 1908.
#$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
# --dport ssh -m recent --rcheck --seconds 86400 --name sshusers -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
    --dport ssh -j ACCEPT
 
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
    --dport 1907 -m recent --name sshusers --remove \
    -j REJECT --reject-with icmp-admin-prohibited
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
    --dport 1908 -m recent --name sshusers --set \
    -j REJECT --reject-with icmp-admin-prohibited
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
    --dport 1909 -m recent --name sshusers --remove \
    -j REJECT --reject-with icmp-admin-prohibited
 
# Web, but allow only 10 open connections per host, and 40 new
# connections per minute from any given host
#$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
# -m multiport --dports http,https -m connlimit --connlimit-above 10 -j DROP
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp \
    -m multiport --dports http,https -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport 8080 -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport 8007 -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport 9090 -j ACCEPT
$IPTABLES -A INPUT -m state --state NEW -i eth0 -p tcp -m tcp --dport 5050 -j ACCEPT
# -m hashlimit --hashlimit 40/min --hashlimit-mode srcip --hashlimit-name webusers -j ACCEPT
 
# if a connection comes in to .157:80, redirect it to local port 8080
$IPTABLES -t nat -A PREROUTING -s 208.70.150.157 -p tcp -m tcp --dport 80 \
    -j REDIRECT --to-ports 8080
 
# SMTP, but allow only 5 open connections per host, and 10 new connections per
# minute from any given host. And only listen at mail.johnwiegley.com.
DEST=""
if [[ $MYNAME == "johnwiegley.com" ]]; then
DEST="-d 208.70.150.154"
fi
#$IPTABLES -A INPUT -m state --state NEW $DEST -p tcp -m tcp \
# -m multiport --dports smtp,submission -m connlimit --connlimit-above 5 -j DROP
$IPTABLES -A INPUT -m state --state NEW $DEST -p tcp -m tcp \
    -m multiport --dports smtp,submission,imaps -m hashlimit \
    --hashlimit 10/min --hashlimit-mode srcip --hashlimit-name mailusers -j ACCEPT
 
# Reject all others by letting them know that such communication with the host
# is forbidden
$IPTABLES -A INPUT -j REJECT --reject-with icmp-admin-prohibited
 
echo If you can exit me now, things are OK...
sleep 120
 
exec $0 $IPTABLES flush