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