]> git.ipfire.org Git - network.git/commitdiff
firewall: Create a basic layout of the firewall chains.
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 3 Oct 2012 16:13:49 +0000 (16:13 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 3 Oct 2012 16:13:49 +0000 (16:13 +0000)
This patch adds code which creates a default set of chains.
No thing will be put into them which makes any sense, but
it's a start...

functions.constants-firewall
functions.firewall
functions.firewall-zones
functions.policy [deleted file]

index 75e1a36af0e81009ad7a967319ca38e447fa3a79..d1fab5d5a875685530b7142a25d6390034ccaec3 100644 (file)
@@ -34,6 +34,9 @@ FIREWALL_MACROS_DIRS="${FIREWALL_MACROS_DIRS} /usr/share/firewall/macros"
 # List of parameters which are saved in the configuration file.
 FIREWALL_CONFIG_PARAMS=""
 
+# Valid arguments in the rules file.
+FIREWALL_RULES_CONFIG_PARAMS="src dst proto action sport dport in out"
+
 # Define the default logging method (nflog or syslog).
 FIREWALL_LOG_METHOD="nflog"
 FIREWALL_CONFIG_PARAMS="${FIREWALL_CONFIG_PARAMS} FIREWALL_LOG_METHOD"
@@ -45,3 +48,12 @@ FIREWALL_CONFIG_PARAMS="${FIREWALL_CONFIG_PARAMS} FIREWALL_NFLOG_THRESHOLD"
 # Enable clamping MSS for braindead ISPs which filter ICMP packets.
 FIREWALL_CLAMP_PATH_MTU="false"
 FIREWALL_CONFIG_PARAMS="${FIREWALL_CONFIG_PARAMS} FIREWALL_CLAMP_PATH_MTU"
+
+FIREWALL_SUPPORTED_PROTOCOLS="tcp udp icmp igmp esp ah gre"
+FIREWALL_PROTOCOLS_SUPPORTING_PORTS="tcp udp"
+
+# Firewall zone settings.
+FIREWALL_ZONE_SETTINGS="FRIEND_ZONES MASQUERADE4"
+
+# Default values.
+FIREWALL_ZONE_SETTINGS_MASQUERADE4="false"
index 37ee847d58a8ccd656dcce6260980fccaf428f10..ba57943975e8d5d25d9029a74127413fd3de52cd 100644 (file)
@@ -51,11 +51,19 @@ function firewall_start() {
        firewall_tcp_clamp_mss
 
        # Add policies for every zone.
-       policy_add_localhost
+       firewall_localhost_create_chains
 
        local zone
        for zone in $(zones_get_all); do
-               policy_add_zone ${zone}
+               # Create all needed chains for the zone.
+               firewall_zone_create_chains ${zone}
+
+               # After the chains that are always available have been
+               # created, we will add a custom policy to every single
+               # zone.
+
+               # XXX TODO
+               #policy_zone_add ${zone}
        done
 
        # Load the new ruleset.
@@ -200,36 +208,208 @@ function firewall_connection_tracking() {
        iptables -A FORWARD -j CONNTRACK
 }
 
-function firewall_import_rules() {
+function firewall_localhost_create_chains() {
+       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
+}
+
+function firewall_zone_create_chains() {
        local zone=${1}
+       assert isset zone
+
+       log DEBUG "Creating firewall chains for zone '${zone}'."
+
+       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 "${chain_prefix}_OUTPUT"
+       iptables -A OUTPUT  -o ${zone} -j "${chain_prefix}_OUTPUT"
+
+       # Custom rules.
+       iptables_chain_create "${chain_prefix}_CUSTOM"
+
+       # Intrusion Prevention System.
+       iptables_chain_create "${chain_prefix}_IPS"
+
+       # Create a chain for each other zone.
+       # This leaves us with n^2 chains. Duh.
+
+       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}
+
+               # Connect the chain with the FORWARD chain.
+               iptables -A FORWARD -i ${zone} -o ${other_zone} \
+                       -j "${other_chain_prefix}"
+
+               # Handle custom rules.
+               iptables -A ${other_chain_prefix} -j "${chain_prefix}_CUSTOM"
+
+               # Link IPS.
+               iptables -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"
+
+               # Policy.
+               iptables_chain_create "${other_chain_prefix}_POLICY"
+               iptables -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}
+
+       ## 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"
+
+       # 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}
+
+       # 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"
+
+       # UPnP
+       iptables_chain_create -4 -t nat "${chain_prefix}_UPNP"
+       iptables -4 -t nat -A ${chain_prefix} -j "${chain_prefix}_UPNP"
+
+       return ${EXIT_OK}
+}
+
+function firewall_parse_rules() {
+       local file=${1}
+       assert isset file
        shift
 
-       local protocol="ipv6"
-       local table="filter"
+       # End if no rule file exists.
+       [ -r "${file}" ] || return ${EXIT_OK}
 
-       while [ $# -gt 0 ]; do
-               case "${1}" in
-                       --table=*)
-                               table=$(cli_get_val ${1})
-                               ;;
-                       --protocol=*)
-                               protocol=$(cli_get_val ${1})
-                               ;;
-               esac
+       local cmd
+
+       local ${FIREWALL_RULES_CONFIG_PARAMS}
+       local line
+       while read -r line; do
+               # Skip empty lines.
+               [ -n "${line}" ] || continue
+
+               # Skip commented lines.
+               [ "${line:0:1}" = "#" ] && continue
+
+               # Parse the rule.
+               _firewall_parse_rule_line ${line}
+               if [ $? -ne ${EXIT_OK} ]; then
+                       log WARNING "Skipping invalid line: ${line}"
+                       continue
+               fi
+
+               cmd="iptables $@"
+
+               # Source IP address/net.
+               if isset src; then
+                       list_append cmd "-s ${src}"
+               fi
+
+               # Destination IP address/net.
+               if isset dst; then
+                       list_append cmd "-d ${dst}"
+               fi
+
+               # Protocol.
+               if isset proto; then
+                       list_append cmd "-p ${proto}"
+
+                       if list_match ${proto} ${FIREWALL_PROTOCOLS_SUPPORTING_PORTS}; then
+                               if isset sport; then
+                                       list_append cmd "--sport ${sport}"
+                               fi
+
+                               if isset dport; then
+                                       list_append cmd "--dport ${dport}"
+                               fi
+                       fi
+               fi
+
+               # Always append the action.
+               list_append cmd "-j ${action}"
+
+               # Execute command.
+               ${cmd}
+       done < ${file}
+}
+
+function _firewall_parse_rule_line() {
+       local arg
+
+       # Clear all values.
+       for arg in ${FIREWALL_RULES_CONFIG_PARAMS}; do
+               assign "${arg}" ""
        done
 
-       assert isoneof protocol ipv4 ipv6
-       assert isoneof table $(iptables_table ${protocol})
+       local key val
+       while read -r arg; do
+               key=$(cli_get_key ${arg})
 
-       # XXX TODO
+               if ! listmatch "${key}" ${FIREWALL_RULES_CONFIG_PARAMS}; then
+                       log WARNING "Unrecognized argument: ${arg}"
+                       return ${EXIT_ERROR}
+               fi
 
-       local src dst proto
-       while read src dst proto; do
-               case "${chain}" in
-                       filter)
-                               ;;
-                       nat)
-                               ;;
-               esac
-       done < ${FIREWALL_CONFIG_RULES}
+               val=$(cli_get_val ${arg})
+               assign "${key}" "${val}"
+       done <<< "$(args $@)"
+
+       # action must always be set.
+       if ! isset action; then
+               log WARNING "'action' is not set: $@"
+               return ${EXIT_ERROR}
+       fi
+
+       for arg in src dst; do
+               isset ${arg} || continue
+
+               # Check for valid IP addresses.
+               if ! ip_is_valid ${!arg}; then
+                       log WARNING "Invalid IP address for '${arg}=${!arg}': $@"
+                       return ${EXIT_ERROR}
+               fi
+       done
+
+       if isset proto; then
+               # Make lowercase.
+               proto=${proto,,}
+
+               if ! list_match "${proto}" ${FIREWALL_SUPPORTED_PROTOCOLS}; then
+                       log WARNING "Unsupported protocol type 'proto=${proto}': $@"
+                       return ${EXIT_ERROR}
+               fi
+       fi
+
+       for arg in sport dport; do
+               isset ${arg} || continue
+
+               # Check if port is valid.
+               if ! isinteger ${arg}; then
+                       log WARNING "Invalid port '${arg}=${!arg}': $@"
+                       return ${EXIT_ERROR}
+               fi
+       done
+
+       return ${EXIT_OK}
 }
