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