2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2012-2013 IPFire Network Development Team #
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. #
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. #
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/>. #
20 ###############################################################################
22 IPTABLES_TABLES
="filter mangle nat"
29 # Rules go to the filter table by default
39 while [ $# -gt 0 ]; do
41 # Filter to which table this rule should go.
46 assert isoneof table
${IPTABLES_TABLES}
49 # Automatically convert ICMP to ICMPv6 for IPv6
53 if [ "${protocol}" = "ipv6" -a "${proto}" = "icmp" ]; then
57 list_append args
"${1} ${proto}"
61 list_append args
"${1}"
63 # Save some values for further processing.
79 # Check if given IP addresses or networks match the protocol version.
82 src_proto
="$(ip_detect_protocol ${src})"
84 assert
[ "${protocol}" = "${src_proto}" ]
89 dst_proto
="$(ip_detect_protocol ${dst})"
91 assert
[ "${protocol}" = "${dst_proto}" ]
94 # Check if the directory where we put our rules in is set and
96 assert isset IPTABLES_TMPDIR
97 local rulesfile
="${IPTABLES_TMPDIR}/${protocol}-${table}"
99 print
"${args}" >> "${rulesfile}"
100 assert_check_retval $?
103 function iptables_chain_create
() {
104 local protocol
="${1}"
105 assert isset protocol
112 while [ $# -gt 0 ]; do
119 policy
="$(cli_get_val ${1})"
122 log WARNING
"Unrecognized argument: ${1}"
133 assert isoneof policy ACCEPT DROP
"-"
135 iptables
"${protocol}" -t "${table}" ":${chain} ${policy} [0:0]"
138 # Calls the binary iptables command.
139 function _iptables
() {
140 local protocol
="${1}"
141 assert isset protocol
145 case "${protocol}" in
154 cmd
="$(which ${cmd})"
160 function iptables_status
() {
161 local protocol
="${1}"
162 assert isset protocol
165 for table
in ${IPTABLES_TABLES}; do
166 print
"${protocol} - ${table}:"
167 _iptables
"${protocol}" -t "${table}" -L -n -v
174 function iptables_rulesfile
() {
179 [ -z "${chain}" ] && chain
="ruleset"
181 print
"${IPTABLES_TMPDIR}/${chain}${proto}"
184 function iptables_init
() {
185 local protocol
="${1}"
186 assert isset protocol
191 # Create filter table and initialize chains.
192 iptables
"${protocol}" "* filter"
193 iptables_chain_create
"${protocol}" -t filter INPUT
--policy="${policy}"
194 iptables_chain_create
"${protocol}" -t filter OUTPUT
--policy="${policy}"
195 iptables_chain_create
"${protocol}" -t filter FORWARD
--policy="${policy}"
197 # Create mangle table and initialize chains.
198 iptables
"${protocol}" -t mangle
"* mangle"
199 iptables_chain_create
"${protocol}" -t mangle PREROUTING
--policy="ACCEPT"
200 iptables_chain_create
"${protocol}" -t mangle INPUT
--policy="ACCEPT"
201 iptables_chain_create
"${protocol}" -t mangle OUTPUT
--policy="ACCEPT"
202 iptables_chain_create
"${protocol}" -t mangle FORWARD
--policy="ACCEPT"
203 iptables_chain_create
"${protocol}" -t mangle POSTROUTING
--policy="ACCEPT"
205 # Create NAT table and initialize chains.
206 iptables
"${protocol}" -t nat
"* nat"
207 iptables_chain_create
"${protocol}" -t nat PREROUTING
--policy="ACCEPT"
208 iptables_chain_create
"${protocol}" -t nat OUTPUT
--policy="ACCEPT"
209 iptables_chain_create
"${protocol}" -t nat POSTROUTING
--policy="ACCEPT"
212 # Load the created ruleset into the kernel.
213 function iptables_commit
() {
214 local protocol
="${1}"
215 assert isset protocol
218 local testmode
="false"
220 while [ $# -gt 0 ]; do
226 log WARNING
"Unrecognized argument: ${1}"
232 # Concat all rules into one big file.
233 local rulesfile
="${IPTABLES_TMPDIR}/ruleset"
234 _iptables_commit_cat_rulesfile
"${protocol}" "${rulesfile}"
236 # Run the following loop twice:
237 # 1st: Check if the ruleset can be loaded
238 # 2nd: If not in test mode, actually load the ruleset into the kernel
239 local load_cmd
="--test"
244 _iptables_commit_load_rulesfile
"${protocol}" "${rulesfile}" "${load_cmd}"
247 case "${i},${ret}" in
249 iptables_dump
"${protocol}" "${rulesfile}" --log-facility="DEBUG"
250 log DEBUG
"Ruleset load check succeeded (${protocol})"
253 # Loading rules has failed (test)
255 iptables_dump
"${protocol}" "${rulesfile}" --log-facility="CRITICAL"
256 log CRITICAL
"Ruleset load check failed (${protocol} - ${ret})"
261 log DEBUG
"Ruleset successfully loaded (${protocol})"
266 log CRITICAL
"Ruleset loading failed (${protocol})"
271 # Skip the second loop iteration, if we are running in test mode.
272 enabled testmode
&& break
280 function _iptables_commit_cat_rulesfile
() {
281 local protocol
="${1}"
282 assert isset protocol
284 local rulesfile
="${2}"
285 assert isset rulesfile
289 for table
in ${IPTABLES_TABLES}; do
290 file="${IPTABLES_TMPDIR}/${protocol}-${table}"
294 # Add the COMMIT statement for every table.
296 done > "${rulesfile}"
298 assert
[ -s "${rulesfile}" ]
301 function _iptables_commit_load_rulesfile
() {
302 local protocol
="${1}"
303 assert isset protocol
305 local rulesfile
="${2}"
306 assert isset rulesfile
309 local testmode
="false"
310 while [ $# -gt 0 ]; do
320 case "${protocol}" in
322 iptables_cmd
="ip6tables-restore"
325 iptables_cmd
="iptables-restore"
328 assert isset iptables_cmd
330 if enabled testmode
; then
331 list_append iptables_cmd
"--test"
334 # Save when importing the rules has started.
335 local time_started
="$(timestamp)"
337 cmd
"${iptables_cmd}" < "${rulesfile}"
342 local time_finished
="$(timestamp)"
343 time_finished
="$(( ${time_finished} - ${time_started} ))"
345 enabled testmode
&& return ${EXIT_OK}
347 log INFO
"Successfully loaded new firewall ruleset for ${protocol} in ${time_finished}s!"
350 if ! enabled testmode
; then
351 log CRITICAL
"Error loading firewall ruleset for ${protocol}!"
359 function iptables_dump
() {
360 local protocol
="${1}"
361 assert isset protocol
363 local rulesfile
="${2}"
364 assert isset rulesfile
367 local log_facility
="INFO"
369 while [ $# -gt 0 ]; do
372 log_facility
="$(cli_get_val ${1})"
375 log WARNING
"Unrecognized argument: ${1}"
381 # Say what we are going to do:
382 log
"${log_facility}" "Firewall ruleset for ${protocol}:"
386 while read -r line
; do
387 counter
="$(( ${counter} + 1 ))"
389 printf -v line
"%4d | %s" "${counter}" "${line}"
390 log
"${log_facility}" "${line}"
391 done < "${rulesfile}"
394 function iptables_LOG
() {
398 # Automatically append a colon and whitespace.
400 # Everything is fine.
403 # Ends with colon, add whitespace only.
414 case "${FIREWALL_LOG_METHOD}" in
416 ret
="NFLOG --nflog-threshold ${FIREWALL_NFLOG_THRESHOLD}"
417 isset prefix
&& ret
="${ret} --nflog-prefix \"$prefix\""
421 isset prefix
&& ret
="${ret} --log-prefix \"$prefix\""
428 function iptables_protocol
() {
431 for proto
in tcp udp esp ah
; do
432 if [ "$PROTO" = "$proto" ]; then
443 function _iptables_port_range
() {
447 function _iptables_port_multiport
() {
451 function _iptables_port
() {
452 if _iptables_port_range
"$@"; then
453 echo $IPTABLES_PORTRANGE
454 elif _iptables_port_multiport
"$@"; then
455 echo $IPTABLES_MULTIPORT
461 function iptables_source_port
() {
462 [ -z "$@" ] && return
464 type=$
(_iptables_port $@
)
465 if [ "$type" = "$IPTABLES_MULTIPORT" ]; then
466 echo "-m multiport --source-ports $@"
472 function iptables_destination_port
() {
473 [ -z "$@" ] && return
475 type=$
(_iptables_port $@
)
476 if [ "$type" = "$IPTABLES_MULTIPORT" ]; then
477 echo "-m multiport --destination-ports $@"