index 70251988fa04e1ecca4d76e847401cbab1cc51e3..69129e38700f069cdada4c11c323414bfba1abaf 100644 (file)
@@ -18,9 +18,6 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
 #                                                                             #
 ###############################################################################
-#
-
-FIREWALL_ZONE_SETTINGS="MASQUERADE POLICY"
 
 function firewall_zone_create() {
        local zone=${1}
@@ -52,17 +49,6 @@ function firewall_zone_exists() {
        [ -r "${file}" ] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
 }
 
-function firewall_zone_defaults() {
-       local zone=${1}
-       assert isset zone
-
-       # Default policy.
-       POLICY="DROP"
-
-       # Don't masquerade by default (IPv4 only).
-       MASQUERADE="false"
-}
-
 function firewall_zone_read() {
        local zone=${1}
        assert isset zone
@@ -70,10 +56,16 @@ function firewall_zone_read() {
        local file=$(firewall_zone_config ${zone})
        assert isset file
 
-       # Load default settings.
-       firewall_zone_defaults ${zone}
-
        config_read ${file} ${FIREWALL_ZONE_SETTINGS}
+
+       local arg default
+       for arg in ${FIREWALL_ZONE_SETTINGS}; do
+               isset ${arg} && continue
+
+               default="FIREWALL_ZONE_SETTINGS_${arg}"
+               assign "${arg}" "${!default}"
+       done
+
        return ${EXIT_OK}
 }
 
@@ -102,6 +94,7 @@ function firewall_zone_print() {
 
 function firewall_zone_edit() {
        local zone=${1}
+       assert isset zone
        shift
 
        assert firewall_zone_exists ${zone}
@@ -112,8 +105,8 @@ function firewall_zone_edit() {
 
                while [ $# -gt 0 ]; do
                        case "${1}" in
-                               --masquerade=*)
-                                       MASQUERADE=$(cli_get_val ${1})
+                               --masquerade4=*)
+                                       MASQUERADE4=$(cli_get_val ${1})
                                        ;;
                                --policy=*)
                                        POLICY=$(cli_get_val ${1})
@@ -125,6 +118,13 @@ function firewall_zone_edit() {
                        shift
                done
 
+               # Sanetize saved value.
+               if enabled MASQUERADE4; then
+                       MASQUERADE4="true"
+               else
+                       MASQUERADE4="false"
+               fi
+
                # Write updated settings.
                firewall_zone_write ${zone}
        )
diff --git a/functions.policy b/functions.policy
deleted file mode 100644 (file)
index 5584d69..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-#!/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 <http://www.gnu.org/licenses/>.       #
-#                                                                             #
-###############################################################################
-
-function policy_add_zone() {
-       local zone=${1}
-       assert isset zone
-
-       log DEBUG "Creating firewall policy for zone '${zone}'."
-
-       local chain="ZONE_${zone}"
-       chain=${chain^^}
-
-       # Create filter chain.
-       iptables_chain_create ${chain}
-       iptables -A INPUT   -i ${zone} -j ${chain}
-       iptables -A FORWARD -i ${zone} -j ${chain}
-       iptables -A FORWARD -o ${zone} -j ${chain}
-       iptables -A OUTPUT  -o ${zone} -j ${chain}
-
-       # Leave some space for own rules right at the beginning
-       # to make it possible to overwrite _everything_.
-       iptables_chain_create ${chain}_CUSTOM
-       iptables -A ${chain} -j ${chain}_CUSTOM
-
-       # Intrusion Prevention System
-       iptables_chain_create ${chain}_IPS
-       iptables -A ${chain} -i ${zone} -j ${chain}_IPS
-
-       # Rules for incoming packets.
-       iptables_chain_create ${chain}_RULES_INC
-       iptables -A ${chain} -i ${zone} -j ${chain}_RULES_INC
-
-       # Rules for outgoing packets.
-       iptables_chain_create ${chain}_RULES_OUT
-       iptables -A ${chain} -o ${zone} -j ${chain}_RULES_OUT
-
-       # Policy rules
-       iptables_chain_create ${chain}_POLICY
-       iptables -A ${chain} -j ${chain}_POLICY
-
-       # Create mangle chain.
-       iptables_chain_create -t mangle ${chain}
-       iptables -t mangle -A PREROUTING  -i ${zone} -j ${chain}
-       iptables -t mangle -A POSTROUTING -o ${zone} -j ${chain}
-
-       # Quality of Service
-       iptables_chain_create -t mangle ${chain}_QOS_INC
-       iptables -t mangle -A ${chain} -i ${zone} -j ${chain}_QOS_INC
-       iptables_chain_create -t mangle ${chain}_QOS_OUT
-       iptables -t mangle -A ${chain} -o ${zone} -j ${chain}_QOS_OUT
-
-       # Create NAT chain.
-       iptables_chain_create -4 -t nat ${chain}
-       iptables -4 -t nat -A PREROUTING  -i ${zone} -j ${chain}
-       iptables -4 -t nat -A POSTROUTING -o ${zone} -j ${chain}
-
-       # Network Address Translation
-       iptables_chain_create -4 -t nat ${chain}_NAT
-       iptables -4 -t nat -A ${chain} -i ${zone} -j ${chain}_NAT
-
-       # Port forwarding
-       iptables_chain_create -4 -t nat ${chain}_PORTFW
-       iptables -4 -t nat -A ${chain} -i ${zone} -j ${chain}_PORTFW
-
-       # UPNP
-       iptables_chain_create -4 -t nat ${chain}_UPNP
-       iptables -4 -t nat -A ${chain} -j ${chain}_UPNP
-
-       # After the chains that are always available have been
-       # created, we will add a custom policy to every single
-       # zone.
-
-       # Local zones are currently allowed to access everything.
-       if zone_is_local ${zone}; then
-               policy_allow_all ${zone} ${chain}
-
-       # Uplink connections are not.
-       else
-               : # XXX TODO
-       fi
-
-       # Import all configured rules and those things.
-       policy_import_all_rules ${zone} ${chain}
-}
-
-function policy_add_localhost() {
-       log DEBUG "Creating firewall policy for localhost..."
-
-       # Accept everything on lo
-       iptables -A INPUT  -i lo -j ACCEPT
-       iptables -A OUTPUT -o lo -j ACCEPT
-}
-
-function policy_allow_all() {
-       local zone=${1}
-       assert isset zone
-
-       local chain=${2}
-       assert isset chain
-
-       # Just accept everything.
-       iptables -A ${chain}_POLICY -j ACCEPT
-}
-
-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
-
-       # XXX TODO
-}