From: Michael Tremer Date: Wed, 3 Oct 2012 16:13:49 +0000 (+0000) Subject: firewall: Create a basic layout of the firewall chains. X-Git-Tag: 005~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a2c9dff5713239f53ed8db14047a44f52838b982;p=network.git firewall: Create a basic layout of the firewall chains. 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... --- diff --git a/functions.constants-firewall b/functions.constants-firewall index 75e1a36a..d1fab5d5 100644 --- a/functions.constants-firewall +++ b/functions.constants-firewall @@ -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" diff --git a/functions.firewall b/functions.firewall index 37ee847d..ba579439 100644 --- a/functions.firewall +++ b/functions.firewall @@ -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} } diff --git a/functions.firewall-zones b/functions.firewall-zones index 70251988..69129e38 100644 --- a/functions.firewall-zones +++ b/functions.firewall-zones @@ -18,9 +18,6 @@ # along with this program. If not, see . # # # ############################################################################### -# - -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 index 5584d699..00000000 --- a/functions.policy +++ /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 . # -# # -############################################################################### - -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 -}