]> git.ipfire.org Git - people/ms/network.git/blame - functions.firewall
firewall: Create a basic layout of the firewall chains.
[people/ms/network.git] / functions.firewall
CommitLineData
98146c00
MT
1#!/bin/bash
2###############################################################################
3# #
4# IPFire.org - A linux based firewall #
5# Copyright (C) 2012 IPFire Network Development Team #
6# #
7# This program is free software: you can redistribute it and/or modify #
8# it under the terms of the GNU General Public License as published by #
9# the Free Software Foundation, either version 3 of the License, or #
10# (at your option) any later version. #
11# #
12# This program is distributed in the hope that it will be useful, #
13# but WITHOUT ANY WARRANTY; without even the implied warranty of #
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15# GNU General Public License for more details. #
16# #
17# You should have received a copy of the GNU General Public License #
18# along with this program. If not, see <http://www.gnu.org/licenses/>. #
19# #
20###############################################################################
21
22# High-level function which will create a ruleset for the current firewall
23# configuration and load it into the kernel.
24function firewall_start() {
afb7d704
MT
25 # Test mode.
26 local test="false"
27
28 while [ $# -gt 0 ]; do
29 case "${1}" in
30 --test)
31 test="true"
32 ;;
33 esac
34 shift
35 done
36
37 if enabled test; then
38 log INFO "Test mode enabled."
39 log INFO "The firewall ruleset will not be loaded."
40 fi
41
98146c00
MT
42 firewall_lock_acquire
43
44 # Initialize an empty iptables ruleset.
45 iptables_init DROP
46
47 # Add default chains.
48 firewall_tcp_state_flags
3b256a38 49 firewall_custom_chains
98146c00 50 firewall_connection_tracking
c2d2d2a9 51 firewall_tcp_clamp_mss
98146c00
MT
52
53 # Add policies for every zone.
a2c9dff5 54 firewall_localhost_create_chains
98146c00
MT
55
56 local zone
57 for zone in $(zones_get_all); do
a2c9dff5
MT
58 # Create all needed chains for the zone.
59 firewall_zone_create_chains ${zone}
60
61 # After the chains that are always available have been
62 # created, we will add a custom policy to every single
63 # zone.
64
65 # XXX TODO
66 #policy_zone_add ${zone}
98146c00
MT
67 done
68
afb7d704
MT
69 # Load the new ruleset.
70 iptables_load ${test}
98146c00
MT
71
72 firewall_lock_release
73}
74
75function firewall_stop() {
76 firewall_lock_acquire
77
78 # Initialize an empty firewall ruleset
79 # with default policy ACCEPT.
80 iptables_init ACCEPT
81
afb7d704
MT
82 # Load it.
83 iptables_load
84
85 firewall_lock_release
86}
87
88function firewall_show() {
89 # Shows the ruleset that is currently loaded.
90 iptables_status
91
92 return ${EXIT_OK}
93}
94
95function firewall_panic() {
96 local admin_hosts="$@"
97
98 firewall_lock_acquire
99
100 # Drop all communications.
101 iptables_init DROP
102
103 # If an admin host is provided, some administrative
104 # things will be allowed from there.
105 local admin_host
106 for admin_host in ${admin_hosts}; do
107 iptables -A INPUT -s ${admin_host} -j ACCEPT
108 iptables -A OUTPUT -d ${admin_host} -j ACCEPT
109 done
110
111 # Load it.
112 iptables_load
98146c00
MT
113
114 firewall_lock_release
115}
116
117function firewall_lock_acquire() {
118 lock_acquire ${RUN_DIR}/.firewall_lock
119
120 # Make sure the lock is released after the firewall
121 # script has crashed or exited early.
122 trap firewall_lock_release EXIT TERM KILL
123
124 # Create a directory where we can put our
125 # temporary data in the most secure way as possible.
126 IPTABLES_TMPDIR=$(mktemp -d)
127}
128
129function firewall_lock_release() {
130 if isset IPTABLES_TMPDIR; then
131 # Remove all temporary data.
132 rm -rf ${IPTABLES_TMPDIR}
133
134 # Reset the tempdir variable.
135 IPTABLES_TMPDIR=
136 fi
137
138 # Reset the trap.
139 trap true EXIT TERM KILL
140
141 lock_release ${RUN_DIR}/.firewall_lock
142}
143
3b256a38
MT
144function firewall_custom_chains() {
145 log INFO "Creating CUSTOM* chains..."
146
147 # These chains are intened to be filled with
148 # rules by the user. They are processed at the very
149 # beginning so it is possible to overwrite everything.
150
151 iptables_chain_create CUSTOMINPUT
152 iptables -A INPUT -j CUSTOMINPUT
153
154 iptables_chain_create CUSTOMFORWARD
155 iptables -A FORWARD -j CUSTOMFORWARD
156
157 iptables_chain_create CUSTOMOUTPUT
158 iptables -A OUTPUT -j CUSTOMOUTPUT
159
160 iptables_chain_create -4 -t nat CUSTOMPREROUTING
161 iptables -4 -t nat -A PREROUTING -j CUSTOMPREROUTING
162
163 iptables_chain_create -4 -t nat CUSTOMPOSTROUTING
164 iptables -4 -t nat -A POSTROUTING -j CUSTOMPOSTROUTING
165
166 iptables_chain_create -4 -t nat CUSTOMOUTPUT
167 iptables -4 -t nat -A OUTPUT -j CUSTOMOUTPUT
168}
169
98146c00
MT
170function firewall_tcp_state_flags() {
171 log INFO "Creating TCP State Flags chain..."
172 iptables_chain_create BADTCP_LOG
173 iptables -A BADTCP_LOG -p tcp -j $(iptables_LOG "Illegal TCP state: ")
174 iptables -A BADTCP_LOG -j DROP
175
176 iptables_chain_create BADTCP
177 iptables -A BADTCP -p tcp --tcp-flags ALL NONE -j BADTCP_LOG
178 iptables -A BADTCP -p tcp --tcp-flags SYN,FIN SYN,FIN -j BADTCP_LOG
179 iptables -A BADTCP -p tcp --tcp-flags SYN,RST SYN,RST -j BADTCP_LOG
180 iptables -A BADTCP -p tcp --tcp-flags FIN,RST FIN,RST -j BADTCP_LOG
181 iptables -A BADTCP -p tcp --tcp-flags ACK,FIN FIN -j BADTCP_LOG
182 iptables -A BADTCP -p tcp --tcp-flags ACK,PSH PSH -j BADTCP_LOG
183 iptables -A BADTCP -p tcp --tcp-flags ACK,URG URG -j BADTCP_LOG
184
185 iptables -A INPUT -p tcp -j BADTCP
186 iptables -A OUTPUT -p tcp -j BADTCP
187 iptables -A FORWARD -p tcp -j BADTCP
188}
189
c2d2d2a9 190function firewall_tcp_clamp_mss() {
fc323fc4
MT
191 # Do nothing if this has been disabled.
192 enabled FIREWALL_CLAMP_PATH_MTU || return ${EXIT_OK}
193
c2d2d2a9
MT
194 log DEBUG "Adding rules to clamp MSS to path MTU..."
195 iptables -t mangle -A FORWARD \
196 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
197}
198
98146c00
MT
199function firewall_connection_tracking() {
200 log INFO "Creating Connection Tracking chain..."
201 iptables_chain_create CONNTRACK
202 iptables -A CONNTRACK -m state --state ESTABLISHED,RELATED -j ACCEPT
203 iptables -A CONNTRACK -m state --state INVALID -j $(iptables_LOG "INVALID packet: ")
204 iptables -A CONNTRACK -m state --state INVALID -j DROP
205
206 iptables -A INPUT -j CONNTRACK
207 iptables -A OUTPUT -j CONNTRACK
208 iptables -A FORWARD -j CONNTRACK
209}
3647b19f 210
a2c9dff5
MT
211function firewall_localhost_create_chains() {
212 log DEBUG "Creating firewall chains for localhost..."
213
214 # Accept everything on lo
215 iptables -A INPUT -i lo -m state --state NEW -j ACCEPT
216 iptables -A OUTPUT -o lo -m state --state NEW -j ACCEPT
217}
218
219function firewall_zone_create_chains() {
3647b19f 220 local zone=${1}
a2c9dff5
MT
221 assert isset zone
222
223 log DEBUG "Creating firewall chains for zone '${zone}'."
224
225 local chain_prefix="ZONE_${zone^^}"
226
227 # Create filter chains.
228 iptables_chain_create "${chain_prefix}_INPUT"
229 iptables -A INPUT -i ${zone} -j "${chain_prefix}_INPUT"
230
231 iptables_chain_create "${chain_prefix}_OUTPUT"
232 iptables -A OUTPUT -o ${zone} -j "${chain_prefix}_OUTPUT"
233
234 # Custom rules.
235 iptables_chain_create "${chain_prefix}_CUSTOM"
236
237 # Intrusion Prevention System.
238 iptables_chain_create "${chain_prefix}_IPS"
239
240 # Create a chain for each other zone.
241 # This leaves us with n^2 chains. Duh.
242
243 local other_zone other_chain_prefix
244 for other_zone in $(zones_get_all); do
245 other_chain_prefix="${chain_prefix}_${other_zone^^}"
246 iptables_chain_create ${other_chain_prefix}
247
248 # Connect the chain with the FORWARD chain.
249 iptables -A FORWARD -i ${zone} -o ${other_zone} \
250 -j "${other_chain_prefix}"
251
252 # Handle custom rules.
253 iptables -A ${other_chain_prefix} -j "${chain_prefix}_CUSTOM"
254
255 # Link IPS.
256 iptables -A ${other_chain_prefix} -j "${chain_prefix}_IPS"
257
258 # Rules.
259 iptables_chain_create "${other_chain_prefix}_RULES"
260 iptables -A ${other_chain_prefix} -j "${other_chain_prefix}_RULES"
261
262 # Policy.
263 iptables_chain_create "${other_chain_prefix}_POLICY"
264 iptables -A ${other_chain_prefix} -j "${other_chain_prefix}_POLICY"
265 done
266
267 ## Create mangle chain.
268 #iptables_chain_create -t mangle ${chain_prefix}
269 #iptables -t mangle -A PREROUTING -i ${zone} -j ${chain_prefix}
270 #iptables -t mangle -A POSTROUTING -o ${zone} -j ${chain_prefix}
271
272 ## Quality of Service
273 #iptables_chain_create -t mangle "${chain_prefix}_QOS_INC"
274 #iptables -t mangle -A ${chain_prefix} -i ${zone} -j "${chain_prefix}_QOS_INC"
275 #iptables_chain_create -t mangle "${chain_prefix}_QOS_OUT"
276 #iptables -t mangle -A ${chain_prefix} -o ${zone} -j "${chain_prefix}_QOS_OUT"
277
278 # Create NAT chain.
279 iptables_chain_create -4 -t nat ${chain_prefix}
280 iptables -4 -t nat -A PREROUTING -i ${zone} -j ${chain_prefix}
281 iptables -4 -t nat -A POSTROUTING -o ${zone} -j ${chain_prefix}
282
283 # Network Address Translation
284 iptables_chain_create -4 -t nat "${chain_prefix}_DNAT"
285 iptables -4 -t nat -A PREROUTING -i ${zone} -j "${chain_prefix}_DNAT"
286 iptables_chain_create -4 -t nat "${chain_prefix}_SNAT"
287 iptables -4 -t nat -A POSTROUTING -o ${zone} -j "${chain_prefix}_SNAT"
288
289 # UPnP
290 iptables_chain_create -4 -t nat "${chain_prefix}_UPNP"
291 iptables -4 -t nat -A ${chain_prefix} -j "${chain_prefix}_UPNP"
292
293 return ${EXIT_OK}
294}
295
296function firewall_parse_rules() {
297 local file=${1}
298 assert isset file
3647b19f
MT
299 shift
300
a2c9dff5
MT
301 # End if no rule file exists.
302 [ -r "${file}" ] || return ${EXIT_OK}
3647b19f 303
a2c9dff5
MT
304 local cmd
305
306 local ${FIREWALL_RULES_CONFIG_PARAMS}
307 local line
308 while read -r line; do
309 # Skip empty lines.
310 [ -n "${line}" ] || continue
311
312 # Skip commented lines.
313 [ "${line:0:1}" = "#" ] && continue
314
315 # Parse the rule.
316 _firewall_parse_rule_line ${line}
317 if [ $? -ne ${EXIT_OK} ]; then
318 log WARNING "Skipping invalid line: ${line}"
319 continue
320 fi
321
322 cmd="iptables $@"
323
324 # Source IP address/net.
325 if isset src; then
326 list_append cmd "-s ${src}"
327 fi
328
329 # Destination IP address/net.
330 if isset dst; then
331 list_append cmd "-d ${dst}"
332 fi
333
334 # Protocol.
335 if isset proto; then
336 list_append cmd "-p ${proto}"
337
338 if list_match ${proto} ${FIREWALL_PROTOCOLS_SUPPORTING_PORTS}; then
339 if isset sport; then
340 list_append cmd "--sport ${sport}"
341 fi
342
343 if isset dport; then
344 list_append cmd "--dport ${dport}"
345 fi
346 fi
347 fi
348
349 # Always append the action.
350 list_append cmd "-j ${action}"
351
352 # Execute command.
353 ${cmd}
354 done < ${file}
355}
356
357function _firewall_parse_rule_line() {
358 local arg
359
360 # Clear all values.
361 for arg in ${FIREWALL_RULES_CONFIG_PARAMS}; do
362 assign "${arg}" ""
3647b19f
MT
363 done
364
a2c9dff5
MT
365 local key val
366 while read -r arg; do
367 key=$(cli_get_key ${arg})
3647b19f 368
a2c9dff5
MT
369 if ! listmatch "${key}" ${FIREWALL_RULES_CONFIG_PARAMS}; then
370 log WARNING "Unrecognized argument: ${arg}"
371 return ${EXIT_ERROR}
372 fi
3647b19f 373
a2c9dff5
MT
374 val=$(cli_get_val ${arg})
375 assign "${key}" "${val}"
376 done <<< "$(args $@)"
377
378 # action must always be set.
379 if ! isset action; then
380 log WARNING "'action' is not set: $@"
381 return ${EXIT_ERROR}
382 fi
383
384 for arg in src dst; do
385 isset ${arg} || continue
386
387 # Check for valid IP addresses.
388 if ! ip_is_valid ${!arg}; then
389 log WARNING "Invalid IP address for '${arg}=${!arg}': $@"
390 return ${EXIT_ERROR}
391 fi
392 done
393
394 if isset proto; then
395 # Make lowercase.
396 proto=${proto,,}
397
398 if ! list_match "${proto}" ${FIREWALL_SUPPORTED_PROTOCOLS}; then
399 log WARNING "Unsupported protocol type 'proto=${proto}': $@"
400 return ${EXIT_ERROR}
401 fi
402 fi
403
404 for arg in sport dport; do
405 isset ${arg} || continue
406
407 # Check if port is valid.
408 if ! isinteger ${arg}; then
409 log WARNING "Invalid port '${arg}=${!arg}': $@"
410 return ${EXIT_ERROR}
411 fi
412 done
413
414 return ${EXIT_OK}
3647b19f 415}