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