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