]> git.ipfire.org Git - people/stevee/network.git/blame - src/functions/functions.firewall
network fix parameter passing when using ""
[people/stevee/network.git] / src / functions / 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
ef953be2
MT
22# This function initializes all kernel parameters that need to be adjusted
23# to run this firewall properly.
1c6a4e30 24firewall_kernel_init() {
ef953be2
MT
25 log INFO "Configuring kernel parameters..."
26 local option
27
28 # Enable conntrack accounting
29 conntrack_set_accounting "true"
30
31 # Adjust max. amount of simultaneous connections
32 conntrack_set_max_connections "${CONNTRACK_MAX_CONNECTIONS}"
33
34 # Increase UDP connection timeout (fixes DNS)
35 conntrack_set_udp_timeout "${CONNTRACK_UDP_TIMEOUT}"
36
37 # Disable sending redirects
38 log INFO "Disabling sending redirects"
39 sysctl_set_recursively "net.ipv6.conf" "send_redirects" 0
40 sysctl_set_recursively "net.ipv4.conf" "send_redirects" 0
41
42 # Enable source route protection
43 log INFO "Enabling source route protection"
44 sysctl_set_recursively "net.ipv6.conf" "accept_source_route" 0
45 sysctl_set_recursively "net.ipv4.conf" "accept_source_route" 0
46
47 # ICMP broadcast protection (smurf amplifier protection)
48 log INFO "Enabling ICMP broadcast protection (smurf amplifier protection)"
49 sysctl_set "net.ipv4.icmp_echo_ignore_broadcasts" 1
50
51 # ICMP Dead Error Message protection
52 log INFO "Enabling ICMP dead error message protection"
53 sysctl_set "net.ipv4.icmp_ignore_bogus_error_responses" 0
54
55 # Enable packet forwarding
56 log INFO "Enabling packet forwarding"
57 sysctl_set_recursively "net.ipv6.conf" "forwarding" 1
58 sysctl_set_recursively "net.ipv4.conf" "forwarding" 1
59
60 # Setting some kernel performance options
61 log INFO "Setting some kernel performance options"
62 for option in window_scaling timestamps sack dsack fack; do
63 sysctl_set "net.ipv4.tcp_${option}" 1
64 done
65 sysctl_set "net.ipv4.tcp_low_latency" 0
66
67 # Reduce DoS ability by reducing timeouts
68 log INFO "Reducing DoS ability"
69 sysctl_set "net.ipv4.tcp_fin_timeout" 30
70 sysctl_set "net.ipv4.tcp_keepalive_time" 1800
71
72 # Set number of times to retry SYN in a new connection
73 sysctl_set "net.ipv4.tcp_syn_retries" 3
74
75 # Set number of times to retry a SYN-ACK in a half-open new connection
76 sysctl_set "net.ipv4.tcp_synack_retries" 2
77
78 # Enable a fix for RFC1337 - time-wait assassination hazards in TCP
79 sysctl_set "net.ipv4.tcp_rfc1337" 1
80
81 # SYN-flood protection
82 if enabled FIREWALL_SYN_COOKIES; then
83 log INFO "Enabling SYN-flood protection via SYN-cookies"
84 sysctl_set_bool "net.ipv4.tcp_syncookies" 1
85 else
86 log INFO "Disabling SYN-flood protection via SYN-cookies"
87 sysctl_set_bool "net.ipv4.tcp_syncookies" 0
88 fi
89
90 # rp_filter
91 if enabled FIREWALL_RP_FILTER; then
92 log INFO "Enabling anti-spoof from non-routable IP addresses"
93 sysctl_set_recursively "net.ipv4.conf" "rp_filter" 1
94 else
95 log INFO "Disabling anti-spoof from non-routable IP addresses"
96 sysctl_set_recursively "net.ipv4.conf" "rp_filter" 0
97 fi
98
99 # Log martians
100 if enabled FIREWALL_LOG_MARTIANS; then
101 log INFO "Enabling the logging of martians"
102 sysctl_set_recursively "net.ipv4.conf" "log_martians" 1
103 else
104 log INFO "Disabling the logging of martians"
105 sysctl_set_recursively "net.ipv4.conf" "log_martians" 0
106 fi
107
108 # ICMP redirect messages
109 if enabled FIREWALL_ACCEPT_ICMP_REDIRECTS; then
110 log INFO "Enabling accepting ICMP-redirect messages"
111 sysctl_set_recursively "net.ipv6.conf" "accept_redirects" 1
112 sysctl_set_recursively "net.ipv4.conf" "accept_redirects" 1
113 else
114 log INFO "Disabling accepting ICMP-redirect messages"
115 sysctl_set_recursively "net.ipv6.conf" "accept_redirects" 0
116 sysctl_set_recursively "net.ipv4.conf" "accept_redirects" 0
117 fi
118
119 # Explicit Congestion Notification
120 if enabled FIREWALL_USE_ECN; then
121 log INFO "Enabling ECN (Explicit Congestion Notification)"
122 sysctl_set "net.ipv4.tcp_ecn" 1
123 else
124 log INFO "Disabling ECN (Explicit Congestion Notification)"
125 sysctl_set "net.ipv4.tcp_ecn" 2
126 fi
127
128 # Dynamic IP address hacking
129 log INFO "Enabling kernel support for dynamic IP addresses"
130 sysctl_set "net.ipv4.ip_dynaddr" 1
131
132 if enabled FIREWALL_PMTU_DISCOVERY; then
133 log INFO "Enabling PMTU discovery"
134 sysctl_set "net.ipv4.ip_no_pmtu_disc" 0
135 else
136 log INFO "Disabling PMTU discovery"
137 sysctl_set "net.ipv4.ip_no_pmtu_disc" 1
138 fi
139
140 # TTL
141 if ipv4_ttl_valid "${FIREWALL_DEFAULT_TTL}"; then
142 log INFO "Setting default TTL to ${FIREWALL_DEFAULT_TTL}"
143 sysctl_set "net.ipv4.ip_default_ttl" "${FIREWALL_DEFAULT_TTL}"
144 else
145 log ERROR "Invalid value for default TTL '${FIREWALL_DEFAULT_TTL}'"
146 log ERROR " Must be between 10 and 255!"
147 fi
148
149 return ${EXIT_OK}
150}
151
98146c00
MT
152# High-level function which will create a ruleset for the current firewall
153# configuration and load it into the kernel.
1c6a4e30 154firewall_start() {
fe52c5e0
MT
155 local protocol="${1}"
156 assert isset protocol
157 shift
158
afb7d704
MT
159 # Test mode.
160 local test="false"
161
162 while [ $# -gt 0 ]; do
163 case "${1}" in
164 --test)
165 test="true"
166 ;;
b4fc59c7
MT
167 *)
168 error "Unrecognized argument: ${1}"
169 return ${EXIT_ERROR}
170 ;;
afb7d704
MT
171 esac
172 shift
173 done
174
175 if enabled test; then
176 log INFO "Test mode enabled."
177 log INFO "The firewall ruleset will not be loaded."
178 fi
179
98146c00
MT
180 firewall_lock_acquire
181
182 # Initialize an empty iptables ruleset.
fe52c5e0 183 iptables_init "${protocol}" "DROP"
98146c00
MT
184
185 # Add default chains.
a7e23f3c 186 firewall_filter_rh0_headers "${protocol}"
204013de 187 firewall_filter_icmp "${protocol}"
4320067c 188 firewall_filter_invalid_packets "${protocol}"
fe52c5e0
MT
189 firewall_custom_chains "${protocol}"
190 firewall_connection_tracking "${protocol}"
191 firewall_tcp_clamp_mss "${protocol}"
98146c00
MT
192
193 # Add policies for every zone.
fe52c5e0 194 firewall_localhost_create_chains "${protocol}"
98146c00
MT
195
196 local zone
197 for zone in $(zones_get_all); do
a2c9dff5 198 # Create all needed chains for the zone.
fe52c5e0 199 firewall_zone_create_chains "${protocol}" "${zone}"
a2c9dff5
MT
200
201 # After the chains that are always available have been
202 # created, we will add a custom policy to every single
203 # zone.
204
fe52c5e0 205 policy_zone_add "${protocol}" "${zone}"
98146c00
MT
206 done
207
afb7d704 208 # Load the new ruleset.
fe52c5e0
MT
209 local args
210 if enabled testmode; then
211 list_append args "--test"
212 fi
213 iptables_commit "${protocol}" ${args}
98146c00
MT
214
215 firewall_lock_release
216}
217
1c6a4e30 218firewall_stop() {
fe52c5e0
MT
219 local protocol="${1}"
220 assert isset protocol
221
98146c00
MT
222 firewall_lock_acquire
223
224 # Initialize an empty firewall ruleset
225 # with default policy ACCEPT.
fe52c5e0 226 iptables_init "${protocol}" ACCEPT
98146c00 227
afb7d704 228 # Load it.
fe52c5e0 229 ipables_load "${protocol}"
afb7d704
MT
230
231 firewall_lock_release
232}
233
1c6a4e30 234firewall_show() {
fe52c5e0
MT
235 local protocol="${1}"
236 assert isset protocol
237
afb7d704 238 # Shows the ruleset that is currently loaded.
fe52c5e0 239 iptables_status "${protocol}"
afb7d704
MT
240
241 return ${EXIT_OK}
242}
243
1c6a4e30 244firewall_panic() {
fe52c5e0
MT
245 local protocol="${1}"
246 assert isset protocol
247 shift
248
afb7d704
MT
249 local admin_hosts="$@"
250
fe52c5e0 251 firewall_lock_acquire "${protocol}"
afb7d704
MT
252
253 # Drop all communications.
fe52c5e0 254 iptables_init "${protocol}" DROP
afb7d704
MT
255
256 # If an admin host is provided, some administrative
257 # things will be allowed from there.
258 local admin_host
259 for admin_host in ${admin_hosts}; do
fe52c5e0
MT
260 iptables "${protocol}" -A INPUT -s "${admin_host}" -j ACCEPT
261 iptables "${protocol}" -A OUTPUT -d "${admin_host}" -j ACCEPT
afb7d704
MT
262 done
263
264 # Load it.
fe52c5e0 265 iptables_commit "${protocol}"
98146c00
MT
266
267 firewall_lock_release
268}
269
1c6a4e30 270firewall_lock_acquire() {
98146c00
MT
271 lock_acquire ${RUN_DIR}/.firewall_lock
272
273 # Make sure the lock is released after the firewall
274 # script has crashed or exited early.
275 trap firewall_lock_release EXIT TERM KILL
276
277 # Create a directory where we can put our
278 # temporary data in the most secure way as possible.
279 IPTABLES_TMPDIR=$(mktemp -d)
280}
281
1c6a4e30 282firewall_lock_release() {
98146c00
MT
283 if isset IPTABLES_TMPDIR; then
284 # Remove all temporary data.
285 rm -rf ${IPTABLES_TMPDIR}
286
287 # Reset the tempdir variable.
288 IPTABLES_TMPDIR=
289 fi
290
291 # Reset the trap.
292 trap true EXIT TERM KILL
293
294 lock_release ${RUN_DIR}/.firewall_lock
295}
296
1c6a4e30 297firewall_custom_chains() {
fe52c5e0
MT
298 local protocol="${1}"
299 assert isset protocol
300
3b256a38
MT
301 log INFO "Creating CUSTOM* chains..."
302
303 # These chains are intened to be filled with
304 # rules by the user. They are processed at the very
305 # beginning so it is possible to overwrite everything.
306
fe52c5e0
MT
307 iptables_chain_create "${protocol}" CUSTOMINPUT
308 iptables "${protocol}" -A INPUT -j CUSTOMINPUT
3b256a38 309
fe52c5e0
MT
310 iptables_chain_create "${protocol}" CUSTOMFORWARD
311 iptables "${protocol}" -A FORWARD -j CUSTOMFORWARD
3b256a38 312
fe52c5e0
MT
313 iptables_chain_create "${protocol}" CUSTOMOUTPUT
314 iptables "${protocol}" -A OUTPUT -j CUSTOMOUTPUT
3b256a38 315
fe52c5e0
MT
316 iptables_chain_create "${protocol}" -t nat CUSTOMPREROUTING
317 iptables "${protocol}" -t nat -A PREROUTING -j CUSTOMPREROUTING
3b256a38 318
fe52c5e0
MT
319 iptables_chain_create "${protocol}" -t nat CUSTOMPOSTROUTING
320 iptables "${protocol}" -t nat -A POSTROUTING -j CUSTOMPOSTROUTING
3b256a38 321
fe52c5e0
MT
322 iptables_chain_create "${protocol}" -t nat CUSTOMOUTPUT
323 iptables "${protocol}" -t nat -A OUTPUT -j CUSTOMOUTPUT
3b256a38
MT
324}
325
1c6a4e30 326firewall_filter_invalid_packets() {
fe52c5e0
MT
327 local protocol="${1}"
328 assert isset protocol
329
4320067c 330 local log_limit="-m limit --limit 5/m --limit-burst 10"
fe52c5e0 331
4320067c
MT
332 # Create a chain
333 iptables_chain_create "${protocol}" FILTER_INVALID
334 iptables "${protocol}" -A INPUT -j FILTER_INVALID
335 iptables "${protocol}" -A OUTPUT -j FILTER_INVALID
336 iptables "${protocol}" -A FORWARD -j FILTER_INVALID
fe52c5e0 337
4320067c
MT
338 # Create a chain where only TCP packets go
339 iptables_chain_create "${protocol}" FILTER_INVALID_TCP
340 iptables "${protocol}" -A FILTER_INVALID -p tcp -j FILTER_INVALID_TCP
fe52c5e0 341
4320067c
MT
342 # Create a chain where only UDP packets go
343 iptables_chain_create "${protocol}" FILTER_INVALID_UDP
344 iptables "${protocol}" -A FILTER_INVALID -p udp -j FILTER_INVALID_UDP
345
346 # Create a chain where only ICMP packets go
347 iptables_chain_create "${protocol}" FILTER_INVALID_ICMP
348 iptables "${protocol}" -A FILTER_INVALID -p icmp -j FILTER_INVALID_ICMP
349
350
351 # Optionally log all port scans
352
353 if enabled FIREWALL_LOG_STEALTH_SCANS; then
354 log INFO "Logging of stealth scans enabled"
355
356 # NMAP FIN/URG/PSH - XMAS scan
357 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags ALL FIN,URG,PSH \
358 "${log_limit}" -j "$(iptables_LOG "Stealth XMAS scan")"
359
360 # SYN/RST/ACK/FIN/URG
361 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG \
362 "${log_limit}" -j "$(iptables_LOG "Stealth XMAS-PSH scan")"
363
364 # ALL/ALL
365 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags ALL ALL \
366 "${log_limit}" -j "$(iptables_LOG "Stealth XMAS-ALL scan")"
367
368 # NMAP FIN Stealth
369 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags ALL FIN \
370 "${log_limit}" -j "$(iptables_LOG "Stealth FIN scan")"
371
372 # SYN/RST
373 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags SYN,RST SYN,RST \
374 "${log_limit}" -j "$(iptables_LOG "Stealth SYN/RST scan")"
375
376 # SYN/FIN
377 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags SYN,FIN SYN,FIN \
378 "${log_limit}" -j "$(iptables_LOG "Stealth SYN/FIN scan")"
379
380 # Null scan
381 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags ALL NONE \
382 "${log_limit}" -j "$(iptables_LOG "Stealth NULL scan")"
383 else
384 log INFO "Logging of stealth scans disabled"
385 fi
386
387
388 # Drop scan packets
389
390 # NMAP FIN/URG/PSH
391 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
392
393 # SYN/RST/ACK/FIN/URG
394 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
395
396 # ALL/ALL
397 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags ALL ALL -j DROP
398
399 # NMAP FIN Stealth
400 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags ALL FIN -j DROP
401
402 # SYN/RST
403 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
404
405 # SYN/FIN
406 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
407
408 # Null scan
409 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-flags ALL NONE -j DROP
410
411
412 # Log packets with bad flags
413
414 if enabled FIREWALL_LOG_BAD_TCP_FLAGS; then
415 log INFO "Logging of packets with bad TCP flags enabled"
416
417 # Option 64
418 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-option 64 \
419 "${log_limit}" -j "$(iptables_LOG "Bad TCP flag(64)")"
420
421 # Option 128
422 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-option 128 \
423 "${log_limit}" -j "$(iptables_LOG "Bad TCP flag(128)")"
424 else
425 log INFO "Logging of packets with bad TCP flags disabled"
426 fi
427
428 # Drop packets with bad flags
429
430 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-option 64 -j DROP
431 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp --tcp-option 128 -j DROP
432
433
434 # Log invalid packets
435
436 if enabled FIREWALL_LOG_INVALID_TCP; then
437 log INFO "Logging of INVALID TCP packets enabled"
438
439 iptables "${protocol}" -A FILTER_INVALID_TCP -p tcp -m conntrack --ctstate INVALID \
440 "${log_limit}" -j "$(iptables_LOG "INVALID TCP")"
441 else
442 log INFO "Logging of INVALID TCP packets disabled"
443 fi
444
445 if enabled FIREWALL_LOG_INVALID_UDP; then
446 log INFO "Logging of INVALID UDP packets enabled"
447
448 iptables "${protocol}" -A FILTER_INVALID_UDP -p udp -m conntrack --ctstate INVALID \
449 "${log_limit}" -j "$(iptables_LOG "INVALID UDP")"
450 else
451 log INFO "Logging of INVALID UDP packets disabled"
452 fi
453
454 if enabled FIREWALL_LOG_INVALID_ICMP; then
455 log INFO "Logging of INVALID ICMP packets enabled"
456
457 iptables "${protocol}" -A FILTER_INVALID_ICMP -p icmp -m conntrack --ctstate INVALID \
458 "${log_limit}" -j "$(iptables_LOG "INVALID ICMP")"
459 else
460 log INFO "Logging of INVALID ICMP packets disabled"
461 fi
462
463 # Drop all INVALID packets
464 iptables "${protocol}" -A FILTER_INVALID -m conntrack --ctstate INVALID -j DROP
98146c00
MT
465}
466
1c6a4e30 467firewall_tcp_clamp_mss() {
fc323fc4
MT
468 # Do nothing if this has been disabled.
469 enabled FIREWALL_CLAMP_PATH_MTU || return ${EXIT_OK}
470
fe52c5e0
MT
471 local protocol="${1}"
472 assert isset protocol
473
c2d2d2a9 474 log DEBUG "Adding rules to clamp MSS to path MTU..."
fe52c5e0
MT
475
476 iptables "${protocol}" -t mangle -A FORWARD \
c2d2d2a9
MT
477 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
478}
479
1c6a4e30 480firewall_connection_tracking() {
fe52c5e0
MT
481 local protocol="${1}"
482 assert isset protocol
483
98146c00 484 log INFO "Creating Connection Tracking chain..."
fe52c5e0
MT
485
486 iptables_chain_create "${protocol}" CONNTRACK
85b52db6
MT
487 iptables "${protocol}" -A CONNTRACK -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
488 iptables "${protocol}" -A CONNTRACK -m conntrack --ctstate INVALID -j "$(iptables_LOG "INVALID packet: ")"
489 iptables "${protocol}" -A CONNTRACK -m conntrack --ctstate INVALID -j DROP
fe52c5e0
MT
490
491 iptables "${protocol}" -A INPUT -j CONNTRACK
492 iptables "${protocol}" -A OUTPUT -j CONNTRACK
493 iptables "${protocol}" -A FORWARD -j CONNTRACK
98146c00 494}
3647b19f 495
1c6a4e30 496firewall_localhost_create_chains() {
fe52c5e0
MT
497 local protocol="${1}"
498 assert isset protocol
499
a2c9dff5
MT
500 log DEBUG "Creating firewall chains for localhost..."
501
502 # Accept everything on lo
fe9bf26b
MT
503 iptables "${protocol}" -A INPUT -i lo -j ACCEPT
504 iptables "${protocol}" -A OUTPUT -o lo -j ACCEPT
a2c9dff5
MT
505}
506
1c6a4e30 507firewall_filter_rh0_headers() {
a7e23f3c
MT
508 local protocol="${1}"
509 assert isset protocol
510
511 # Only IPv6.
512 [ "${protocol}" = "ipv6" ] || return ${EXIT_OK}
513
514 # Filter all packets that have RH0 headers
515 # http://www.ietf.org/rfc/rfc5095.txt
516 iptables_chain_create "${protocol}" FILTER_RH0
517 iptables "${protocol}" -A FILTER_RH0 -m rt --rt-type 0 -j DROP
518
519 iptables "${protocol}" -A INPUT -j FILTER_RH0
520 iptables "${protocol}" -A FORWARD -j FILTER_RH0
521 iptables "${protocol}" -A OUTPUT -j FILTER_RH0
522}
523
1c6a4e30 524firewall_filter_icmp() {
204013de
MT
525 local protocol="${1}"
526 assert isset protocol
527
528 # Only IPv6.
529 [ "${protocol}" = "ipv6" ] || return ${EXIT_OK}
530
531 local chain="FILTER_ICMPV6"
532
533 # Create an extra chain for handling ICMP packets.
534 iptables_chain_create "${protocol}" "${chain}_COMMON"
535
536 local suffix
537 for suffix in INC FWD OUT; do
538 iptables_chain_create "${protocol}" "${chain}_${suffix}"
539 iptables "${protocol}" -A "${chain}_${suffix}" -j "${chain}_COMMON"
540 done
541 iptables "${protocol}" -A INPUT -p icmpv6 -j "${chain}_INC"
542 iptables "${protocol}" -A FORWARD -p icmpv6 -j "${chain}_FWD"
543 iptables "${protocol}" -A OUTPUT -p icmpv6 -j "${chain}_OUT"
544
545 # Packets that must always pass the firewall.
546 # Type 4: Parameter Problem
547 local type
548 for type in ttl-zero-during-reassembly bad-header; do
549 iptables "${protocol}" -A "${chain}_COMMON" \
550 -p icmpv6 --icmpv6-type "${type}" -j ACCEPT
551 done
552
553 # Packets that are accepted if they belong to an existing connection.
554 for type in echo-reply destination-unreachable packet-too-big \
555 unknown-header-type unknown-option; do
556 iptables "${protocol}" -A "${chain}_COMMON" \
557 -m conntrack --ctstate ESTABLISHED,RELATED \
558 -p icmpv6 --icmpv6-type "${type}" -j ACCEPT
559 done
560
561 # Packets that are always discarded.
562 # Type 100, 101, 200, 201: Private Experimentation
563 for type in 100 101 200 201; do
564 iptables "${protocol}" -A "${chain}_COMMON" \
565 -p icmpv6 --icmpv6-type "${type}" -j DROP
566 done
567
568 # Discard packets from local networks with hop limit smaller than $hoplimit.
569 # Type 148: Path solicitation
570 # Type 149: Path advertisement
571 local hoplimit=255
572 for type in {router,neighbour}-{advertisement,solicitation} 148 149; do
573 iptables "${protocol}" -A "${chain}_INC" \
574 -p icmpv6 --icmpv6-type "${type}" \
575 -m hl --hl-lt "${hoplimit}" -j DROP
576 done
577
578 # The firewall is always allowed to send ICMP echo requests.
579 iptables "${protocol}" -A "${chain}_OUT" \
580 -p icmpv6 --icmpv6-type echo-request -j ACCEPT
581
582 return ${EXIT_OK}
583}
584
1c6a4e30 585firewall_zone_create_chains() {
fe52c5e0
MT
586 local protocol="${1}"
587 assert isset protocol
588
589 local zone="${2}"
a2c9dff5
MT
590 assert isset zone
591
592 log DEBUG "Creating firewall chains for zone '${zone}'."
593
594 local chain_prefix="ZONE_${zone^^}"
595
596 # Create filter chains.
fe52c5e0
MT
597 iptables_chain_create "${protocol}" "${chain_prefix}_INPUT"
598 iptables "${protocol}" -A INPUT -i ${zone} -j "${chain_prefix}_INPUT"
a2c9dff5 599
fe52c5e0
MT
600 iptables_chain_create "${protocol}" "${chain_prefix}_OUTPUT"
601 iptables "${protocol}" -A OUTPUT -o ${zone} -j "${chain_prefix}_OUTPUT"
a2c9dff5
MT
602
603 # Custom rules.
fe52c5e0 604 iptables_chain_create "${protocol}" "${chain_prefix}_CUSTOM"
a2c9dff5
MT
605
606 # Intrusion Prevention System.
fe52c5e0 607 iptables_chain_create "${protocol}" "${chain_prefix}_IPS"
a2c9dff5
MT
608
609 # Create a chain for each other zone.
610 # This leaves us with n^2 chains. Duh.
611
612 local other_zone other_chain_prefix
613 for other_zone in $(zones_get_all); do
614 other_chain_prefix="${chain_prefix}_${other_zone^^}"
fe52c5e0 615 iptables_chain_create "${protocol}" "${other_chain_prefix}"
a2c9dff5
MT
616
617 # Connect the chain with the FORWARD chain.
fe52c5e0 618 iptables "${protocol}" -A FORWARD -i "${zone}" -o "${other_zone}" \
a2c9dff5
MT
619 -j "${other_chain_prefix}"
620
621 # Handle custom rules.
fe52c5e0 622 iptables "${protocol}" -A "${other_chain_prefix}" -j "${chain_prefix}_CUSTOM"
a2c9dff5
MT
623
624 # Link IPS.
fe52c5e0 625 iptables "${protocol}" -A "${other_chain_prefix}" -j "${chain_prefix}_IPS"
a2c9dff5
MT
626
627 # Rules.
fe52c5e0
MT
628 iptables_chain_create "${protocol}" "${other_chain_prefix}_RULES"
629 iptables "${protocol}" -A "${other_chain_prefix}" -j "${other_chain_prefix}_RULES"
a2c9dff5
MT
630
631 # Policy.
fe52c5e0
MT
632 iptables_chain_create "${protocol}" "${other_chain_prefix}_POLICY"
633 iptables "${protocol}" -A "${other_chain_prefix}" -j "${other_chain_prefix}_POLICY"
a2c9dff5
MT
634 done
635
636 ## Create mangle chain.
fe52c5e0
MT
637 #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}"
638 #iptables "${protocol}" -t mangle -A PREROUTING -i "${zone}" -j "${chain_prefix}"
639 #iptables "${protocol}" -t mangle -A POSTROUTING -o "${zone}" -j "${chain_prefix}"
a2c9dff5
MT
640
641 ## Quality of Service
fe52c5e0
MT
642 #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}_QOS_INC"
643 #iptables "${protocol}" -t mangle -A "${chain_prefix}" -i "${zone}" -j "${chain_prefix}_QOS_INC"
644 #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}_QOS_OUT"
645 #iptables "${protocol}" -t mangle -A "${chain_prefix}" -o "${zone}" -j "${chain_prefix}_QOS_OUT"
a2c9dff5
MT
646
647 # Create NAT chain.
fe52c5e0
MT
648 iptables_chain_create "${protocol}" -t nat "${chain_prefix}"
649 iptables "${protocol}" -t nat -A PREROUTING -i "${zone}" -j "${chain_prefix}"
650 iptables "${protocol}" -t nat -A POSTROUTING -o "${zone}" -j "${chain_prefix}"
a2c9dff5
MT
651
652 # Network Address Translation
fe52c5e0
MT
653 iptables_chain_create "${protocol}" -t nat "${chain_prefix}_DNAT"
654 iptables "${protocol}" -t nat -A PREROUTING -i "${zone}" -j "${chain_prefix}_DNAT"
655 iptables_chain_create "${protocol}" -t nat "${chain_prefix}_SNAT"
656 iptables "${protocol}" -t nat -A POSTROUTING -o "${zone}" -j "${chain_prefix}_SNAT"
a2c9dff5
MT
657
658 # UPnP
fe52c5e0
MT
659 iptables_chain_create "${protocol}" -t nat "${chain_prefix}_UPNP"
660 iptables "${protocol}" -t nat -A "${chain_prefix}" -j "${chain_prefix}_UPNP"
a2c9dff5
MT
661
662 return ${EXIT_OK}
663}
664
1c6a4e30 665firewall_parse_rules() {
a2c9dff5
MT
666 local file=${1}
667 assert isset file
3647b19f
MT
668 shift
669
a2c9dff5
MT
670 # End if no rule file exists.
671 [ -r "${file}" ] || return ${EXIT_OK}
3647b19f 672
a2c9dff5
MT
673 local cmd
674
675 local ${FIREWALL_RULES_CONFIG_PARAMS}
676 local line
677 while read -r line; do
678 # Skip empty lines.
679 [ -n "${line}" ] || continue
680
681 # Skip commented lines.
682 [ "${line:0:1}" = "#" ] && continue
683
684 # Parse the rule.
685 _firewall_parse_rule_line ${line}
686 if [ $? -ne ${EXIT_OK} ]; then
687 log WARNING "Skipping invalid line: ${line}"
688 continue
689 fi
690
691 cmd="iptables $@"
692
693 # Source IP address/net.
694 if isset src; then
695 list_append cmd "-s ${src}"
696 fi
697
698 # Destination IP address/net.
699 if isset dst; then
700 list_append cmd "-d ${dst}"
701 fi
702
703 # Protocol.
704 if isset proto; then
705 list_append cmd "-p ${proto}"
706
707 if list_match ${proto} ${FIREWALL_PROTOCOLS_SUPPORTING_PORTS}; then
708 if isset sport; then
709 list_append cmd "--sport ${sport}"
710 fi
711
712 if isset dport; then
713 list_append cmd "--dport ${dport}"
714 fi
715 fi
716 fi
717
718 # Always append the action.
719 list_append cmd "-j ${action}"
720
721 # Execute command.
722 ${cmd}
723 done < ${file}
724}
725
1c6a4e30 726_firewall_parse_rule_line() {
a2c9dff5
MT
727 local arg
728
729 # Clear all values.
730 for arg in ${FIREWALL_RULES_CONFIG_PARAMS}; do
731 assign "${arg}" ""
3647b19f
MT
732 done
733
a2c9dff5
MT
734 local key val
735 while read -r arg; do
736 key=$(cli_get_key ${arg})
3647b19f 737
8c9205b1 738 if ! list_match "${key}" ${FIREWALL_RULES_CONFIG_PARAMS}; then
a2c9dff5
MT
739 log WARNING "Unrecognized argument: ${arg}"
740 return ${EXIT_ERROR}
741 fi
3647b19f 742
2212045f 743 val=$(cli_get_val "${arg}")
a2c9dff5 744 assign "${key}" "${val}"
2212045f 745 done <<< "$(args "$@")"
a2c9dff5
MT
746
747 # action must always be set.
748 if ! isset action; then
749 log WARNING "'action' is not set: $@"
750 return ${EXIT_ERROR}
751 fi
752
753 for arg in src dst; do
754 isset ${arg} || continue
755
756 # Check for valid IP addresses.
757 if ! ip_is_valid ${!arg}; then
758 log WARNING "Invalid IP address for '${arg}=${!arg}': $@"
759 return ${EXIT_ERROR}
760 fi
761 done
762
763 if isset proto; then
764 # Make lowercase.
765 proto=${proto,,}
766
767 if ! list_match "${proto}" ${FIREWALL_SUPPORTED_PROTOCOLS}; then
768 log WARNING "Unsupported protocol type 'proto=${proto}': $@"
769 return ${EXIT_ERROR}
770 fi
771 fi
772
773 for arg in sport dport; do
774 isset ${arg} || continue
775
776 # Check if port is valid.
777 if ! isinteger ${arg}; then
778 log WARNING "Invalid port '${arg}=${!arg}': $@"
779 return ${EXIT_ERROR}
780 fi
781 done
782
783 return ${EXIT_OK}
3647b19f 784}