From: Michael Tremer Date: Thu, 25 Apr 2013 14:23:54 +0000 (+0200) Subject: Split firewall in a IPv6 and IPv4 component. X-Git-Url: http://git.ipfire.org/?p=people%2Fstevee%2Fnetwork.git;a=commitdiff_plain;h=fe52c5e06965f9156b3fb06b6a07cde233640136 Split firewall in a IPv6 and IPv4 component. --- diff --git a/Makefile b/Makefile index 7898985f..5a6645ed 100644 --- a/Makefile +++ b/Makefile @@ -103,7 +103,8 @@ install: $(MAN_PAGES) -mkdir -pv $(DESTDIR)$(tmpfilesdir) -mkdir -pv $(DESTDIR)$(datadir)/firewall - install -m 755 -v firewall $(DESTDIR)$(sbindir) + install -m 755 -v firewall6 $(DESTDIR)$(sbindir) + install -m 755 -v firewall4 $(DESTDIR)$(sbindir) install -m 755 -v network $(DESTDIR)$(sbindir) cp -rfv {hooks,header*,functions*} $(DESTDIR)$(libdir)/network/ diff --git a/firewall4 b/firewall4 new file mode 100755 index 00000000..68fa8aea --- /dev/null +++ b/firewall4 @@ -0,0 +1,29 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2012 IPFire Network Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +. /usr/lib/network/functions + +# Read firewall configuration. +firewall_config_read "ipv4" + +firewall_cli "ipv4" "$@" + +exit ${EXIT_ERROR} diff --git a/firewall6 b/firewall6 new file mode 100755 index 00000000..74afeef6 --- /dev/null +++ b/firewall6 @@ -0,0 +1,29 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2012 IPFire Network Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +. /usr/lib/network/functions + +# Read firewall configuration. +firewall_config_read "ipv6" + +firewall_cli "ipv6" "$@" + +exit ${EXIT_ERROR} diff --git a/functions b/functions index 46a3420f..2f6cfdf4 100644 --- a/functions +++ b/functions @@ -42,6 +42,3 @@ function init_run() { for file in /usr/lib/network/functions.*; do . ${file} done - -# Reading in global configuration files -config_read_globals diff --git a/firewall b/functions.cli.firewall similarity index 70% rename from firewall rename to functions.cli.firewall index a1f1a17d..39f0a434 100755 --- a/firewall +++ b/functions.cli.firewall @@ -19,21 +19,72 @@ # # ############################################################################### -. /usr/lib/network/functions +function firewall_cli() { + local protocol="${1}" + assert isset protocol + shift -function cli_start() { - firewall_start $@ -} + # Parse the command line + while [ $# -gt 0 ]; do + case "${1}" in + -d|--debug) + DEBUG=1 + log DEBUG "Enabled debugging mode" + ;; + *) + action=${1} + ;; + esac + shift + [ -n "${action}" ] && break + done -function cli_stop() { - firewall_stop -} + # Process the given action + case "${action}" in + start|restart|reload) + firewall_start "${protocol}" "$@" + ;; + + stop) + firewall_stop "${protocol}" "$@" + ;; + + show) + firewall_show "${protocol}" "$@" + ;; + + panic) + firewall_cli_panic "${protocol}" "$@" + ;; + + config) + firewall_cli_config "${protocol}" $@ + ;; + + zone) + firewall_cli_zone $@ + ;; + + ""|help|--help|-h) + cli_usage root + exit ${EXIT_OK} + ;; + + *) + error "Invalid command given: ${action}" + cli_usage usage + exit ${EXIT_CONF_ERROR} + ;; + esac -function cli_show() { - firewall_show $@ + exit ${EXIT_OK} } -function cli_panic() { +function firewall_cli_panic() { + local protocol="${1}" + assert isset protocol + shift + if cli_help_requested $@; then cli_show_man firewall-panic exit ${EXIT_OK} @@ -56,21 +107,29 @@ function cli_panic() { firewall_panic ${admin_hosts} } -function cli_config() { +function firewall_cli_config() { + local protocol="${1}" + assert isset protocol + shift + if cli_help_requested $@; then cli_usage root-config exit ${EXIT_OK} fi if [ -n "${1}" ]; then - config_set $@ - firewall_config_write + config_set "$@" + firewall_config_write "${protocol}" else - firewall_config_print + firewall_config_print "${protocol}" fi } -function cli_zone() { +function firewall_cli_zone() { + local protocol="${1}" + assert isset protocol + shift + if cli_help_requested $@; then cli_show_man firewall-zone exit ${EXIT_OK} @@ -92,10 +151,10 @@ function cli_zone() { # Process the given action. case "${action}" in edit) - cli_zone_edit ${zone} $@ + firewall_cli_zone_edit ${zone} $@ ;; status|"") - cli_zone_status ${zone} $@ + firewall_cli_zone_status ${zone} $@ ;; # Print the raw configuration settings. @@ -132,7 +191,7 @@ function cli_zone() { } # Show firewall zone conifguration. -function cli_zone_status() { +function firewall_cli_zone_status() { local zone=${1} assert isset zone @@ -149,63 +208,8 @@ function cli_zone_status() { } # Edit firewall zone configuration. -function cli_zone_edit() { - firewall_zone_edit $@ +function firewall_cli_zone_edit() { + firewall_zone_edit "$@" exit ${EXIT_OK} } - -# Parse the command line -while [ $# -gt 0 ]; do - case "${1}" in - -d|--debug) - DEBUG=1 - log DEBUG "Enabled debugging mode" - ;; - *) - action=${1} - ;; - esac - shift - [ -n "${action}" ] && break -done - -# Process the given action -case "${action}" in - start|restart|reload) - cli_start $@ - ;; - - stop) - cli_stop $@ - ;; - - show) - cli_show $@ - ;; - - panic) - cli_panic $@ - ;; - - config) - cli_config $@ - ;; - - zone) - cli_zone $@ - ;; - - ""|help|--help|-h) - cli_usage root - exit ${EXIT_OK} - ;; - - *) - error "Invalid command given: ${action}" - cli_usage usage - exit ${EXIT_CONF_ERROR} - ;; -esac - -exit ${EXIT_OK} diff --git a/functions.config b/functions.config index 8e1ab95d..11e92466 100644 --- a/functions.config +++ b/functions.config @@ -19,12 +19,6 @@ # # ############################################################################### -# Load all global configuration files. -function config_read_globals() { - network_config_read - firewall_config_read -} - function config_read() { local file=${1} assert isset file @@ -224,15 +218,60 @@ function network_config_print() { config_print ${NETWORK_CONFIG_FILE_PARAMS} } +function firewall_config_file() { + local protocol="${1}" + assert isset protocol + + local file + case "${protocol}" in + ipv6) + file="${FIREWALL6_CONFIG_FILE}" + ;; + ipv4) + file="${FIREWALL4_CONFIG_FILE}" + ;; + esac + assert isset file + + print "${file}" + return ${EXIT_OK} +} + +function firewall_config_env() { + local protocol="${1}" + assert isset protocol + + case "${protocol}" in + ipv6) + file="${FIREWALL6_CONFIG_FILE}" + params="${FIREWALL6_CONFIG_PARAMS}" + ;; + ipv4) + file="${FIREWALL4_CONFIG_FILE}" + params="${FIREWALL4_CONFIG_PARAMS}" + ;; + esac + assert isset file + assert isset params +} + function firewall_config_read() { - config_read ${FIREWALL_CONFIG_FILE} ${FIREWALL_CONFIG_PARAMS} + local file params + firewall_config_env "$@" + + config_read "${file}" "${params}" } function firewall_config_write() { - config_write ${FIREWALL_CONFIG_FILE} \ - ${FIREWALL_CONFIG_PARAMS} + local file params + firewall_config_env "$@" + + config_write "${file}" "${params}" } function firewall_config_print() { - config_print ${FIREWALL_CONFIG_PARAMS} + local file params + firewall_config_env "$@" + + config_print "${params}" } diff --git a/functions.constants-firewall b/functions.constants-firewall index d1fab5d5..decd7084 100644 --- a/functions.constants-firewall +++ b/functions.constants-firewall @@ -25,7 +25,8 @@ IPTABLES_TMPDIR= FIREWALL_CONFIG_DIR="/etc/firewall" FIREWALL_ZONES_DIR="${FIREWALL_CONFIG_DIR}/zones" -FIREWALL_CONFIG_FILE="${FIREWALL_CONFIG_DIR}/config" +FIREWALL4_CONFIG_FILE="${FIREWALL_CONFIG_DIR}/config4" +FIREWALL6_CONFIG_FILE="${FIREWALL_CONFIG_DIR}/config6" FIREWALL_CONFIG_RULES="${FIREWALL_CONFIG_DIR}/rules" FIREWALL_MACROS_DIRS="${FIREWALL_CONFIG_DIR}/macros" @@ -49,6 +50,9 @@ FIREWALL_CONFIG_PARAMS="${FIREWALL_CONFIG_PARAMS} FIREWALL_NFLOG_THRESHOLD" FIREWALL_CLAMP_PATH_MTU="false" FIREWALL_CONFIG_PARAMS="${FIREWALL_CONFIG_PARAMS} FIREWALL_CLAMP_PATH_MTU" +FIREWALL4_CONFIG_PARAMS="${FIREWALL_CONFIG_PARAMS}" +FIREWALL6_CONFIG_PARAMS="${FIREWALL_CONFIG_PARAMS}" + FIREWALL_SUPPORTED_PROTOCOLS="tcp udp icmp igmp esp ah gre" FIREWALL_PROTOCOLS_SUPPORTING_PORTS="tcp udp" diff --git a/functions.firewall b/functions.firewall index a55ea9a5..610ed54c 100644 --- a/functions.firewall +++ b/functions.firewall @@ -22,6 +22,10 @@ # High-level function which will create a ruleset for the current firewall # configuration and load it into the kernel. function firewall_start() { + local protocol="${1}" + assert isset protocol + shift + # Test mode. local test="false" @@ -46,73 +50,87 @@ function firewall_start() { firewall_lock_acquire # Initialize an empty iptables ruleset. - iptables_init DROP + iptables_init "${protocol}" "DROP" # Add default chains. - firewall_tcp_state_flags - firewall_custom_chains - firewall_connection_tracking - firewall_tcp_clamp_mss + firewall_tcp_state_flags "${protocol}" + firewall_custom_chains "${protocol}" + firewall_connection_tracking "${protocol}" + firewall_tcp_clamp_mss "${protocol}" # Add policies for every zone. - firewall_localhost_create_chains + firewall_localhost_create_chains "${protocol}" local zone for zone in $(zones_get_all); do # Create all needed chains for the zone. - firewall_zone_create_chains ${zone} + firewall_zone_create_chains "${protocol}" "${zone}" # After the chains that are always available have been # created, we will add a custom policy to every single # zone. - policy_zone_add ${zone} + policy_zone_add "${protocol}" "${zone}" done # Load the new ruleset. - iptables_load ${test} + local args + if enabled testmode; then + list_append args "--test" + fi + iptables_commit "${protocol}" ${args} firewall_lock_release } function firewall_stop() { + local protocol="${1}" + assert isset protocol + firewall_lock_acquire # Initialize an empty firewall ruleset # with default policy ACCEPT. - iptables_init ACCEPT + iptables_init "${protocol}" ACCEPT # Load it. - iptables_load + ipables_load "${protocol}" firewall_lock_release } function firewall_show() { + local protocol="${1}" + assert isset protocol + # Shows the ruleset that is currently loaded. - iptables_status + iptables_status "${protocol}" return ${EXIT_OK} } function firewall_panic() { + local protocol="${1}" + assert isset protocol + shift + local admin_hosts="$@" - firewall_lock_acquire + firewall_lock_acquire "${protocol}" # Drop all communications. - iptables_init DROP + iptables_init "${protocol}" DROP # If an admin host is provided, some administrative # things will be allowed from there. local admin_host for admin_host in ${admin_hosts}; do - iptables -A INPUT -s ${admin_host} -j ACCEPT - iptables -A OUTPUT -d ${admin_host} -j ACCEPT + iptables "${protocol}" -A INPUT -s "${admin_host}" -j ACCEPT + iptables "${protocol}" -A OUTPUT -d "${admin_host}" -j ACCEPT done # Load it. - iptables_load + iptables_commit "${protocol}" firewall_lock_release } @@ -145,82 +163,103 @@ function firewall_lock_release() { } function firewall_custom_chains() { + local protocol="${1}" + assert isset protocol + log INFO "Creating CUSTOM* chains..." # These chains are intened to be filled with # rules by the user. They are processed at the very # beginning so it is possible to overwrite everything. - iptables_chain_create CUSTOMINPUT - iptables -A INPUT -j CUSTOMINPUT + iptables_chain_create "${protocol}" CUSTOMINPUT + iptables "${protocol}" -A INPUT -j CUSTOMINPUT - iptables_chain_create CUSTOMFORWARD - iptables -A FORWARD -j CUSTOMFORWARD + iptables_chain_create "${protocol}" CUSTOMFORWARD + iptables "${protocol}" -A FORWARD -j CUSTOMFORWARD - iptables_chain_create CUSTOMOUTPUT - iptables -A OUTPUT -j CUSTOMOUTPUT + iptables_chain_create "${protocol}" CUSTOMOUTPUT + iptables "${protocol}" -A OUTPUT -j CUSTOMOUTPUT - iptables_chain_create -4 -t nat CUSTOMPREROUTING - iptables -4 -t nat -A PREROUTING -j CUSTOMPREROUTING + iptables_chain_create "${protocol}" -t nat CUSTOMPREROUTING + iptables "${protocol}" -t nat -A PREROUTING -j CUSTOMPREROUTING - iptables_chain_create -4 -t nat CUSTOMPOSTROUTING - iptables -4 -t nat -A POSTROUTING -j CUSTOMPOSTROUTING + iptables_chain_create "${protocol}" -t nat CUSTOMPOSTROUTING + iptables "${protocol}" -t nat -A POSTROUTING -j CUSTOMPOSTROUTING - iptables_chain_create -4 -t nat CUSTOMOUTPUT - iptables -4 -t nat -A OUTPUT -j CUSTOMOUTPUT + iptables_chain_create "${protocol}" -t nat CUSTOMOUTPUT + iptables "${protocol}" -t nat -A OUTPUT -j CUSTOMOUTPUT } function firewall_tcp_state_flags() { + local protocol="${1}" + assert isset protocol + log INFO "Creating TCP State Flags chain..." - iptables_chain_create BADTCP_LOG - iptables -A BADTCP_LOG -p tcp -j $(iptables_LOG "Illegal TCP state: ") - iptables -A BADTCP_LOG -j DROP - - iptables_chain_create BADTCP - iptables -A BADTCP -p tcp --tcp-flags ALL NONE -j BADTCP_LOG - iptables -A BADTCP -p tcp --tcp-flags SYN,FIN SYN,FIN -j BADTCP_LOG - iptables -A BADTCP -p tcp --tcp-flags SYN,RST SYN,RST -j BADTCP_LOG - iptables -A BADTCP -p tcp --tcp-flags FIN,RST FIN,RST -j BADTCP_LOG - iptables -A BADTCP -p tcp --tcp-flags ACK,FIN FIN -j BADTCP_LOG - iptables -A BADTCP -p tcp --tcp-flags ACK,PSH PSH -j BADTCP_LOG - iptables -A BADTCP -p tcp --tcp-flags ACK,URG URG -j BADTCP_LOG - - iptables -A INPUT -p tcp -j BADTCP - iptables -A OUTPUT -p tcp -j BADTCP - iptables -A FORWARD -p tcp -j BADTCP + + iptables_chain_create "${protocol}" BADTCP_LOG + iptables "${protocol}" -A BADTCP_LOG -p tcp -j "$(iptables_LOG "Illegal TCP state: ")" + iptables "${protocol}" -A BADTCP_LOG -j DROP + + iptables_chain_create "${protocol}" BADTCP + iptables "${protocol}" -A BADTCP -p tcp --tcp-flags ALL NONE -j BADTCP_LOG + iptables "${protocol}" -A BADTCP -p tcp --tcp-flags SYN,FIN SYN,FIN -j BADTCP_LOG + iptables "${protocol}" -A BADTCP -p tcp --tcp-flags SYN,RST SYN,RST -j BADTCP_LOG + iptables "${protocol}" -A BADTCP -p tcp --tcp-flags FIN,RST FIN,RST -j BADTCP_LOG + iptables "${protocol}" -A BADTCP -p tcp --tcp-flags ACK,FIN FIN -j BADTCP_LOG + iptables "${protocol}" -A BADTCP -p tcp --tcp-flags ACK,PSH PSH -j BADTCP_LOG + iptables "${protocol}" -A BADTCP -p tcp --tcp-flags ACK,URG URG -j BADTCP_LOG + + iptables "${protocol}" -A INPUT -p tcp -j BADTCP + iptables "${protocol}" -A OUTPUT -p tcp -j BADTCP + iptables "${protocol}" -A FORWARD -p tcp -j BADTCP } function firewall_tcp_clamp_mss() { # Do nothing if this has been disabled. enabled FIREWALL_CLAMP_PATH_MTU || return ${EXIT_OK} + local protocol="${1}" + assert isset protocol + log DEBUG "Adding rules to clamp MSS to path MTU..." - iptables -t mangle -A FORWARD \ + + iptables "${protocol}" -t mangle -A FORWARD \ -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu } function firewall_connection_tracking() { + local protocol="${1}" + assert isset protocol + log INFO "Creating Connection Tracking chain..." - iptables_chain_create CONNTRACK - iptables -A CONNTRACK -m state --state ESTABLISHED,RELATED -j ACCEPT - iptables -A CONNTRACK -m state --state INVALID -j $(iptables_LOG "INVALID packet: ") - iptables -A CONNTRACK -m state --state INVALID -j DROP - - iptables -A INPUT -j CONNTRACK - iptables -A OUTPUT -j CONNTRACK - iptables -A FORWARD -j CONNTRACK + + iptables_chain_create "${protocol}" CONNTRACK + iptables "${protocol}" -A CONNTRACK -m state --state ESTABLISHED,RELATED -j ACCEPT + iptables "${protocol}" -A CONNTRACK -m state --state INVALID -j "$(iptables_LOG "INVALID packet: ")" + iptables "${protocol}" -A CONNTRACK -m state --state INVALID -j DROP + + iptables "${protocol}" -A INPUT -j CONNTRACK + iptables "${protocol}" -A OUTPUT -j CONNTRACK + iptables "${protocol}" -A FORWARD -j CONNTRACK } function firewall_localhost_create_chains() { + local protocol="${1}" + assert isset protocol + log DEBUG "Creating firewall chains for localhost..." # Accept everything on lo - iptables -A INPUT -i lo -m state --state NEW -j ACCEPT - iptables -A OUTPUT -o lo -m state --state NEW -j ACCEPT + iptables "${protocol}" -A INPUT -i lo -m state --state NEW -j ACCEPT + iptables "${protocol}" -A OUTPUT -o lo -m state --state NEW -j ACCEPT } function firewall_zone_create_chains() { - local zone=${1} + local protocol="${1}" + assert isset protocol + + local zone="${2}" assert isset zone log DEBUG "Creating firewall chains for zone '${zone}'." @@ -228,17 +267,17 @@ function firewall_zone_create_chains() { local chain_prefix="ZONE_${zone^^}" # Create filter chains. - iptables_chain_create "${chain_prefix}_INPUT" - iptables -A INPUT -i ${zone} -j "${chain_prefix}_INPUT" + iptables_chain_create "${protocol}" "${chain_prefix}_INPUT" + iptables "${protocol}" -A INPUT -i ${zone} -j "${chain_prefix}_INPUT" - iptables_chain_create "${chain_prefix}_OUTPUT" - iptables -A OUTPUT -o ${zone} -j "${chain_prefix}_OUTPUT" + iptables_chain_create "${protocol}" "${chain_prefix}_OUTPUT" + iptables "${protocol}" -A OUTPUT -o ${zone} -j "${chain_prefix}_OUTPUT" # Custom rules. - iptables_chain_create "${chain_prefix}_CUSTOM" + iptables_chain_create "${protocol}" "${chain_prefix}_CUSTOM" # Intrusion Prevention System. - iptables_chain_create "${chain_prefix}_IPS" + iptables_chain_create "${protocol}" "${chain_prefix}_IPS" # Create a chain for each other zone. # This leaves us with n^2 chains. Duh. @@ -246,52 +285,52 @@ function firewall_zone_create_chains() { local other_zone other_chain_prefix for other_zone in $(zones_get_all); do other_chain_prefix="${chain_prefix}_${other_zone^^}" - iptables_chain_create ${other_chain_prefix} + iptables_chain_create "${protocol}" "${other_chain_prefix}" # Connect the chain with the FORWARD chain. - iptables -A FORWARD -i ${zone} -o ${other_zone} \ + iptables "${protocol}" -A FORWARD -i "${zone}" -o "${other_zone}" \ -j "${other_chain_prefix}" # Handle custom rules. - iptables -A ${other_chain_prefix} -j "${chain_prefix}_CUSTOM" + iptables "${protocol}" -A "${other_chain_prefix}" -j "${chain_prefix}_CUSTOM" # Link IPS. - iptables -A ${other_chain_prefix} -j "${chain_prefix}_IPS" + iptables "${protocol}" -A "${other_chain_prefix}" -j "${chain_prefix}_IPS" # Rules. - iptables_chain_create "${other_chain_prefix}_RULES" - iptables -A ${other_chain_prefix} -j "${other_chain_prefix}_RULES" + iptables_chain_create "${protocol}" "${other_chain_prefix}_RULES" + iptables "${protocol}" -A "${other_chain_prefix}" -j "${other_chain_prefix}_RULES" # Policy. - iptables_chain_create "${other_chain_prefix}_POLICY" - iptables -A ${other_chain_prefix} -j "${other_chain_prefix}_POLICY" + iptables_chain_create "${protocol}" "${other_chain_prefix}_POLICY" + iptables "${protocol}" -A "${other_chain_prefix}" -j "${other_chain_prefix}_POLICY" done ## Create mangle chain. - #iptables_chain_create -t mangle ${chain_prefix} - #iptables -t mangle -A PREROUTING -i ${zone} -j ${chain_prefix} - #iptables -t mangle -A POSTROUTING -o ${zone} -j ${chain_prefix} + #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}" + #iptables "${protocol}" -t mangle -A PREROUTING -i "${zone}" -j "${chain_prefix}" + #iptables "${protocol}" -t mangle -A POSTROUTING -o "${zone}" -j "${chain_prefix}" ## Quality of Service - #iptables_chain_create -t mangle "${chain_prefix}_QOS_INC" - #iptables -t mangle -A ${chain_prefix} -i ${zone} -j "${chain_prefix}_QOS_INC" - #iptables_chain_create -t mangle "${chain_prefix}_QOS_OUT" - #iptables -t mangle -A ${chain_prefix} -o ${zone} -j "${chain_prefix}_QOS_OUT" + #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}_QOS_INC" + #iptables "${protocol}" -t mangle -A "${chain_prefix}" -i "${zone}" -j "${chain_prefix}_QOS_INC" + #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}_QOS_OUT" + #iptables "${protocol}" -t mangle -A "${chain_prefix}" -o "${zone}" -j "${chain_prefix}_QOS_OUT" # Create NAT chain. - iptables_chain_create -4 -t nat ${chain_prefix} - iptables -4 -t nat -A PREROUTING -i ${zone} -j ${chain_prefix} - iptables -4 -t nat -A POSTROUTING -o ${zone} -j ${chain_prefix} + iptables_chain_create "${protocol}" -t nat "${chain_prefix}" + iptables "${protocol}" -t nat -A PREROUTING -i "${zone}" -j "${chain_prefix}" + iptables "${protocol}" -t nat -A POSTROUTING -o "${zone}" -j "${chain_prefix}" # Network Address Translation - iptables_chain_create -4 -t nat "${chain_prefix}_DNAT" - iptables -4 -t nat -A PREROUTING -i ${zone} -j "${chain_prefix}_DNAT" - iptables_chain_create -4 -t nat "${chain_prefix}_SNAT" - iptables -4 -t nat -A POSTROUTING -o ${zone} -j "${chain_prefix}_SNAT" + iptables_chain_create "${protocol}" -t nat "${chain_prefix}_DNAT" + iptables "${protocol}" -t nat -A PREROUTING -i "${zone}" -j "${chain_prefix}_DNAT" + iptables_chain_create "${protocol}" -t nat "${chain_prefix}_SNAT" + iptables "${protocol}" -t nat -A POSTROUTING -o "${zone}" -j "${chain_prefix}_SNAT" # UPnP - iptables_chain_create -4 -t nat "${chain_prefix}_UPNP" - iptables -4 -t nat -A ${chain_prefix} -j "${chain_prefix}_UPNP" + iptables_chain_create "${protocol}" -t nat "${chain_prefix}_UPNP" + iptables "${protocol}" -t nat -A "${chain_prefix}" -j "${chain_prefix}_UPNP" return ${EXIT_OK} } diff --git a/functions.firewall-policy b/functions.firewall-policy new file mode 100644 index 00000000..842fa9fb --- /dev/null +++ b/functions.firewall-policy @@ -0,0 +1,127 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2012 IPFire Network Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +function policy_zone_add() { + local zone=${1} + assert isset zone + + local ${FIREWALL_ZONE_SETTINGS} + firewall_zone_read ${zone} + + # Apply masquerading. + if enabled MASQUERADE4; then + policy_zone_masquerade4 ${zone} + fi + + # Allow/deny cross-zone communication. + local other_zone + for other_zone in $(zones_get_all); do + if list_match "${other_zone}" ${FRIEND_ZONES}; then + policy_zone_allow_all ${zone} ${other_zone} + else + policy_zone_deny_all ${zone} ${other_zone} + fi + done +} + +function policy_zone_masquerade4() { + local zone=${1} + assert isset zone + + local chain="ZONE_${zone^^}_SNAT" + + iptables -4 -t nat -A "${chain}" -o ${zone} \ + -j MASQUERADE --random +} + +function policy_zone_allow_all() { + local zone=${1} + assert isset zone + + local other_zone=${2} + assert isset other_zone + + local chain="ZONE_${zone^^}_${other_zone^^}_POLICY" + + # Just accept all new connections. + iptables -A "${chain}" -m state --state NEW -j ACCEPT +} + +function policy_zone_deny_all() { + local zone=${1} + assert isset zone + + local other_zone=${2} + assert isset other_zone + + local chain="ZONE_${zone^^}_${other_zone^^}_POLICY" + + # Just accept all new connections. + iptables -A "${chain}" -j DROP +} + +function policy_drop_all() { + # Nothing to do here, because that is the + # default policy of the INPUT/OUTPUT/FORWARD chain. + : +} + +function policy_import_all_rules() { + # This will populate all chains with the rules + # for the given zone. + + local zone=${1} + assert isset zone + + local chain=${2} + assert isset chain + + local zone_dir=$(firewall_zone_dir ${zone}) + assert isset zone_dir + + local rulesfile="${zone_dir}/rules" + + #firewall_parse_rules "${rulesfile}" \ + # -A ${chain}_RULES_INC +} + +function policy_load() { + local zone_from=${1} + assert isset zone_from + + local zone_to=${2} + assert isset zone_to + + local chain=${3} + assert isset chain + + # Allow routes that have the same incoming and outgoing interface. + if [ "${zone_from}" = "${zone_to}" ]; then + iptables -A ${chain} -j ACCEPT + return ${EXIT_OK} + fi + + # Grant all local zones accessing everything (GREEN). + if zone_is_local ${zone_from}; then + iptables -A ${chain} -j ACCEPT + return ${EXIT_OK} + fi +} diff --git a/functions.iptables b/functions.iptables index 98658bbe..3e1b9293 100644 --- a/functions.iptables +++ b/functions.iptables @@ -2,7 +2,7 @@ ############################################################################### # # # IPFire.org - A linux based firewall # -# Copyright (C) 2012 IPFire Network Development Team # +# Copyright (C) 2012-2013 IPFire Network Development Team # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # @@ -19,43 +19,34 @@ # # ############################################################################### +IPTABLES_TABLES="filter mangle nat" + function iptables() { - local arg - local args + local protocol="${1}" + assert isset protocol + shift + + # Rules go to the filter table by default local table="filter" - local src dst - # Default is both protocols. - local proto="6 4" + # Argument list + local args - # Check if the directory where we put our rules in is set and - # exists. - assert isset IPTABLES_TMPDIR - assert [ -d "${IPTABLES_TMPDIR}" ] + # Cached arguments + local src dst # Parsing arguments while [ $# -gt 0 ]; do case "${1}" in - # Select IPv4 protocol. - -4) - proto="4" - shift - ;; - # Select IPv6 protocol. - -6) - proto="6" - shift - ;; + # Filter to which table this rule should go. -t) - table=${2} - shift 2 - ;; - -A) - args="${args} -A ${2^^}" + table="${2}" shift 2 + + assert isoneof table ${IPTABLES_TABLES} ;; *) - args="${args} ${1}" + list_append args "${1}" # Save some values for further processing. case "${1}" in @@ -71,73 +62,99 @@ function iptables() { esac done - # Check that the nat table is not used for IPv6. - if isoneof 6 ${proto}; then - assert [ "${table}" != "nat" ] - fi + assert isset action - # Detect the version of the IP protocol. + # Check if given IP addresses or networks match the protocol version. local src_proto - isset src && src_proto=$(ip_detect_protocol ${src}) + if isset src; then + src_proto="$(ip_detect_protocol ${src})" + + assert [ "${protocol}" = "${src_proto}" ] + fi local dst_proto - isset dst && dst_proto=$(ip_detect_protocol ${dst}) + if isset dst; then + dst_proto="$(ip_detect_protocol ${dst})" - # Check that the source and destinations are not - # using different versions of the IP protocol. - if isset src_proto && isset dst_proto; then - assert [ "${src_proto}" = "${dst_proto}" ] + assert [ "${protocol}" = "${dst_proto}" ] fi - local rulesfile - local p - for p in ${proto}; do - case "${p}" in - 6) - listmatch ipv4 ${src_proto} ${dst_proto} \ - && continue + # Check if the directory where we put our rules in is set and + # exists. + assert isset IPTABLES_TMPDIR + local rulesfile="${IPTABLES_TMPDIR}/${protocol}-${table}" + + print "${args}" >> "${rulesfile}" + assert_check_retval $? +} + +function iptables_chain_create() { + local protocol="${1}" + assert isset protocol + shift + + local chain + local table="filter" + local policy="-" + + while [ $# -gt 0 ]; do + case "${1}" in + -t) + table="${2}" + shift ;; - 4) - listmatch ipv6 ${src_proto} ${dst_proto} \ - && continue + --policy=*) + policy="$(cli_get_val ${1})" + ;; + -*) + log WARNING "Unrecognized argument: ${1}" + ;; + *) + chain=${1} ;; esac + shift + done - rulesfile=$(iptables_rulesfile ipv${p} ${table}) - assert isset rulesfile + assert isset chain + assert isset table + assert isoneof policy ACCEPT DROP "-" - print "${args:1:${#args}}" >> ${rulesfile} - done + iptables "${protocol}" -t "${table}" ":${chain} ${policy} [0:0]" } # Calls the binary iptables command. function _iptables() { - local iptables_cmd=$(which iptables) - assert isset iptables_cmd - - cmd ${iptables_cmd} $@ -} - -function iptables_status() { - _iptables -L -n -v -} - -# Returns which tables exist for the given protocol. -function iptables_tables() { - local proto=${1} - assert isset proto + local protocol="${1}" + assert isset protocol + shift - case "${proto}" in + local cmd + case "${protocol}" in ipv6) - print "filter mangle" + cmd="ip6tables" ;; ipv4) - print "filter mangle nat" - ;; - *) - return ${EXIT_ERROR} + cmd="iptables" ;; esac + assert isset cmd + cmd="$(which ${cmd})" + + cmd "${cmd}" "$@" + return $? +} + +function iptables_status() { + local protocol="${1}" + assert isset protocol + + local table + for table in ${IPTABLES_TABLES}; do + print "${protocol} - ${table}:" + _iptables "${protocol}" -t "${table}" -L -n -v + print + done return ${EXIT_OK} } @@ -153,133 +170,173 @@ function iptables_rulesfile() { } function iptables_init() { - local policy=${1} + local protocol="${1}" + assert isset protocol + + local policy="${2}" assert isset policy # Create filter table and initialize chains. - iptables "* filter" - iptables_chain_create -t filter INPUT --policy=${policy} - iptables_chain_create -t filter OUTPUT --policy=${policy} - iptables_chain_create -t filter FORWARD --policy=${policy} - - # Create mangle table initialize chains. - iptables -t mangle "* mangle" - iptables_chain_create -t mangle PREROUTING --policy=ACCEPT - iptables_chain_create -t mangle INPUT --policy=ACCEPT - iptables_chain_create -t mangle OUTPUT --policy=ACCEPT - iptables_chain_create -t mangle FORWARD --policy=ACCEPT - iptables_chain_create -t mangle POSTROUTING --policy=ACCEPT - - # Add NAT table for IPv4. - iptables -4 -t nat "* nat" - iptables_chain_create -4 -t nat PREROUTING --policy=ACCEPT - iptables_chain_create -4 -t nat OUTPUT --policy=ACCEPT - iptables_chain_create -4 -t nat POSTROUTING --policy=ACCEPT + iptables "${protocol}" "* filter" + iptables_chain_create "${protocol}" -t filter INPUT --policy="${policy}" + iptables_chain_create "${protocol}" -t filter OUTPUT --policy="${policy}" + iptables_chain_create "${protocol}" -t filter FORWARD --policy="${policy}" + + # Create mangle table and initialize chains. + iptables "${protocol}" -t mangle "* mangle" + iptables_chain_create "${protocol}" -t mangle PREROUTING --policy="ACCEPT" + iptables_chain_create "${protocol}" -t mangle INPUT --policy="ACCEPT" + iptables_chain_create "${protocol}" -t mangle OUTPUT --policy="ACCEPT" + iptables_chain_create "${protocol}" -t mangle FORWARD --policy="ACCEPT" + iptables_chain_create "${protocol}" -t mangle POSTROUTING --policy="ACCEPT" + + # Create NAT table and initialize chains. + iptables "${protocol}" -t nat "* nat" + iptables_chain_create "${protocol}" -t nat PREROUTING --policy="ACCEPT" + iptables_chain_create "${protocol}" -t nat OUTPUT --policy="ACCEPT" + iptables_chain_create "${protocol}" -t nat POSTROUTING --policy="ACCEPT" } # Load the created ruleset into the kernel. -function iptables_load() { - # If first argument is present and true, we - # run in test mode. - local test="${1}" - - local rulesfile +function iptables_commit () { + local protocol="${1}" + assert isset protocol + shift - # Concat the table rulesets into one big file. - local proto - for proto in 6 4; do - rulesfile=$(iptables_rulesfile ipv${proto}) - assert isset rulesfile + local testmode="false" - local table - local tablefile - for table in $(iptables_tables ipv${proto}); do - tablefile=$(iptables_rulesfile ipv${proto} ${table}) + while [ $# -gt 0 ]; do + case "${1}" in + --test) + testmode="true" + ;; + *) + log WARNING "Unrecognized argument: ${1}" + ;; + esac + shift + done - fread ${tablefile} + # Concat all rules into one big file. + local rulesfile="${IPTABLES_TMPDIR}/ruleset" + _iptables_commit_cat_rulesfile "${protocol}" "${rulesfile}" + + # Run the following loop twice: + # 1st: Check if the ruleset can be loaded + # 2nd: If not in test mode, actually load the ruleset into the kernel + local load_cmd="--test" + local ret=0 + + local i + for i in 0 1; do + _iptables_commit_load_rulesfile "${protocol}" "${rulesfile}" "${load_cmd}" + ret=$? + + case "${i},${ret}" in + 0,${EXIT_OK}) + iptables_dump "${protocol}" "${rulesfile}" --log-facility="DEBUG" + log DEBUG "Ruleset load check succeeded (${protocol})" + ;; - # Add the COMMIT statement for every table. - if [ -s "${tablefile}" ]; then - print "COMMIT" - fi - done > ${rulesfile} + # Loading rules has failed (test) + 0,*) + iptables_dump "${protocol}" "${rulesfile}" --log-facility="CRITICAL" + log CRITICAL "Ruleset load check failed (${protocol} - ${ret})" + return ${ret} + ;; - assert [ -s "${rulesfile}" ] - done + 1,${EXIT_OK}) + log DEBUG "Ruleset successfully loaded (${protocol})" + return ${EXIT_OK} + ;; - local error="false" - local ret + 1,*) + log CRITICAL "Ruleset loading failed (${protocol})" + return ${ret} + ;; + esac - # First check if everything is correctly formatted. - for proto in 6 4; do - rulesfile=$(iptables_rulesfile ipv${proto}) - assert isset rulesfile + # Skip the second loop iteration, if we are running in test mode. + enabled testmode && break - _iptables_load ipv${proto} ${rulesfile} true - if [ $? -ne ${EXIT_OK} ]; then - log CRITICAL "Ruleset load check failed for IPv${proto}" - error="true" - fi + load_cmd="" done - # Check if there has been an error in the load check. - if enabled error; then - iptables_dump CRITICAL + return ${EXIT_OK} +} - log CRITICAL "New firewall rules could not be loaded." - return ${EXIT_ERROR} - fi +function _iptables_commit_cat_rulesfile() { + local protocol="${1}" + assert isset protocol - # Dump the data, we are going to load. - iptables_dump + local rulesfile="${2}" + assert isset rulesfile - # If we are running in test mode, we are done here. - enabled test && return ${EXIT_OK} + local table + local file + for table in ${IPTABLES_TABLES}; do + file="${IPTABLES_TMPDIR}/${protocol}-${table}" - # If we got until here, everything is fine to load the ruleset. - for proto in 6 4; do - rulesfile=$(iptables_rulesfile ipv${proto}) + fread "${file}" - _iptables_load ipv${proto} ${rulesfile} - done - return ${EXIT_OK} + # Add the COMMIT statement for every table. + print "COMMIT" + done > "${rulesfile}" + + assert [ -s "${rulesfile}" ] } -function _iptables_load() { - local proto=${1} - local file=${2} - local testmode=${3} +function _iptables_commit_load_rulesfile() { + local protocol="${1}" + assert isset protocol + + local rulesfile="${2}" + assert isset rulesfile + shift 2 + + local testmode="false" + while [ $# -gt 0 ]; do + case "${1}" in + --test) + testmode="true" + ;; + esac + shift + done - local command - case "${proto}" in + local iptables_cmd + case "${protocol}" in ipv6) - command="ip6tables-restore" + iptables_cmd="ip6tables-restore" ;; ipv4) - command="iptables-restore" + iptables_cmd="iptables-restore" ;; esac - assert isset command + assert isset iptables_cmd if enabled testmode; then - command="${command} --test" + list_append iptables_cmd "--test" fi - local time_started=$(date -u "+%s") + # Save when importing the rules has started. + local time_started="$(timestamp)" - cmd ${command} < ${file} + cmd "${iptables_cmd}" < "${rulesfile}" local ret=$? case "${ret}" in ${EXIT_OK}) - local time_finished=$(date -u "+%s") - time_finished=$(( ${time_finished} - ${time_started} )) - log INFO \ - "Successfully loaded new firewall ruleset for IPv${proto/ipv/} in ${time_finished}s!" + local time_finished="$(timestamp)" + time_finished="$(( ${time_finished} - ${time_started} ))" + + enabled testmode && return ${EXIT_OK} + + log INFO "Successfully loaded new firewall ruleset for ${protocol} in ${time_finished}s!" ;; *) if ! enabled testmode; then - log CRITICAL "Error loading firewall ruleset for IPv${proto/ipv/}!" + log CRITICAL "Error loading firewall ruleset for ${protocol}!" fi ;; esac @@ -288,63 +345,38 @@ function _iptables_load() { } function iptables_dump() { - local log_facility=${1-DEBUG} + local protocol="${1}" + assert isset protocol - # Here is nothing to do, if we are not running in - # debug mode. - enabled DEBUG || return ${EXIT_OK} + local rulesfile="${2}" + assert isset rulesfile + shift 2 - local rulesfile - local counter - local line + local log_facility="INFO" - local proto - for proto in 6 4; do - rulesfile=$(iptables_rulesfile ipv${proto}) - [ -e "${rulesfile}" ] || continue - - log ${log_facility} "Firewall ruleset for IPv${proto}:" - - counter=1 - while read -r line; do - printf -v line "%4d | %s" "${counter}" "${line}" - log ${log_facility} "${line}" - - counter=$(( $counter + 1 )) - done < ${rulesfile} - done -} - -function iptables_chain_create() { - local chain - local table="filter" - local policy="-" - local proto - local args while [ $# -gt 0 ]; do case "${1}" in - -6|-4) - proto=${1} - ;; - -t) - table=${2} - shift - ;; - --policy=*) - policy=$(cli_get_val ${1}) + --log-facility=*) + log_facility="$(cli_get_val ${1})" ;; *) - chain=${1} + log WARNING "Unrecognized argument: ${1}" ;; esac shift done - assert isset chain - assert isset table - assert isoneof policy ACCEPT DROP "-" + # Say what we are going to do: + log "${log_facility}" "Firewall ruleset for ${protocol}:" + + local counter="0" + local line + while read -r line; do + counter="$(( ${counter} + 1 ))" - iptables ${proto} -t ${table} ":${chain} ${policy} [0:0]" + printf -v line "%4d | %s" "${counter}" "${line}" + log "${log_facility}" "${line}" + done < "${rulesfile}" } function iptables_LOG() { diff --git a/functions.util b/functions.util index 3a4751f4..1fb19515 100644 --- a/functions.util +++ b/functions.util @@ -52,6 +52,18 @@ function quote() { print "\"%s\"" "$@" } +function strip() { + local value="$@" + + # remove leading whitespace characters + value="${value#"${value%%[![:space:]]*}"}" + + # remove trailing whitespace characters + value="${value%"${value##*[![:space:]]}"}" + + print "${value}" +} + # Print a pretty error message function error() { echo -e " ${CLR_RED_B}ERROR${CLR_RESET} : $@" >&2 @@ -340,6 +352,11 @@ function which() { type -P $@ } +# Prints the number of seconds since epoch. +function timestamp() { + date -u "+%s" +} + function beautify_time() { local value=${1} diff --git a/network b/network index 78229005..5a5aba28 100755 --- a/network +++ b/network @@ -35,6 +35,9 @@ done . /usr/lib/network/functions +# Read network configuration. +network_config_read + function cli_config() { if cli_help_requested $@; then cli_show_man network-config