]> git.ipfire.org Git - people/ms/network.git/blame - functions.firewall
ipv6: Replace configuration with new sysctl commands.
[people/ms/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
ef953be2
MT
22# This function initializes all kernel parameters that need to be adjusted
23# to run this firewall properly.
24function 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 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.
154function firewall_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}"
fe52c5e0
MT
188 firewall_tcp_state_flags "${protocol}"
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
218function firewall_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
234function firewall_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
244function firewall_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
270function firewall_lock_acquire() {
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
282function firewall_lock_release() {
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
3b256a38 297function firewall_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
98146c00 326function firewall_tcp_state_flags() {
fe52c5e0
MT
327 local protocol="${1}"
328 assert isset protocol
329
98146c00 330 log INFO "Creating TCP State Flags chain..."
fe52c5e0
MT
331
332 iptables_chain_create "${protocol}" BADTCP_LOG
333 iptables "${protocol}" -A BADTCP_LOG -p tcp -j "$(iptables_LOG "Illegal TCP state: ")"
334 iptables "${protocol}" -A BADTCP_LOG -j DROP
335
336 iptables_chain_create "${protocol}" BADTCP
337 iptables "${protocol}" -A BADTCP -p tcp --tcp-flags ALL NONE -j BADTCP_LOG
338 iptables "${protocol}" -A BADTCP -p tcp --tcp-flags SYN,FIN SYN,FIN -j BADTCP_LOG
339 iptables "${protocol}" -A BADTCP -p tcp --tcp-flags SYN,RST SYN,RST -j BADTCP_LOG
340 iptables "${protocol}" -A BADTCP -p tcp --tcp-flags FIN,RST FIN,RST -j BADTCP_LOG
341 iptables "${protocol}" -A BADTCP -p tcp --tcp-flags ACK,FIN FIN -j BADTCP_LOG
342 iptables "${protocol}" -A BADTCP -p tcp --tcp-flags ACK,PSH PSH -j BADTCP_LOG
343 iptables "${protocol}" -A BADTCP -p tcp --tcp-flags ACK,URG URG -j BADTCP_LOG
344
345 iptables "${protocol}" -A INPUT -p tcp -j BADTCP
346 iptables "${protocol}" -A OUTPUT -p tcp -j BADTCP
347 iptables "${protocol}" -A FORWARD -p tcp -j BADTCP
98146c00
MT
348}
349
c2d2d2a9 350function firewall_tcp_clamp_mss() {
fc323fc4
MT
351 # Do nothing if this has been disabled.
352 enabled FIREWALL_CLAMP_PATH_MTU || return ${EXIT_OK}
353
fe52c5e0
MT
354 local protocol="${1}"
355 assert isset protocol
356
c2d2d2a9 357 log DEBUG "Adding rules to clamp MSS to path MTU..."
fe52c5e0
MT
358
359 iptables "${protocol}" -t mangle -A FORWARD \
c2d2d2a9
MT
360 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
361}
362
98146c00 363function firewall_connection_tracking() {
fe52c5e0
MT
364 local protocol="${1}"
365 assert isset protocol
366
98146c00 367 log INFO "Creating Connection Tracking chain..."
fe52c5e0
MT
368
369 iptables_chain_create "${protocol}" CONNTRACK
85b52db6
MT
370 iptables "${protocol}" -A CONNTRACK -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
371 iptables "${protocol}" -A CONNTRACK -m conntrack --ctstate INVALID -j "$(iptables_LOG "INVALID packet: ")"
372 iptables "${protocol}" -A CONNTRACK -m conntrack --ctstate INVALID -j DROP
fe52c5e0
MT
373
374 iptables "${protocol}" -A INPUT -j CONNTRACK
375 iptables "${protocol}" -A OUTPUT -j CONNTRACK
376 iptables "${protocol}" -A FORWARD -j CONNTRACK
98146c00 377}
3647b19f 378
a2c9dff5 379function firewall_localhost_create_chains() {
fe52c5e0
MT
380 local protocol="${1}"
381 assert isset protocol
382
a2c9dff5
MT
383 log DEBUG "Creating firewall chains for localhost..."
384
385 # Accept everything on lo
fe9bf26b
MT
386 iptables "${protocol}" -A INPUT -i lo -j ACCEPT
387 iptables "${protocol}" -A OUTPUT -o lo -j ACCEPT
a2c9dff5
MT
388}
389
a7e23f3c
MT
390function firewall_filter_rh0_headers() {
391 local protocol="${1}"
392 assert isset protocol
393
394 # Only IPv6.
395 [ "${protocol}" = "ipv6" ] || return ${EXIT_OK}
396
397 # Filter all packets that have RH0 headers
398 # http://www.ietf.org/rfc/rfc5095.txt
399 iptables_chain_create "${protocol}" FILTER_RH0
400 iptables "${protocol}" -A FILTER_RH0 -m rt --rt-type 0 -j DROP
401
402 iptables "${protocol}" -A INPUT -j FILTER_RH0
403 iptables "${protocol}" -A FORWARD -j FILTER_RH0
404 iptables "${protocol}" -A OUTPUT -j FILTER_RH0
405}
406
204013de
MT
407function firewall_filter_icmp() {
408 local protocol="${1}"
409 assert isset protocol
410
411 # Only IPv6.
412 [ "${protocol}" = "ipv6" ] || return ${EXIT_OK}
413
414 local chain="FILTER_ICMPV6"
415
416 # Create an extra chain for handling ICMP packets.
417 iptables_chain_create "${protocol}" "${chain}_COMMON"
418
419 local suffix
420 for suffix in INC FWD OUT; do
421 iptables_chain_create "${protocol}" "${chain}_${suffix}"
422 iptables "${protocol}" -A "${chain}_${suffix}" -j "${chain}_COMMON"
423 done
424 iptables "${protocol}" -A INPUT -p icmpv6 -j "${chain}_INC"
425 iptables "${protocol}" -A FORWARD -p icmpv6 -j "${chain}_FWD"
426 iptables "${protocol}" -A OUTPUT -p icmpv6 -j "${chain}_OUT"
427
428 # Packets that must always pass the firewall.
429 # Type 4: Parameter Problem
430 local type
431 for type in ttl-zero-during-reassembly bad-header; do
432 iptables "${protocol}" -A "${chain}_COMMON" \
433 -p icmpv6 --icmpv6-type "${type}" -j ACCEPT
434 done
435
436 # Packets that are accepted if they belong to an existing connection.
437 for type in echo-reply destination-unreachable packet-too-big \
438 unknown-header-type unknown-option; do
439 iptables "${protocol}" -A "${chain}_COMMON" \
440 -m conntrack --ctstate ESTABLISHED,RELATED \
441 -p icmpv6 --icmpv6-type "${type}" -j ACCEPT
442 done
443
444 # Packets that are always discarded.
445 # Type 100, 101, 200, 201: Private Experimentation
446 for type in 100 101 200 201; do
447 iptables "${protocol}" -A "${chain}_COMMON" \
448 -p icmpv6 --icmpv6-type "${type}" -j DROP
449 done
450
451 # Discard packets from local networks with hop limit smaller than $hoplimit.
452 # Type 148: Path solicitation
453 # Type 149: Path advertisement
454 local hoplimit=255
455 for type in {router,neighbour}-{advertisement,solicitation} 148 149; do
456 iptables "${protocol}" -A "${chain}_INC" \
457 -p icmpv6 --icmpv6-type "${type}" \
458 -m hl --hl-lt "${hoplimit}" -j DROP
459 done
460
461 # The firewall is always allowed to send ICMP echo requests.
462 iptables "${protocol}" -A "${chain}_OUT" \
463 -p icmpv6 --icmpv6-type echo-request -j ACCEPT
464
465 return ${EXIT_OK}
466}
467
a2c9dff5 468function firewall_zone_create_chains() {
fe52c5e0
MT
469 local protocol="${1}"
470 assert isset protocol
471
472 local zone="${2}"
a2c9dff5
MT
473 assert isset zone
474
475 log DEBUG "Creating firewall chains for zone '${zone}'."
476
477 local chain_prefix="ZONE_${zone^^}"
478
479 # Create filter chains.
fe52c5e0
MT
480 iptables_chain_create "${protocol}" "${chain_prefix}_INPUT"
481 iptables "${protocol}" -A INPUT -i ${zone} -j "${chain_prefix}_INPUT"
a2c9dff5 482
fe52c5e0
MT
483 iptables_chain_create "${protocol}" "${chain_prefix}_OUTPUT"
484 iptables "${protocol}" -A OUTPUT -o ${zone} -j "${chain_prefix}_OUTPUT"
a2c9dff5
MT
485
486 # Custom rules.
fe52c5e0 487 iptables_chain_create "${protocol}" "${chain_prefix}_CUSTOM"
a2c9dff5
MT
488
489 # Intrusion Prevention System.
fe52c5e0 490 iptables_chain_create "${protocol}" "${chain_prefix}_IPS"
a2c9dff5
MT
491
492 # Create a chain for each other zone.
493 # This leaves us with n^2 chains. Duh.
494
495 local other_zone other_chain_prefix
496 for other_zone in $(zones_get_all); do
497 other_chain_prefix="${chain_prefix}_${other_zone^^}"
fe52c5e0 498 iptables_chain_create "${protocol}" "${other_chain_prefix}"
a2c9dff5
MT
499
500 # Connect the chain with the FORWARD chain.
fe52c5e0 501 iptables "${protocol}" -A FORWARD -i "${zone}" -o "${other_zone}" \
a2c9dff5
MT
502 -j "${other_chain_prefix}"
503
504 # Handle custom rules.
fe52c5e0 505 iptables "${protocol}" -A "${other_chain_prefix}" -j "${chain_prefix}_CUSTOM"
a2c9dff5
MT
506
507 # Link IPS.
fe52c5e0 508 iptables "${protocol}" -A "${other_chain_prefix}" -j "${chain_prefix}_IPS"
a2c9dff5
MT
509
510 # Rules.
fe52c5e0
MT
511 iptables_chain_create "${protocol}" "${other_chain_prefix}_RULES"
512 iptables "${protocol}" -A "${other_chain_prefix}" -j "${other_chain_prefix}_RULES"
a2c9dff5
MT
513
514 # Policy.
fe52c5e0
MT
515 iptables_chain_create "${protocol}" "${other_chain_prefix}_POLICY"
516 iptables "${protocol}" -A "${other_chain_prefix}" -j "${other_chain_prefix}_POLICY"
a2c9dff5
MT
517 done
518
519 ## Create mangle chain.
fe52c5e0
MT
520 #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}"
521 #iptables "${protocol}" -t mangle -A PREROUTING -i "${zone}" -j "${chain_prefix}"
522 #iptables "${protocol}" -t mangle -A POSTROUTING -o "${zone}" -j "${chain_prefix}"
a2c9dff5
MT
523
524 ## Quality of Service
fe52c5e0
MT
525 #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}_QOS_INC"
526 #iptables "${protocol}" -t mangle -A "${chain_prefix}" -i "${zone}" -j "${chain_prefix}_QOS_INC"
527 #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}_QOS_OUT"
528 #iptables "${protocol}" -t mangle -A "${chain_prefix}" -o "${zone}" -j "${chain_prefix}_QOS_OUT"
a2c9dff5
MT
529
530 # Create NAT chain.
fe52c5e0
MT
531 iptables_chain_create "${protocol}" -t nat "${chain_prefix}"
532 iptables "${protocol}" -t nat -A PREROUTING -i "${zone}" -j "${chain_prefix}"
533 iptables "${protocol}" -t nat -A POSTROUTING -o "${zone}" -j "${chain_prefix}"
a2c9dff5
MT
534
535 # Network Address Translation
fe52c5e0
MT
536 iptables_chain_create "${protocol}" -t nat "${chain_prefix}_DNAT"
537 iptables "${protocol}" -t nat -A PREROUTING -i "${zone}" -j "${chain_prefix}_DNAT"
538 iptables_chain_create "${protocol}" -t nat "${chain_prefix}_SNAT"
539 iptables "${protocol}" -t nat -A POSTROUTING -o "${zone}" -j "${chain_prefix}_SNAT"
a2c9dff5
MT
540
541 # UPnP
fe52c5e0
MT
542 iptables_chain_create "${protocol}" -t nat "${chain_prefix}_UPNP"
543 iptables "${protocol}" -t nat -A "${chain_prefix}" -j "${chain_prefix}_UPNP"
a2c9dff5
MT
544
545 return ${EXIT_OK}
546}
547
548function firewall_parse_rules() {
549 local file=${1}
550 assert isset file
3647b19f
MT
551 shift
552
a2c9dff5
MT
553 # End if no rule file exists.
554 [ -r "${file}" ] || return ${EXIT_OK}
3647b19f 555
a2c9dff5
MT
556 local cmd
557
558 local ${FIREWALL_RULES_CONFIG_PARAMS}
559 local line
560 while read -r line; do
561 # Skip empty lines.
562 [ -n "${line}" ] || continue
563
564 # Skip commented lines.
565 [ "${line:0:1}" = "#" ] && continue
566
567 # Parse the rule.
568 _firewall_parse_rule_line ${line}
569 if [ $? -ne ${EXIT_OK} ]; then
570 log WARNING "Skipping invalid line: ${line}"
571 continue
572 fi
573
574 cmd="iptables $@"
575
576 # Source IP address/net.
577 if isset src; then
578 list_append cmd "-s ${src}"
579 fi
580
581 # Destination IP address/net.
582 if isset dst; then
583 list_append cmd "-d ${dst}"
584 fi
585
586 # Protocol.
587 if isset proto; then
588 list_append cmd "-p ${proto}"
589
590 if list_match ${proto} ${FIREWALL_PROTOCOLS_SUPPORTING_PORTS}; then
591 if isset sport; then
592 list_append cmd "--sport ${sport}"
593 fi
594
595 if isset dport; then
596 list_append cmd "--dport ${dport}"
597 fi
598 fi
599 fi
600
601 # Always append the action.
602 list_append cmd "-j ${action}"
603
604 # Execute command.
605 ${cmd}
606 done < ${file}
607}
608
609function _firewall_parse_rule_line() {
610 local arg
611
612 # Clear all values.
613 for arg in ${FIREWALL_RULES_CONFIG_PARAMS}; do
614 assign "${arg}" ""
3647b19f
MT
615 done
616
a2c9dff5
MT
617 local key val
618 while read -r arg; do
619 key=$(cli_get_key ${arg})
3647b19f 620
a2c9dff5
MT
621 if ! listmatch "${key}" ${FIREWALL_RULES_CONFIG_PARAMS}; then
622 log WARNING "Unrecognized argument: ${arg}"
623 return ${EXIT_ERROR}
624 fi
3647b19f 625
a2c9dff5
MT
626 val=$(cli_get_val ${arg})
627 assign "${key}" "${val}"
628 done <<< "$(args $@)"
629
630 # action must always be set.
631 if ! isset action; then
632 log WARNING "'action' is not set: $@"
633 return ${EXIT_ERROR}
634 fi
635
636 for arg in src dst; do
637 isset ${arg} || continue
638
639 # Check for valid IP addresses.
640 if ! ip_is_valid ${!arg}; then
641 log WARNING "Invalid IP address for '${arg}=${!arg}': $@"
642 return ${EXIT_ERROR}
643 fi
644 done
645
646 if isset proto; then
647 # Make lowercase.
648 proto=${proto,,}
649
650 if ! list_match "${proto}" ${FIREWALL_SUPPORTED_PROTOCOLS}; then
651 log WARNING "Unsupported protocol type 'proto=${proto}': $@"
652 return ${EXIT_ERROR}
653 fi
654 fi
655
656 for arg in sport dport; do
657 isset ${arg} || continue
658
659 # Check if port is valid.
660 if ! isinteger ${arg}; then
661 log WARNING "Invalid port '${arg}=${!arg}': $@"
662 return ${EXIT_ERROR}
663 fi
664 done
665
666 return ${EXIT_OK}
3647b19f 667}