#!/bin/bash # # rc.firewall Linux Firewall version 2.0rc9 -- 05/02/03 # http://Projectfiles.org/firewall/ # # Copyright (C) 2001-2003 Scott Bartlett # # 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 2 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: # http://www.gnu.org/licenses/gpl.html # ##################################### # -- Basic Configuration Options -- # ##################################### # # NOTE: All lists are delimited by single spaces, eg "eth0 eth1 ppp0". # # The PERMIT option below allows remote access to this machine in the three # ways listed below. Note that by default hosts in internal networks are # already allowed to connect to all services on the firewall. # 1.) Listed PORTS will be open to ANY connecting host. Protocols 'tcp' and # 'udp' can optionally be specified. If no protocol is specified, then # connections using either protocol will be accepted on the given port(s). # Format: [/] # Example: PERMIT="80/tcp 53 2400-2500/tcp" # 2.) Listed NETWORKS or HOSTS will be allowed to connect to ANY service # on the firewall itself. This option should be used to specify machines # allowed to connect for administrative purposes. # Format: [/] # Example: PERMIT="207.198.61.33 128.173.0.0/16" # NOTE (for advanced users): These networks and hosts will also be allowed to # bypass DENY_OUTBOUND and ALLOW_INBOUND restrictions for Linux routers. # 3.) Connections can be allowed from specific networks to specific ports by # listing entries in the following format: # Format:[/]:[/] # Example: PERMIT="198.82.0.0/16:80/tcp" -- (Allow web traffic from 198.82.*.*) PERMIT="" # List internal (private) interfaces here to allow this machine to act as a # router. All interfaces NOT listed here are considered external (public) # and will be automatically protected by the firewall. # Example: INTERNAL_INTERFACES="eth1 eth2 brg0" INTERNAL_INTERFACES="" # List dial-up and other interfaces without a static IP address here. # Interfaces configured to obtain an IP address automatically (DHCP) do not # need to be listed here unless for some reason your DHCP client does not # receive the same address each time it renews the lease. # Example: DYNAMIC_INTERFACES="ppp0" DYNAMIC_INTERFACES="" # Most users do not need to change anything below this point. ######################################## # -- Advanced Configuration Options -- # ######################################## # ** DO NOT ** modify anything below unless you know what you are doing!! # See online documentation at: http://Projectfiles.org/firewall/config.html DENY_OUTBOUND="" ALLOW_INBOUND="" BLACKLIST="" STATIC_INSIDE_OUTSIDE="" PORT_FORWARDS="" PORT_FWD_ALL="yes" PORT_FWD_ROUTED_NETWORKS="yes" ADDITIONAL_ROUTED_NETWORKS="" TRUST_ROUTED_NETWORKS="yes" SHARED_INTERNAL="yes" FIREWALL_IP="" TRUST_LOCAL_EXTERNAL_NETWORKS="no" DMZ_INTERFACES="" NAT_EXTERNAL="yes" ADDITIONAL_NAT_INTERFACES="" IGNORE_INTERFACES="" LOGGING="no" REQUIRE_EXTERNAL_CONFIG="no" ############################################ # -- Advanced Firewall Behavior Options -- # ############################################ # The default settings provide the suggested firewall configuration. NO_RP_FILTER_INTERFACES="" INTERNAL_DHCP="yes" RFC_1122_COMPLIANT="yes" DROP_NEW_WITHOUT_SYN="no" DUMP_TCP_ON_INIT="no" TTL_STEALTH_ROUTER="no" LOG_LIMIT="1/minute" LOG_BURST="5" LOG_LEVEL="notice" ########################################################### # -- Nothing below this point should need modification -- # ########################################################### # Set version information. VERSION="2.0rc9" COMPATIBLE_VERSIONS="2.0rc9" # Welcome! echo "-> Projectfiles.org Linux Firewall version $VERSION running." # Set PATH explicitly. export PATH="/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin" # Tell everyone if we are loading data from an external configuration file. if [ "$1" == "update" ] || [ "$1" == "load" ] || [ "$1" == "fast" ] || \ [ "$1" == "save" ] || [ "$REQUIRE_EXTERNAL_CONFIG" == "yes" ] || \ ( [ "$1" == "check" ] && [ -n "$2" ] ); then if [ -z "$2" ]; then CONFIG="/etc/firewall.conf" else CONFIG=`echo $2 | sed s#^\./#$PWD/#` fi if [ "$1" != "save" ]; then echo "-> Loading configuration from $CONFIG." fi fi # Define exit/failure function. exit_failure() { echo " [ FAILED ]" echo "-> FATAL: $FAILURE" 1>&2 if [ "$1" != "check" ]; then echo "-> Firewall configuration ** ABORTED **." 1>&2 fi exit 1 } # Sanity checking section echo -n "-> Performing sanity checks." # Make sure we are running the script with root privileges. if [ "$EUID" != "0" ]; then FAILURE="You must have root privileges to configure the firewall." exit_failure $1 fi # Make sure we have iptables installed. if (( `iptables -V 2>&1 | grep -c "command not found"` )); then FAILURE="Cannot find 'iptables' command. Did you forget to install iptables?" exit_failure $1 fi # Add SysV style initialization support. (start and restart are the same as running the script without any arguments) if [ "$1" == "stop" ] || [ "$1" == "clear" ]; then echo " [ PASSED ]" iptables -t filter -F > /dev/null 2>&1 iptables -t filter -X > /dev/null 2>&1 iptables -t nat -F > /dev/null 2>&1 iptables -t nat -X > /dev/null 2>&1 iptables -t mangle -F > /dev/null 2>&1 iptables -t mangle -X > /dev/null 2>&1 iptables -t filter -P INPUT ACCEPT > /dev/null 2>&1 iptables -t filter -P OUTPUT ACCEPT > /dev/null 2>&1 iptables -t filter -P FORWARD ACCEPT > /dev/null 2>&1 iptables -t nat -P PREROUTING ACCEPT > /dev/null 2>&1 iptables -t nat -P POSTROUTING ACCEPT > /dev/null 2>&1 iptables -t nat -P OUTPUT ACCEPT > /dev/null 2>&1 iptables -t mangle -P POSTROUTING ACCEPT > /dev/null 2>&1 iptables -t mangle -P OUTPUT ACCEPT > /dev/null 2>&1 iptables -t mangle -P PREROUTING ACCEPT > /dev/null 2>&1 iptables -t mangle -P INPUT ACCEPT > /dev/null 2>&1 iptables -t mangle -P FORWARD ACCEPT > /dev/null 2>&1 if !(( `which modprobe 2>&1 | grep -c "which: no modprobe in"` )) && [ -a "/proc/modules" ]; then for MODULE in ipt_TTL iptable_mangle ipt_mark ipt_MARK ipt_MASQUERADE \ ip_nat_irc ip_nat_ftp ipt_LOG ipt_limit ipt_REJECT \ ip_conntrack_irc ip_conntrack_ftp ipt_state iptable_nat \ iptable_filter ip_tables; do if (( `lsmod | grep -c "$MODULE"` )); then rmmod $MODULE > /dev/null 2>&1 fi done fi echo "-> Firewall disabled." exit fi # Cleanup tcp session dump rules. Note that ESTABLISHED TCP session can take up to 5 days to expire. if [ "$1" == "cleanup" ]; then echo " [ PASSED ]" COUNT=`iptables -nL INPUT | grep -c "tcp-reset"` TAB=$COUNT while [ "$((COUNT--))" -gt "0" ]; do iptables -D INPUT 1 done COUNT=`iptables -nL FORWARD | grep -c "tcp-reset"` while [ "$((COUNT--))" -gt "0" ]; do iptables -D FORWARD 1 done echo "-> Old TCP session dump rules expunged ( $TAB )...." exit fi # Check external configuration file. if [ "$1" == "update" ] || [ "$1" == "load" ] || [ "$1" == "fast" ] || \ ( [ "$REQUIRE_EXTERNAL_CONFIG" == "yes" ] && [ "$1" != "save" ] ) || \ ( [ "$1" == "check" ] && [ -n "$2" ] ); then if [ -r "$CONFIG" ]; then if (( `head -1 "$CONFIG" | grep -c "# Linux Firewall configuration -- http://Projectfiles.org/firewall/"` )); then CONFIG_VERSION='echo `head -4 "$CONFIG" | tail -1 | cut -d\\" -f2`' if [ "$1" == "update" ] || (( $(echo "$COMPATIBLE_VERSIONS" | grep -c "`eval $CONFIG_VERSION`" ) )); then . $CONFIG else if [ "$CONFIG" == "/etc/firewall.conf" ]; then CONFIG="" else CONFIG=" $CONFIG" fi FAILURE="Configuration file outdated. Please run '$0 update$CONFIG'." exit_failure $1 fi else FAILURE="The configuration file '$CONFIG' does not appear to be associated with this program. Refusing to load data." exit_failure $1 fi else FAILURE="Cannot read from file '$CONFIG'. Did you forget to save your configuration with './rc.firewall save' or has the file moved?" exit_failure $1 fi fi # Make sure we have proc filesystem support. if ! [ -a "/proc/version" ]; then FAILURE="proc filesystem support required. Please mount /proc or add proc filesystem support in your kernel." exit_failure $1 fi # Create DUMP_TCP_ON_INIT function dump_tcp() { echo -n "-> Dumping current TCP sessions...." if [ "$1" != "fast" ]; then sleep 1 # Allow a few moments for that last message to be delivered before we reset remote connections. fi COUNT=10 TAB=0 NET=`cat /proc/net/ip_conntrack | grep "^tcp" | grep ESTABLISHED | awk '{ gsub(/\ /,"\n"); print }'` for ADDRESS in `echo "$NET" | sed -n $COUNT~20p | cut -d= -f2`; do if !(( `echo $INTERNAL_ADDRESSES $EXTERNAL_ADDRESSES | grep -c "$ADDRESS"` )); then DEST=`echo "$NET" | sed -n $((COUNT+1))~20p | cut -d= -f2 | head -1` PORTS=`echo "$NET" | sed -n $((COUNT+2))~20p | cut -d= -f2 | head -1` DPORTS=`echo "$NET" | sed -n $((COUNT+3))~20p | cut -d= -f2 | head -1` iptables -I INPUT -s $ADDRESS -d $DEST -p tcp --sport $PORTS --dport $DPORTS -j REJECT --reject-with tcp-reset if [ "$IS_ROUTER" == "yes" ]; then iptables -I FORWARD -s $ADDRESS -d $DEST -p tcp --sport $PORTS --dport $DPORTS -j REJECT --reject-with tcp-reset fi TAB=$((TAB+1)) fi COUNT=$((COUNT+20)) done echo "( $TAB dumped )" } # Handle 'fast' argument. if [ "$1" == "fast" ]; then if (( `which iptables-restore 2>&1 | grep -c "which: no iptables-restore in"` )); then FAILURE="Required program 'iptables-restore' not found." exit_failure $1 fi echo " [ SKIPPED ]" echo "1" > /proc/sys/net/ipv4/conf/all/rp_filter for INTERFACE in $NO_RP_FILTER_INTERFACES; do echo "0" > /proc/sys/net/ipv4/conf/$INTERFACE/rp_filter done cat $CONFIG | sed -n 40~1p | iptables-restore if [ -n "$DYNAMIC_INTERFACES" ]; then echo "1" > /proc/sys/net/ipv4/ip_dynaddr else echo "0" > /proc/sys/net/ipv4/ip_dynaddr fi if [ "$LOGGING" == "yes" ]; then echo "1" > /proc/sys/net/ipv4/conf/all/log_martians fi if [ -n "$INTERNAL_INTERFACES" ] || [ -n "$PORT_FORWARDS" ]; then echo "1" > /proc/sys/net/ipv4/ip_forward else echo "0" > /proc/sys/net/ipv4/ip_forward fi echo "-> Firewall configuration complete. No sanity checking was performed." if [ "$DUMP_TCP_ON_INIT" == "yes" ]; then dump_tcp fast fi exit fi # Create a few sanity checking functions. check_network() { # Checks NET variable. FAILURE="" HOST=`echo "$NET/" | cut -d/ -f1` MASK=`echo "$NET/" | cut -d/ -f2` # Optional: Netfilter assumes /32 if not defined. if (( `echo "$NET/" | cut -d/ -f3 | grep -c "."` )); then FAILURE="Syntax error" return 1 fi if [ -z "$HOST" ]; then FAILURE="Syntax error" return 1 fi for OCTET in 1 2 3 4; do OCTET=`echo "$HOST." | cut -d. -f$OCTET --output-delimiter=" "` if [ -z "$OCTET" ] || (( `echo "$OCTET" | grep -c "[^[:digit:]]"` )) || [ "$OCTET" -lt "0" ] || [ "$OCTET" -gt "255" ]; then FAILURE="Network addresses must be in dotted decimal format" return 1 fi done if (( `echo "$HOST." | cut -d. -f5 | grep -c "."` )); then FAILURE="Network address must be in dotted decimal format" return 1 fi if [ -n "$MASK" ]; then if (( `echo "$MASK" | grep -c "[^[:digit:]]"` )) || [ "$MASK" -lt "0" ] || [ "$MASK" -gt "32" ]; then FAILURE="Network mask must be between '/0' (0.0.0.0) and '/32' (255.255.255.255) inclusive" return 1 fi else if (( `echo "$NET" | grep -c "/"` )); then FAILURE="Mask expected but not found" return 1 fi fi } check_ports() { # Checks PORTS variable. FAILURE="" RANGE=`echo "$PORTS/" | cut -d/ -f1` PROTOCOL=`echo "$PORTS/" | cut -d/ -f2` if (( `echo "$PORTS/" | cut -d/ -f3 | grep -c "."` )); then FAILURE="Syntax error" return 1 fi if [ -z "$RANGE" ]; then FAILURE="Syntax error" return 1 fi if (( `echo "$RANGE" | grep -c "[^[:digit:]]"` )) || [ "$RANGE" -lt "1" ] || [ "$RANGE" -gt "65535" ]; then for PORT in `echo "$RANGE-" | cut -d- -f1,2 --output-delimiter=" "`; do if (( `echo "$PORT" | grep -c "[^[:digit:]]"` )) || [ "$PORT" -lt "1" ] || [ "$PORT" -gt "65535" ]; then FAILURE="Valid port numbers must be between 1 and 65535" return 1 fi done if (( `echo "$RANGE-" | cut -d- -f3 | grep -c "."` )); then FAILURE="Syntax error" return 1 fi fi if [ -n "$PROTOCOL" ]; then if ! ( [ "$PROTOCOL" == "tcp" ] || [ "$PROTOCOL" == "udp" ] ); then FAILURE="Invalid protocol" return 1 fi else if (( `echo "$PORTS" | grep -c "/"` )); then FAILURE="Protocol expected but not found" return 1 fi fi } xbits() { # Set XBITS to the number of network bits that two addresses NET and NET1 are the same. XBITS=0 for NUM in 1 2 3 4; do OCTET=`echo "$NET./" | cut -d/ -f1 | cut -d. -f$NUM` OCTET1=`echo "$NET1./" | cut -d/ -f1 | cut -d. -f$NUM` if [ "$OCTET" == "$OCTET1" ]; then XBITS=$((XBITS + 8)) continue fi for SUBTRACT in 128 64 32 16 8 4 2 1; do if [ "$((OCTET - SUBTRACT))" -ge "0" ] && [ "$((OCTET1 - SUBTRACT))" -ge "0" ]; then XBITS=$((XBITS + 1)) OCTET=$((OCTET - SUBTRACT)) OCTET1=$((OCTET1 - SUBTRACT)) elif [ "$((OCTET - SUBTRACT))" -lt "0" ] && [ "$((OCTET1 - SUBTRACT))" -lt "0" ]; then XBITS=$((XBITS + 1)) else return fi done done } # Save selected variable settings if we are going to back up our configuration. if [ "$1" == "save" ] || [ "$1" == "update" ]; then if (( `which iptables-save 2>&1 | grep -c "which: no iptables-save in"` )); then FAILURE="iptables-save not found; required for '$1' argument." exit_failure $1 fi if [ "$1" == "update" ]; then PERMIT=`echo $PERMIT $TRUSTED_NETWORKS $OPEN_PORTS` OPEN_PORTS="" fi ORIG_PERMIT="$PERMIT" ORIG_INTERNAL_INTERFACES="$INTERNAL_INTERFACES" ORIG_PORT_FORWARDS="$PORT_FORWARDS" ORIG_ALLOW_INBOUND="$ALLOW_INBOUND" ORIG_DENY_OUTBOUND="$DENY_OUTBOUND" ORIG_DYNAMIC_INTERFACES="$DYNAMIC_INTERFACES" ORIG_STATIC_INSIDE_OUTSIDE="$STATIC_INSIDE_OUTSIDE" fi # Add DMZ interfaces to list of internal interfaces. if [ -n "$DMZ_INTERFACES" ]; then INTERNAL_INTERFACES="$INTERNAL_INTERFACES $DMZ_INTERFACES" fi # Remove duplicate internal interfaces. if [ -n "$INTERNAL_INTERFACES" ]; then for INTERFACE in $INTERNAL_INTERFACES; do if !(( `echo "$MOD_INTERFACES" | grep -c "$INTERFACE"` )); then MOD_INTERFACES="$MOD_INTERFACES $INTERFACE" fi done INTERNAL_INTERFACES=`echo $MOD_INTERFACES` fi # Determine if we are a router. if [ -n "$INTERNAL_INTERFACES" ] || [ -n "$PORT_FORWARDS" ]; then IS_ROUTER="yes" fi # Sanity check PERMIT and BLACKLIST. for PARAM in PERMIT BLACKLIST; do if [ "$PARAM" == "PERMIT" ]; then ITEM="$PERMIT" else ITEM="$BLACKLIST" fi for NETWORK in $ITEM; do NET=`echo "$NETWORK:" | cut -d: -f1` PORTS=`echo "$NETWORK:" | cut -d: -f2` if (( `echo "$NETWORK:" | cut -d: -f3 | grep -c "."` )); then FAILURE="Syntax error in $PARAM." exit_failure $1 fi if ! check_network; then PORTS="$NET" FAIL="$FAILURE in $PARAM." if ! check_ports; then FAILURE="$FAIL" exit_failure $1 fi fi if [ -n "$PORTS" ]; then if ! check_ports; then FAILURE="$FAILURE in $PARAM." exit_failure $1 fi fi done done echo -n "." # Remove entries with ports and put them in their own variable. if [ -n "$PERMIT" ]; then for NETWORK in $PERMIT; do NET=`echo "$NETWORK:" | cut -d: -f1` PORTS=`echo "$NETWORK:" | cut -d: -f2` if [ -z "$PORTS" ]; then if ! check_network; then OPEN_PORTS="$OPEN_PORTS $NET" else TEMP_PERMIT="$TEMP_PERMIT $NET" fi else PROTOCOL=`echo "$PORTS/" | cut -d/ -f2` if [ "$PROTOCOL" == "tcp" ] || [ "$PROTOCOL" == "udp" ]; then TRUSTED_PORTS="$TRUSTED_PORTS $NET:$PORTS/$PROTOCOL" else TRUSTED_PORTS="$TRUSTED_PORTS $NET:$PORTS/tcp" TRUSTED_PORTS="$TRUSTED_PORTS $NET:$PORTS/udp" fi fi done PERMIT=`echo $TEMP_PERMIT` TRUSTED_PORTS=`echo $TRUSTED_PORTS` OPEN_PORTS=`echo $OPEN_PORTS` fi # Sanity check additional routed networks. if [ -n "$INTERNAL_INTERFACES" ]; then for NET in $ADDITIONAL_ROUTED_NETWORKS; do if ! check_network; then FAILURE="$FAILURE in ADDITIONAL_ROUTED_NETWORKS." exit_failure $1 fi done fi # Sanity check port forwarding definitions. Protocol and destination ports are optional. if [ -n "$PORT_FORWARDS" ]; then for FORWARD in $PORT_FORWARDS; do if (( `echo "$FORWARD:" | cut -d: -f5 | grep -c "."` )); then FAILURE="Syntax error in PORT_FORWARDS." exit_failure $1 fi PROTOCOL=`echo "$FORWARD:" | cut -d: -f1` if [ "$PROTOCOL" != "tcp" ] && [ "$PROTOCOL" != "udp" ]; then COUNT="1" MOD_FORWARDS="$MOD_FORWARDS tcp:$FORWARD udp:$FORWARD" PROT="" else COUNT="0" MOD_FORWARDS="$MOD_FORWARDS $FORWARD" PROT="/$PROTOCOL" fi PORTS=`echo "$FORWARD:" | cut -d: -f$((2-COUNT))` FAILURE="Invalid syntax " if ! check_ports || [ -n "$PROTOCOL" ]; then FAILURE="$FAILURE in PORT_FORWARDS." exit_failure $1 fi if [ "$PORT_FWD_ALL" == "yes" ]; then for TAB in NULL; do for PORT in $OPEN_PORTS; do if [ "$PORT" == "${PORTS}$PROT" ]; then break 2 fi done OPEN_PORTS="$OPEN_PORTS ${PORTS}$PROT" done fi NET=`echo "$FORWARD:" | cut -d: -f$((3-COUNT))` FAILURE="Destination must be a single host" if ! check_network || [ -n "$MASK" ]; then FAILURE="$FAILURE in PORT_FORWARDS." exit_failure $1 fi PORTS=`echo "$FORWARD:" | cut -d: -f$((4-COUNT))` if [ -n "$PORTS" ]; then FAILURE="Invalid syntax" if ! check_ports || [ -n "$PROTOCOL" ]; then FAILURE="$FAILURE in PORT_FORWARDS." exit_failure $1 fi fi done PORT_FORWARDS=`echo $MOD_FORWARDS` OPEN_PORTS=`echo $OPEN_PORTS` fi # Sanity check open ports. Expand undefined protocols into tcp and udp. if [ -n "$OPEN_PORTS" ]; then for PORTS in $OPEN_PORTS; do if ! check_ports; then FAILURE="$FAILURE in OPEN_PORTS." exit_failure $1 fi if [ "$PROTOCOL" == "tcp" ] || [ "$PROTOCOL" == "udp" ]; then MOD_PORTS="$MOD_PORTS $PORTS" else MOD_PORTS="$MOD_PORTS $PORTS/tcp $PORTS/udp" fi done OPEN_PORTS=`echo $MOD_PORTS` fi # Sanity check static inside,outside translations. if [ -n "$STATIC_INSIDE_OUTSIDE" ]; then MOD_STATIC="" for FORWARD in $STATIC_INSIDE_OUTSIDE; do if (( `echo "$FORWARD:" | cut -d: -f3 | grep -c "."` )); then FAILURE="Syntax error in STATIC_INSIDE_OUTSIDE." exit_failure $1 fi NET=`echo "$FORWARD:" | cut -d: -f1` if ! check_network; then FAILURE="$FAILURE in STATIC_INSIDE_OUTSIDE." exit_failure $1 fi NET1=`echo $NET | cut -d\/ -f1` STROKE="$MASK" NET=`echo "$FORWARD:" | cut -d: -f2` if ! check_network; then FAILURE="$FAILURE in STATIC_INSIDE_OUTSIDE." exit_failure $1 fi if [ -n "$MASK" ]; then if [ "$STROKE" != "$MASK" ]; then FAILURE="If outside address in STATIC_INSIDE_OUTSIDE has a netmask, it must be the same as the inside address." exit_failure $1 fi if [ "$MASK" -lt "24" ]; then FAILURE="Networks larger than class C (254 hosts) are not supported on the OUTSIDE address of STATIC_INSIDE_OUTSIDE." exit_failure $1 fi TAB="1" NET=`echo $NET | cut -d\/ -f1` COUNT=`echo $NET | cut -d. -f4` if [ "$COUNT" -ne "`echo $NET1 | cut -d. -f4`" ]; then FAILURE="When using a subnet mask on the OUTSIDE address in STATIC_INSIDE_OUTSIDE, last octet of both inside and outside addresses must be the same." exit_failure $1 fi NET1=`echo $NET1 | cut -d. -f1,2,3` NET=`echo $NET | cut -d. -f1,2,3` while [ "$MASK" -lt "32" ]; do TAB=$((TAB * 2)) MASK=$((MASK+1)) done STROKE="$TAB" while [ "$TAB" -gt "0" ]; do TAB=$((TAB-1)) OCTET=$((COUNT-(COUNT%STROKE)+TAB)) if [ "$OCTET" != "0" ] && [ "$OCTET" != "255" ]; then MOD_STATIC="$MOD_STATIC $NET1.$OCTET:$NET.$OCTET" fi done else MOD_STATIC="$MOD_STATIC $FORWARD" fi done STATIC_INSIDE_OUTSIDE=`echo $MOD_STATIC` fi # Sanity check FIREWALL_IP. for ADDRESS in $FIREWALL_IP; do if (( `echo "$ADDRESS:" | cut -d: -f3 | grep -c "."` )); then FAILURE="Syntax error in FIREWALL_IP." exit_failure $1 fi NET=`echo "$ADDRESS:" | cut -d: -f1` if ! check_network; then FAILURE="$FAILURE in FIREWALL_IP." exit_failure $1 fi if [ -n "$MASK" ]; then FAILURE="FIREWALL_IP may not contain network masks." exit_failure $1 fi NET=`echo "$ADDRESS:" | cut -d: -f2` if ! check_network; then FAILURE="$FAILURE in FIREWALL_IP." exit_failure $1 fi if [ -n "$MASK" ]; then FAILURE="FIREWALL_IP may not contain network masks." exit_failure $1 fi done # Make sure dynamic, nat, and rp_filter interface definitions do not use IP aliases. if (( `echo "$INTERNAL_INTERFACES $DYNAMIC_INTERFACES $NO_RP_FILTER_INTERFACES $ADDITIONAL_NAT_INTERFACES" | grep -c ":"` )); then FAILURE="Definitions cannot contain IP aliases." exit_failure $1 fi # Obtain list of external interfaces. EXTERNAL_INTERFACES=`ifconfig | grep "^[[:alpha:]]" | cut -d\ -f1 | sed s/^lo.*//` PARAM=`echo $EXTERNAL_INTERFACES` for INTERFACE in $INTERNAL_INTERFACES; do EXTERNAL_INTERFACES=`echo "$EXTERNAL_INTERFACES" | sed s/^$INTERFACE//` done for INTERFACE in $PARAM; do if !(( `echo "$EXTERNAL_INTERFACES $INTERNAL_INTERFACES" | grep -c "$INTERFACE"` )); then INTERNAL_INTERFACES="$INTERNAL_INTERFACES $INTERFACE" fi done EXTERNAL_INTERFACES=`echo $EXTERNAL_INTERFACES | sed 's/[^0-9]\:[0-9]\+//g'` # Cleanup. for INTERFACE in $IGNORE_INTERFACES; do if !(( `echo "$EXTERNAL_INTERFACES" | grep -c "$INTERFACE"` )); then FAILURE="Interface specified to IGNORE was not found. Check the configuration." exit_failure $1 else EXTERNAL_INTERFACES=`echo $EXTERNAL_INTERFACES | sed s#$INTERFACE##g` fi done EXTERNAL_INTERFACES=`echo $EXTERNAL_INTERFACES` # Remove whitespace. echo -n "." # Divide internal and external interfaces into static and dynamic groups. for INTERFACE in $INTERNAL_INTERFACES; do if (( `echo "$DYNAMIC_INTERFACES" | grep -c "$INTERFACE"` )); then if [ -n "$DMZ_INTERFACES" ]; then FAILURE="Cannot have dynamic internal interfaces with a DMZ." exit_failure $1 fi DYNAMIC_INTERNAL_INTERFACES="$DYNAMIC_INTERNAL_INTERFACES $INTERFACE" else STATIC_INTERNAL_INTERFACES="$STATIC_INTERNAL_INTERFACES $INTERFACE" fi done for INTERFACE in $EXTERNAL_INTERFACES; do if (( `echo "$DYNAMIC_INTERFACES" | grep -c "$(echo $INTERFACE | cut -d: -f1)"` )); then if !(( `echo "$INTERFACE" | grep -c ":"` )); then DYNAMIC_EXTERNAL_INTERFACES="$DYNAMIC_EXTERNAL_INTERFACES $INTERFACE" fi else STATIC_EXTERNAL_INTERFACES="$STATIC_EXTERNAL_INTERFACES $INTERFACE" fi done for INTERFACE in $DYNAMIC_INTERFACES; do if !(( `echo "$INTERNAL_INTERFACES $EXTERNAL_INTERFACES" | grep -c "$INTERFACE"` )); then DYNAMIC_EXTERNAL_INTERFACES="$DYNAMIC_EXTERNAL_INTERFACES $INTERFACE" fi done DYNAMIC_INTERNAL_INTERFACES=`echo $DYNAMIC_INTERNAL_INTERFACES` DYNAMIC_EXTERNAL_INTERFACES=`echo $DYNAMIC_EXTERNAL_INTERFACES` STATIC_INTERNAL_INTERFACES=`echo $STATIC_INTERNAL_INTERFACES` STATIC_EXTERNAL_INTERFACES=`echo $STATIC_EXTERNAL_INTERFACES` # If we are configured to be a router, then make sure we have somewhere to route traffic. if [ -n "$INTERNAL_INTERFACES" ] && ( [ -z "$STATIC_EXTERNAL_INTERFACES" ] && [ -z "$DYNAMIC_EXTERNAL_INTERFACES" ] ); then if (( `echo "$INTERNAL_INTERFACES" | wc -w | grep -c "1"` )); then FAILURE="Routing enabled, with no place to route traffic! Did you forget to ifconfig an interface, or list DYNAMIC_INTERFACES?" exit_failure $1 fi fi # Obtain list of interfaces to NAT outbound connections if [ "$IS_ROUTER" == "yes" ]; then if [ "$NAT_EXTERNAL" == "yes" ]; then for INTERFACE in $STATIC_EXTERNAL_INTERFACES; do if !(( `echo "$INTERFACE" | grep -c ":"` )); then STATIC_NAT_INTERFACES="$STATIC_NAT_INTERFACES $INTERFACE" fi done for INTERFACE in $DYNAMIC_EXTERNAL_INTERFACES; do if !(( `echo "$INTERFACE" | grep -c ":"` )); then DYNAMIC_NAT_INTERFACES="$DYNAMIC_NAT_INTERFACES $INTERFACE" fi done fi for INTERFACE in $ADDITIONAL_NAT_INTERFACES; do if (( `echo "$DYNAMIC_INTERFACES" | grep -c "$INTERFACE"` )); then DYNAMIC_NAT_INTERFACES="$DYNAMIC_NAT_INTERFACES $INTERFACE" else STATIC_NAT_INTERFACES="$STATIC_NAT_INTERFACES $INTERFACE" fi done fi # If we are a router, check that all static internal interfaces are up. for INTERFACE in $STATIC_INTERNAL_INTERFACES; do if !(( `ifconfig | grep -c "^$INTERFACE\ "` )); then FAILURE="A static internal interface is down. Did you forgot to configure interfaces before running the firewall?" exit_failure $1 fi done # Obtain list of NAT addresses if we are a router doing nat. if [ -n "$STATIC_NAT_INTERFACES" ]; then for INTERFACE in $STATIC_NAT_INTERFACES; do ADDRESS=`ifconfig | grep "^$INTERFACE\ " -A1 | grep "inet" | cut -d: -f2 | cut -d\ -f1 | head -1` if [ -z "$ADDRESS" ]; then echo " [ WAIT ]" echo -n "-> $INTERFACE has no IP address. Waiting for DHCP" for COUNT in 1 2 3 4 5 6 7 8 9 10; do sleep 1 echo -n "." ADDRESS=`ifconfig | grep "^$INTERFACE\ " -A1 | grep "inet" | cut -d: -f2 | cut -d\ -f1 | head -1` if [ -n "$ADDRESS" ]; then echo " [ FOUND ]" break else if [ "$COUNT" == "10" ]; then echo " [ MISSING ]" echo "-> WARNING: IP address for $INTERFACE not found. Coverting to dynamic interface." DYNAMIC_EXTERNAL_INTERFACES="$DYNAMIC_EXTERNAL_INTERFACES $INTERFACE" DYNAMIC_INTERFACES="$DYNAMIC_INTERFACES $INTERFACE" if [ "$NAT_EXTERNAL" == "yes" ]; then DYNAMIC_NAT_INTERFACES="$DYNAMIC_NAT_INTERFACES $INTERFACE" fi for INT in $STATIC_EXTERNAL_INTERFACES; do if [ "$INTERFACE" != "$INT" ]; then MOD_STATIC_EXTERNAL_INTERFACES="$MOD_STATIC_EXTERNAL_INTERFACES $INTERFACE" fi done STATIC_EXTERNAL_INTERFACES=`echo $MOD_STATIC_EXTERNAL_INTERFACES` fi fi done echo -n "-> Continuing sanity checks.." else MOD_STATIC_NAT_INTERFACES="$MOD_STATIC_NAT_INTERFACES $INTERFACE" if [ -n "$FIREWALL_IP" ]; then for FORWARD in $FIREWALL_IP; do if [ `echo "$FORWARD" | cut -d: -f1` == "$ADDRESS" ]; then ADDRESS=`echo "$FORWARD" | cut -d: -f2` fi done fi NAT_ADDRESSES="$NAT_ADDRESSES $ADDRESS" fi done STATIC_NAT_INTERFACES=`echo $MOD_STATIC_NAT_INTERFACES` NAT_ADDRESSES=`echo $NAT_ADDRESSES` fi echo -n "." # Determine if this is a modular kernel, if so modprobe the required modules. if !(( `which modprobe 2>&1 | grep -c "which: no modprobe in"` )) && [ -a "/proc/modules" ]; then if (( `lsmod | grep -c "ipchains"` )); then rmmod ipchains > /dev/null 2>&1 fi REQUIRED_MODULES="ip_tables ip_conntrack ipt_state iptable_filter ip_conntrack_irc ip_conntrack_ftp" if [ "$RFC_1122_COMPLIANT" == "yes" ]; then REQUIRED_MODULES="$REQUIRED_MODULES ipt_REJECT" fi if [ "$LOGGING" == "yes" ]; then REQUIRED_MODULES="$REQUIRED_MODULES ipt_LOG ipt_limit" fi if [ "$IS_ROUTER" == "yes" ]; then if [ -n "$STATIC_NAT_INTERFACES" ] || [ -n "$DYNAMIC_NAT_INTERFACES" ] || \ [ -n "$PORT_FORWARDS" ] || [ -n "$STATIC_INSIDE_OUTSIDE" ]; then REQUIRED_MODULES="$REQUIRED_MODULES iptable_nat ip_nat_irc ip_nat_ftp" if [ -n "$DYNAMIC_NAT_INTERFACES" ] || \ ( [ -n "$DYNAMIC_INTERFACES" ] && ( [ -n "$PORT_FORWARDS" ] || [ -n "$STATIC_INSIDE_OUTSIDE" ] ) ); then REQUIRED_MODULES="$REQUIRED_MODULES ipt_MASQUERADE" fi fi if [ -n "$PORT_FORWARDS" ] || [ "$TTL_STEALTH_ROUTER" == "yes" ]; then REQUIRED_MODULES="$REQUIRED_MODULES iptable_mangle" fi if [ -n "$PORT_FORWARDS" ]; then REQUIRED_MODULES="$REQUIRED_MODULES ipt_mark ipt_MARK" fi if [ "$TTL_STEALTH_ROUTER" == "yes" ]; then REQUIRED_MODULES="$REQUIRED_MODULES ipt_TTL" fi fi for MODULE in $REQUIRED_MODULES; do if (( `modprobe -l | grep -c "$MODULE"` )); then modprobe $MODULE > /dev/null 2>&1 fi done fi # Obtain list of internal networks with subnet masks corresponding to internal interfaces. if [ -n "$STATIC_INTERNAL_INTERFACES" ]; then for INTERFACE in $STATIC_INTERNAL_INTERFACES; do STROKE="0" MASK=`ifconfig | grep "^$INTERFACE\ " -A1 | grep "Mask" | cut -d: -f4 | head -1` for OCTET in 1 2 3 4; do BINARY=`echo "$MASK" | cut -d. -f$OCTET` for SUBTRACT in 128 64 32 16 8 4 2 1; do if [ "$((BINARY - SUBTRACT))" -ge "0" ]; then BINARY=$((BINARY - SUBTRACT)) STROKE=$((STROKE + 1)) fi done done ADDRESS=`ifconfig | grep "^$INTERFACE\ " -A1 | grep "inet" | cut -d: -f2 | cut -d\ -f1 | head -1` INTERNAL_ADDRESSES="$INTERNAL_ADDRESSES $ADDRESS" INTERNAL_NETWORKS="$INTERNAL_NETWORKS $ADDRESS/$STROKE" if [ -z "$DMZ_INTERFACES" ] || !(( `echo "$DMZ_INTERFACES" | grep -c "$INTERFACE"` )); then NAT_NETWORKS="$NAT_NETWORKS $ADDRESS/$STROKE" fi done INTERNAL_ADDRESSES=`echo $INTERNAL_ADDRESSES` INTERNAL_NETWORKS=`echo $INTERNAL_NETWORKS` NAT_NETWORKS=`echo $NAT_NETWORKS` fi # Obtain a list of external addresses. if [ -n "$STATIC_EXTERNAL_INTERFACES" ]; then for INTERFACE in $STATIC_EXTERNAL_INTERFACES; do STROKE="0" MASK=`ifconfig | grep "^$INTERFACE\ " -A1 | grep "Mask" | cut -d: -f4 | head -1` for OCTET in 1 2 3 4; do BINARY=`echo "$MASK" | cut -d. -f$OCTET` for SUBTRACT in 128 64 32 16 8 4 2 1; do if [ "$((BINARY - SUBTRACT))" -ge "0" ]; then BINARY=$((BINARY - SUBTRACT)) STROKE=$((STROKE + 1)) fi done done ADDRESS=`ifconfig | grep "^$INTERFACE\ " -A1 | grep "inet" | cut -d: -f2 | cut -d\ -f1 | head -1` EXTERNAL_ADDRESSES="$EXTERNAL_ADDRESSES $ADDRESS" EXTERNAL_NETWORKS="$EXTERNAL_NETWORKS $ADDRESS/$STROKE" done EXTERNAL_ADDRESSES=`echo $EXTERNAL_ADDRESSES` EXTERNAL_NETWORKS=`echo $EXTERNAL_NETWORKS` fi # Make a table of interfaces for marking packets based on their incoming interface for port forwarding. if [ -n "$PORT_FORWARDS" ]; then COUNT="0" TAB="1" for INTERFACE in $STATIC_INTERNAL_INTERFACES $STATIC_EXTERNAL_INTERFACES; do COUNT=$((COUNT + 1)) ADDRESS=`echo $INTERNAL_ADDRESSES $EXTERNAL_ADDRESSES | cut -d\ -f$COUNT` # Do not forward packets destined for an address in STATIC_INSIDE_OUTSIDE. if !(( `echo "$STATIC_INSIDE_OUTSIDE" | awk '{ gsub(/\ /,"\n"); print }' | \ cut -d: -f2 | grep -c "$ADDRESS"` )); then if [ -n "$FIREWALL_IP" ]; then # Nobody will ever use the address of the private network between us and our gateway for port forwarding. if (( `echo "$FIREWALL_IP" | awk '{ gsub(/\ /,"\n"); print }' | \ cut -d: -f2 | grep -c "$ADDRESS"` )); then continue fi if (( `echo "$FIREWALL_IP" | awk '{ gsub(/\ /,"\n"); print }' | \ cut -d: -f1 | grep -c "$ADDRESS"` )); then ADDRESS=`echo "$FIREWALL_IP" | awk '{ gsub(/\ /,"\n"); print }' | \ grep "$ADDRESS" | cut -d: -f2` fi fi INTERFACE=`echo "$INTERFACE" | cut -d: -f1` INTERFACE_TAB[$TAB]="$INTERFACE" ADDRESS_TAB[$TAB]="$ADDRESS" PORT_FORWARD_ADDRESSES="$PORT_FORWARD_ADDRESSES $ADDRESS" if [ "$PORT_FWD_ROUTED_NETWORKS" == "yes" ]; then if (( `echo "$STATIC_INTERNAL_INTERFACES" | grep -c "$INTERFACE"` )); then NETWORK_TAB[$TAB]="$ADDITIONAL_ROUTED_NETWORKS `echo "$INTERNAL_NETWORKS" | cut -d\ -f$COUNT`" fi fi TAB=$((TAB + 1)) fi done for INTERFACE in $DYNAMIC_INTERNAL_INTERFACES $DYNAMIC_EXTERNAL_INTERFACES; do INTERFACE_TAB[$TAB]="$INTERFACE" TAB=$((TAB + 1)) done PORT_FORWARD_ADDRESSES=`echo $PORT_FORWARD_ADDRESSES` fi # Obtain broadcast list if we are doing logging (so that we will not log them). # We have to do this before we hax0r STATIC_INTERNAL_INTERFACES. if [ "$LOGGING" == "yes" ]; then BCAST_LIST="255.255.255.255" for INTERFACE in $STATIC_INTERNAL_INTERFACES $STATIC_EXTERNAL_INTERFACES; do BROADCAST=`ifconfig | grep "^$INTERFACE\ " -A1 | grep "Bcast" | cut -d: -f3 | cut -d\ -f1 | head -1` if !(( `echo "$BCAST_LIST" | grep -c "$BROADCAST"` )); then BCAST_LIST="$BCAST_LIST $BROADCAST" fi done fi # Remove redundant networks from INTERNAL_INTERFACES, STATIC_INTERNAL_INTERFACES, and INTERNAL_NETWORKS. if [ -n "$INTERNAL_NETWORKS" ]; then CHANGE=1 until [ "$CHANGE" == "0" ]; do COUNT=0 CHANGE=0 for NET in $INTERNAL_NETWORKS; do TAB=0 COUNT=$((COUNT + 1)) INTERFACE=`echo "$STATIC_INTERNAL_INTERFACES" | cut -d\ -f$COUNT` STROKE=`echo "$NET" | cut -d/ -f2` for NET1 in $INTERNAL_NETWORKS; do TAB=$((TAB + 1)) INTERFACE1=`echo "$STATIC_INTERNAL_INTERFACES" | cut -d\ -f$TAB` if [ "$INTERFACE" == "$INTERFACE1" ]; then continue # Obviously we don't want to compare a network to itself. fi PARAM=`echo "$INTERFACE1" | cut -d: -f1` if !(( `echo "$INTERFACE" | cut -d: -f1 | grep -c "$PARAM"` )); then continue # We only want to compare networks attached to the same interface. fi MASK=`echo "$NET1/" | cut -d/ -f2` xbits if [ "$STROKE" -le "$MASK" ]; then # Then NET defines a larger network than NET1. if [ "$XBITS" -ge "$STROKE" ]; then # Then delete the second one if they are the same up to STROKE. INTERNAL_NETWORKS=`echo "$INTERNAL_NETWORKS" | sed s#$NET1##` INTERNAL_NETWORKS=`echo $INTERNAL_NETWORKS` STATIC_INTERNAL_INTERFACES=`echo "$STATIC_INTERNAL_INTERFACES" | sed s#$INTERFACE1##` STATIC_INTERNAL_INTERFACES=`echo $STATIC_INTERNAL_INTERFACES` if [ -z "$DMZ_INTERFACES" ] || !(( `echo "$DMZ_INTERFACES" | grep -c "$PARAM"` )); then NAT_NETWORKS=`echo "$NAT_NETWORKS" | sed s#$NET1##` NAT_NETWORKS=`echo $NAT_NETWORKS` fi CHANGE=1 continue 3 fi elif [ "$XBITS" -ge "$MASK" ]; then # Else delete the first one (provided it is still the same interface). INTERNAL_NETWORKS=`echo "$INTERNAL_NETWORKS" | sed s#$NET##` INTERNAL_NETWORKS=`echo $INTERNAL_NETWORKS` STATIC_INTERNAL_INTERFACES=`echo "$STATIC_INTERNAL_INTERFACES" | sed s#$INTERFACE##` STATIC_INTERNAL_INTERFACES=`echo $STATIC_INTERNAL_INTERFACES` if [ -z "$DMZ_INTERFACES" ] || !(( `echo "$DMZ_INTERFACES" | grep -c "$PARAM"` )); then NAT_NETWORKS=`echo "$NAT_NETWORKS" | sed s#$NET##` NAT_NETWORKS=`echo $NAT_NETWORKS` fi CHANGE=1 continue 3 fi done done done fi echo -n "." # Sanity check ALLOW_INBOUND and DENY_OUTBOUND and compare against INTERNAL_NETWORKS. if [ -n "$ALLOW_INBOUND" ] || [ -n "$DENY_OUTBOUND" ]; then for PARAM in DENY_OUTBOUND ALLOW_INBOUND; do if [ "$PARAM" == "DENY_OUTBOUND" ]; then LIST="$DENY_OUTBOUND" else LIST="$ALLOW_INBOUND" fi for FORWARD in $LIST; do for TEMP in NULL; do # You'll see why. if (( `echo "$FORWARD:" | cut -d: -f4 | grep -c "."` )); then FAILURE="Too many parameters in $PARAM." exit_failure $1 fi NET=`echo "$FORWARD:" | cut -d: -f1` if [ -n "$NET" ] && ! check_network; then PORTS="$NET" if ! check_ports; then FAILURE="Syntax error in $PARAM." exit_failure $1 else eval TEMP_$PARAM="any:any:$PORTS" break fi elif [ -z "$NET" ]; then NET="any" else if [ "$PARAM" == "DENY_OUTBOUND" ]; then STROKE=`echo "$NET/" | cut -d/ -f2` if [ -z "$STROKE" ]; then STROKE=32 fi for TAB in NULL; do for NET1 in $INTERNAL_NETWORKS $ADDITIONAL_ROUTED_NETWORKS; do MASK=`echo "$NET1/" | cut -d/ -f2` if [ -z "$MASK" ]; then MASK=32 fi xbits # Is this host/network from one of our internal networks? if [ "$STROKE" -lt "$MASK" ]; then continue # Can't tell elif [ "$XBITS" -ge "$MASK" ]; then break 2 # Yes! fi # Can't tell done FAILURE="Source host from DENY_OUTBOUND not found in an internal network." exit_failure $1 done fi fi NET2="$NET" NET=`echo "$FORWARD:" | cut -d: -f2` if [ -n "$NET" ] && ! check_network; then PORTS="$NET" if ! check_ports; then FAILURE="Syntax error in $PARAM." exit_failure $1 else eval TEMP_$PARAM="$NET2:any:$PORTS" break fi elif [ -z "$NET" ]; then eval TEMP_$PARAM="$NET2:any:any" break fi if [ "$PARAM" == "ALLOW_INBOUND" ]; then STROKE=`echo "$NET/" | cut -d/ -f2` if [ -z "$STROKE" ]; then STROKE=32 fi for TAB in NULL; do for NET1 in $INTERNAL_NETWORKS $ADDITIONAL_ROUTED_NETWORKS; do MASK=`echo "$NET1/" | cut -d/ -f2` if [ -z "$MASK" ]; then MASK=32 fi xbits # Is this host/network from one of our internal networks? if [ "$STROKE" -lt "$MASK" ]; then continue # Can't tell on this network elif [ "$XBITS" -ge "$MASK" ]; then break 2 # Yes! fi # Can't tell done FAILURE="Destination host in ALLOW_INBOUND not found in an internal network." exit_failure $1 done fi PORTS=`echo "$FORWARD:" | cut -d: -f3` if [ -z "$PORTS" ]; then eval TEMP_$PARAM="$NET2:$NET:any" break else if ! check_ports; then FAILURE="$FAILURE in $PARAM." exit_failure $1 else eval TEMP_$PARAM="$NET2:$NET:$PORTS" break fi fi done if [ "$PARAM" == "ALLOW_INBOUND" ]; then MOD_ALLOW_INBOUND="$MOD_ALLOW_INBOUND $TEMP_ALLOW_INBOUND" else MOD_DENY_OUTBOUND="$MOD_DENY_OUTBOUND $TEMP_DENY_OUTBOUND" fi done done ALLOW_INBOUND=`echo $MOD_ALLOW_INBOUND` DENY_OUTBOUND=`echo $MOD_DENY_OUTBOUND` fi # Remove duplicate external addresses, for example those created when using channel bonding. if [ -n "$EXTERNAL_ADDRESSES" ]; then MOD_ADDRESSES="" for ADDRESS in $EXTERNAL_ADDRESSES; do if !(( `echo "$MOD_ADDRESSES" | grep -c "$ADDRESS"` )); then MOD_ADDRESSES="$MOD_ADDRESSES $ADDRESS" fi done EXTERNAL_ADDRESSES=`echo $MOD_ADDRESSES` fi # Make sure we own the addresses that we are staticly mapping through the firewall, and verify internal hosts are actually from internal networks. if [ -n "$STATIC_INSIDE_OUTSIDE" ]; then for FORWARD in $STATIC_INSIDE_OUTSIDE; do NET1=`echo "$FORWARD:" | cut -d: -f1` OUTSIDE=`echo "$FORWARD:" | cut -d: -f2` for TAB in NULL; do for ADDRESS in $EXTERNAL_ADDRESSES $INTERNAL_ADDRESSES; do if [ "$ADDRESS" == "$OUTSIDE" ]; then break 2 fi done FAILURE="Could not find an interface with address given in STATIC_INSIDE_OUTSIDE." exit_failure $1 done STROKE=`echo "$NET1/" | cut -d/ -f2` if [ -z "$STROKE" ]; then STROKE=32 fi for TAB in NULL; do for NET in $INTERNAL_NETWORKS $ADDITIONAL_ROUTED_NETWORKS; do MASK=`echo "$NET/" | cut -d/ -f2` if [ -z "$MASK" ]; then MASK=32 fi xbits # Is this host/network from one of our internal networks? if [ "$STROKE" -lt "$MASK" ]; then continue # Can't tell elif [ "$XBITS" -ge "$MASK" ]; then break 2 # Yes! fi # Can't tell done FAILURE="Internal host from STATIC_INSIDE_OUTSIDE not found in an internal network." exit_failure $1 done done fi # For FIREWALL_IP, make sure that our source address is on an external interface and our destination address is on an internal interface. for ADDRESS in $FIREWALL_IP; do OUTSIDE=`echo "$ADDRESS:" | cut -d: -f1` INSIDE=`echo "$ADDRESS:" | cut -d: -f2` for TAB in NULL; do for ADDRESS in $EXTERNAL_ADDRESSES; do if [ "$ADDRESS" == "$OUTSIDE" ]; then break 2 fi done FAILURE="Source address given in FIREWALL_IP must be configured on an *external* interface." exit_failure $1 done for TAB in NULL; do for ADDRESS in $INTERNAL_ADDRESSES; do if [ "$ADDRESS" == "$INSIDE" ]; then break 2 fi done FAILURE="Destination address given in FIREWALL_IP must be configured on an *internal* interface." exit_failure $1 done done # If we do not trust routed networks then add internal interfaces as "secured" addresses in the exit message. if [ -n "$STATIC_INTERNAL_INTERFACES" ] && [ "$TRUST_ROUTED_NETWORKS" != "yes" ]; then EXTERNAL_ADDRESSES="$EXTERNAL_ADDRESSES $INTERNAL_ADDRESSES" fi echo -n "." # Check that rp_filter interfaces are valid. for INTERFACE in $NO_RP_FILTER_INTERFACES; do if ! [ -w "/proc/sys/net/ipv4/conf/$INTERFACE/rp_filter" ]; then FAILURE="Cannot write to /proc/sys/net/ipv4/conf/$INTERFACE/rp_filter. Is the interface definition valid?" exit_failure $1 fi done # Check for Local Loopback interface. if !(( `ifconfig | grep -A1 "^lo" | grep "127\." | grep -c "255\.0\.0\.0"` )); then FAILURE="Local Loopback interface (lo) required but not found." exit_failure $1 fi # Make sure the filter table exists. if (( `iptables -t filter -nL 2>&1 | grep -c "Table does not exist"` )) || (( `iptables -t filter -nL 2>&1 | grep -c "can't initialize iptables table"` )); then FAILURE="Could not find 'filter' table. Did you compile support for all necessary modules?" exit_failure $1 fi # Check for the REJECT target if RFC 1122 compliance is enabled. if [ "$RFC_1122_COMPLIANT" == "yes" ]; then if ((`iptables -t filter -i lo -o lo -I FORWARD -j REJECT 2>&1 | grep -c "No chain/target/match by that name"`)); then FAILURE="Could not find 'REJECT' target. Did you compile support for all necessary modules?" exit_failure $1 else iptables -t filter -D FORWARD 1 fi fi # If logging is enabled check for LOG and limit targets. if [ "$LOGGING" == "yes" ]; then if (( `iptables -t filter -i lo -o lo -I FORWARD -m limit 2>&1 | \ grep -c "No chain/target/match by that name"` )); then FAILURE="Could not find 'limit' target. Did you compile support for all necessary modules?" exit_failure $1 else iptables -t filter -D FORWARD 1 fi if (( `iptables -t filter -i lo -o lo -I FORWARD -j LOG 2>&1 | grep -c "No chain/target/match by that name"` )); then FAILURE="Could not find 'LOG' target. Did you compile support for all necessary modules?" exit_failure $1 else iptables -t filter -D FORWARD 1 fi fi # Check for the nat table if we need it. if [ -n "$STATIC_NAT_INTERFACES" ] || [ -n "$DYNAMIC_NAT_INTERFACES" ] || [ -n "$PORT_FORWARDS" ]; then if (( `iptables -t nat -nL 2>&1 | grep -c "Table does not exist"` )) || (( `iptables -t nat -nL 2>&1 | grep -c "can't initialize iptables table"` )); then FAILURE="Could not find 'nat' table. Did you compile support for all necessary modules?" exit_failure $1 fi fi # Determine if we need the MASQUERADE target. if [ -n "$DYNAMIC_NAT_INTERFACES" ] || ( [ -n "$DYNAMIC_INTERFACES" ] && [ -n "$PORT_FORWARDS" ] ); then if ((`iptables -t nat -I POSTROUTING -o lo -j MASQUERADE 2>&1 | grep -c "No chain/target/match by that name"`)); then FAILURE="Could not find 'MASQUERADE' target. Did you compile support for all necessary modules?" exit_failure $1 else iptables -t nat -D POSTROUTING 1 fi fi # Check for state match module. if (( `iptables -t filter -I OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 2>&1 | \ grep -c "No chain/target/match by that name"` )); then FAILURE="Failed to load state match module. Did you compile support for all necessary modules?" exit_failure $1 else iptables -t filter -D OUTPUT 1 fi # Check for various port forwarding and ttl_stealth_router requirements. if [ -n "$PORT_FORWARDS" ] || [ "$TTL_STEALTH_ROUTER" == "yes" ]; then if (( `iptables -t mangle -nL 2>&1 | grep -c "Table does not exist"` )) || (( `iptables -t mangle -nL 2>&1 | grep -c "can't initialize iptables table"` )); then FAILURE="Could not find 'mangle' table, required for port forwarding and TTL stealth router mode. Did you compile support for all necessary modules?" exit_failure $1 fi if [ -n "$PORT_FORWARDS" ]; then if (( `iptables -t mangle -I OUTPUT -j MARK --set-mark "1" 2>&1 | grep -c "No chain/target/match by that name"` )); then FAILURE="Failed to load MARK target, required for port forwarding. Did you compile support for all necessary modules?" exit_failure $1 else iptables -t mangle -D OUTPUT 1 fi if (( `iptables -t mangle -I OUTPUT -m mark --mark "1" -j ACCEPT 2>&1 | grep -c "No chain/target/match by that name"` )); then FAILURE="Failed to netfilter MARK match module, required for port forwarding. Did you compile support for all necessary modules?" exit_failure $1 else iptables -t mangle -D OUTPUT 1 fi fi if [ "$TTL_STEALTH_ROUTER" == "yes" ]; then if (( `iptables -t mangle -I FORWARD -j ACCEPT 2>&1 | grep -c "No chain/target/match by that name"` )); then FAILURE="Linux kernel 2.4.18 or newer required for TTL_STEALTH_ROUTER mode." exit_failure $1 else iptables -t mangle -D FORWARD 1 fi fi fi # Test for ipt_TTL support. if [ "$TTL_STEALTH_ROUTER" == "yes" ]; then if (( `iptables -t mangle -I FORWARD -j TTL --ttl-inc "1" 2>&1 | grep -c "No chain/target/match by that name"` )); then FAILURE="TTL_STEALTH_ROUTER mode requires a patched kernel. See http://Projectfiles.org/firewall/ for details." exit_failure $1 else iptables -t mangle -D FORWARD 1 fi fi # System and configuration approved. echo " [ PASSED ]" # Exit if we only want to do sanity checking. if [ "$1" == "check" ]; then exit fi ########################## # -- Firewall Section -- # ########################## echo -n "-> Building firewall." # Let no packets slip by while we are configuring the firewall. echo "0" > /proc/sys/net/ipv4/ip_forward # Enable kernel level reverse path filtering. echo "1" > /proc/sys/net/ipv4/conf/all/rp_filter for INTERFACE in $NO_RP_FILTER_INTERFACES; do echo "0" > /proc/sys/net/ipv4/conf/$INTERFACE/rp_filter done # Enable kernel level dynamic address handling. if [ -n "$DYNAMIC_INTERFACES" ]; then echo "1" > /proc/sys/net/ipv4/ip_dynaddr else echo "0" > /proc/sys/net/ipv4/ip_dynaddr fi # Set default policies. iptables -t filter -F iptables -t filter -X iptables -t filter -P INPUT DROP iptables -t filter -P FORWARD DROP iptables -t filter -P OUTPUT ACCEPT if !(( `iptables -t nat -F 2>&1 | grep -c "Table does not exist"` )); then iptables -t nat -X iptables -t nat -P PREROUTING ACCEPT iptables -t nat -P POSTROUTING ACCEPT iptables -t nat -P OUTPUT ACCEPT fi if !(( `iptables -t mangle -F 2>&1 | grep -c "Table does not exist"` )); then iptables -t mangle -F iptables -t mangle -X iptables -t mangle -P PREROUTING ACCEPT iptables -t mangle -P OUTPUT ACCEPT iptables -t mangle -P POSTROUTING ACCEPT > /dev/null 2>&1 # New 2.4.18 builtin mangle chains iptables -t mangle -P INPUT ACCEPT > /dev/null 2>&1 iptables -t mangle -P FORWARD ACCEPT > /dev/null 2>&1 fi # Drop traffic to and from blacklisted networks. for NETWORK in $BLACKLIST; do NET=`echo "$NETWORK:" | cut -d: -f1` if ! check_network; then PORTS="$NET" NET="0.0.0.0/0" else PORTS=`echo "$NETWORK:" | cut -d: -f2` fi if [ -n "$PORTS" ]; then PROTOCOL=`echo "$PORTS/" | cut -d/ -f2` PORT="--dport `echo "$PORTS/" | cut -d/ -f1 | cut -d- -f1,2 --output-delimiter=":"`" if [ "$PROTOCOL" == "tcp" ] || [ -z "$PROTOCOL" ]; then if [ "$IS_ROUTER" == "yes" ]; then iptables -t filter -I FORWARD -s $NET -p tcp $PORT -j DROP iptables -t filter -I FORWARD -d $NET -p tcp $PORT -j DROP fi iptables -t filter -I INPUT -s $NET -p tcp $PORT -j DROP iptables -t filter -I INPUT -d $NET -p tcp $PORT -j DROP iptables -t filter -I OUTPUT -s $NET -p tcp $PORT -j DROP iptables -t filter -I OUTPUT -d $NET -p tcp $PORT -j DROP fi if [ "$PROTOCOL" == "udp" ] || [ -z "$PROTOCOL" ]; then if [ "$IS_ROUTER" == "yes" ]; then iptables -t filter -I FORWARD -s $NET -p udp $PORT -j DROP iptables -t filter -I FORWARD -d $NET -p udp $PORT -j DROP fi iptables -t filter -I INPUT -s $NET -p udp $PORT -j DROP iptables -t filter -I INPUT -d $NET -p udp $PORT -j DROP iptables -t filter -I OUTPUT -s $NET -p udp $PORT -j DROP iptables -t filter -I OUTPUT -d $NET -p udp $PORT -j DROP fi else if [ "$IS_ROUTER" == "yes" ]; then iptables -t filter -I FORWARD -s $NET -j DROP iptables -t filter -I FORWARD -d $NET -j DROP fi iptables -t filter -I INPUT -s $NET -j DROP iptables -t filter -I INPUT -d $NET -j DROP iptables -t filter -I OUTPUT -s $NET -j DROP iptables -t filter -I OUTPUT -d $NET -j DROP fi done # Initialize trusted chain iptables -t filter -N TRUSTED if [ "$RFC_1122_COMPLIANT" == "yes" ]; then iptables -t filter -A TRUSTED -p icmp -j DROP # ICMP will be permitted elsewhere. iptables -t filter -A TRUSTED -j REJECT else iptables -t filter -A TRUSTED -j DROP fi # Reject state NEW without SYN flag set. (paranoia setting) if [ "$DROP_NEW_WITHOUT_SYN" == "yes" ]; then if [ "$LOGGING" == "yes" ]; then iptables -A INPUT -p tcp ! --syn -m state --state NEW -m limit --limit $LOG_LIMIT \ --limit-burst $LOG_BURST -j LOG --log-level $LOG_LEVEL --log-prefix "firewall: " fi iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP if [ "$IS_ROUTER" == "yes" ]; then if [ "$LOGGING" == "yes" ]; then iptables -A FORWARD -p tcp ! --syn -m state --state NEW -m limit --limit $LOG_LIMIT \ --limit-burst $LOG_BURST -j LOG --log-level $LOG_LEVEL --log-prefix "firewall: " fi iptables -A FORWARD -p tcp ! --syn -m state --state NEW -j DROP fi fi # Set logging preferences. Do not log broadcasts. if [ "$LOGGING" == "yes" ]; then echo "1" > /proc/sys/net/ipv4/conf/all/log_martians iptables -t filter -N LOGME iptables -t filter -I TRUSTED -j LOGME for BROADCAST in $BCAST_LIST; do iptables -t filter -I LOGME -d $BROADCAST -j RETURN done iptables -t filter -A LOGME -p icmp -m limit --limit $LOG_LIMIT --limit-burst $LOG_BURST -j LOG --log-level $LOG_LEVEL \ --log-prefix "firewall: " iptables -t filter -A LOGME -p tcp -m limit --limit $LOG_LIMIT --limit-burst $LOG_BURST -j LOG --log-level $LOG_LEVEL \ --log-prefix "firewall: " iptables -t filter -A LOGME -p udp -m limit --limit $LOG_LIMIT --limit-burst $LOG_BURST -j LOG --log-level $LOG_LEVEL \ --log-prefix "firewall: " fi echo -n "." # Accept icmp-echo-request packets if RFC-1122 compliance option is enabled. Limit logging of icmp packets. if [ "$RFC_1122_COMPLIANT" == "yes" ]; then if [ "$LOGGING" == "yes" ]; then for ADDRESS in $INTERNAL_ADDRESSES $EXTERNAL_ADDRESSES; do iptables -t filter -I TRUSTED 2 -d $ADDRESS -p icmp --icmp-type echo-request -j ACCEPT done for FORWARD in $STATIC_INSIDE_OUTSIDE; do ADDRESS=`echo "$FORWARD:" | cut -d: -f1` iptables -t filter -I TRUSTED 2 -d $ADDRESS -p icmp --icmp-type echo-request -j ACCEPT done for ADDRESS in $INTERNAL_ADDRESSES $EXTERNAL_ADDRESSES; do iptables -t filter -I TRUSTED -d $ADDRESS -p icmp --icmp-type echo-request -m limit --limit 2/second --limit-burst 10 -j ACCEPT done for FORWARD in $STATIC_INSIDE_OUTSIDE; do ADDRESS=`echo "$FORWARD:" | cut -d: -f1` iptables -t filter -I TRUSTED -d $ADDRESS -p icmp --icmp-type echo-request -m limit --limit 2/second --limit-burst 10 -j ACCEPT done if [ "$IS_ROUTER" != "yes" ] && [ -z "$EXTERNAL_ADDRESSES" ]; then iptables -t filter -I TRUSTED 2 -p icmp --icmp-type echo-request -j ACCEPT iptables -t filter -I TRUSTED -p icmp --icmp-type echo-request -m limit --limit 2/second --limit-burst 10 -j ACCEPT elif [ -n "$DMZ_INTERFACES" ]; then for INTERFACE in $DMZ_INTERFACES; do iptables -t filter -I TRUSTED 2 -o $INTERFACE -p icmp --icmp-type echo-request -j ACCEPT iptables -t filter -I TRUSTED -o $INTERFACE -p icmp --icmp-type echo-request -m limit --limit 2/second --limit-burst 10 -j ACCEPT done fi else for ADDRESS in $INTERNAL_ADDRESSES $EXTERNAL_ADDRESSES; do iptables -t filter -I TRUSTED -d $ADDRESS -p icmp --icmp-type echo-request -j ACCEPT done for FORWARD in $STATIC_INSIDE_OUTSIDE; do ADDRESS=`echo "$FORWARD:" | cut -d: -f1` iptables -t filter -I TRUSTED -d $ADDRESS -p icmp --icmp-type echo-request -j ACCEPT done if [ "$IS_ROUTER" != "yes" ] && [ -z "$EXTERNAL_ADDRESSES" ]; then iptables -t filter -I TRUSTED -p icmp --icmp-type echo-request -j ACCEPT elif [ -n "$DMZ_INTERFACES" ]; then for INTERFACE in $DMZ_INTERFACES; do iptables -t filter -I TRUSTED -o $INTERFACE -p icmp --icmp-type echo-request -j ACCEPT done fi fi fi # Insert trusted networks into trusted chain before everything else. for NETWORK in $PERMIT ; do iptables -t filter -I TRUSTED -s $NETWORK -j ACCEPT done # Insert local external networks into the trusted chain if option is enabled. if [ "$TRUST_LOCAL_EXTERNAL_NETWORKS" == "yes" ]; then for NETWORK in $EXTERNAL_NETWORKS; do iptables -t filter -I TRUSTED -s $NETWORK -j ACCEPT done fi # Set default policy for ESTABLISHED and RELATED connections to ACCEPT on FORWARD chains. iptables -t filter -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT if [ "$IS_ROUTER" == "yes" ]; then iptables -t filter -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT fi # Configure ALLOW_INBOUND and DENY_OUTBOUND. if [ -n "$INTERNAL_INTERFACES" ]; then for PARAM in ACCEPT TRUSTED; do if [ "$PARAM" == "TRUSTED" ]; then LIST="$DENY_OUTBOUND" else LIST="$ALLOW_INBOUND" fi for ITEM in $LIST; do NET="-s `echo "$ITEM:" | cut -d: -f1`" if [ "$NET" == "-s any" ]; then NET="" fi DEST="-d `echo "$ITEM:" | cut -d: -f2`" if [ "$DEST" == "-d any" ]; then DEST="" fi PORTS=`echo "$ITEM:" | cut -d: -f3` PROTOCOL=`echo "$PORTS/" | cut -d/ -f2` PORT="--dport `echo "$PORTS/" | cut -d/ -f1 | cut -d- -f1,2 --output-delimiter=":"`" if [ -z "$DEST" ] || [ -z "$NET" ]; then if [ "$PARAM" == "ACCEPT" ]; then TAB="-o" # (just to reuse the variable) For ALLOW_INBOUND else # classify packets sent out on internal interfaces and TAB="-i" # for DENY_OUTBOUND, received by internal interfaces, fi # unless both source and destination addresses are available. for INTERFACE in $INTERNAL_INTERFACES; do if !(( `echo "$INTERFACE" | grep -c ":"` )); then if [ "$PORTS" == "any" ]; then iptables -t filter -A FORWARD -m state --state NEW $TAB $INTERFACE $NET $DEST -j $PARAM else if [ "$PROTOCOL" == "tcp" ] || [ -z "$PROTOCOL" ]; then iptables -t filter -A FORWARD -m state --state NEW $TAB $INTERFACE $NET $DEST -p tcp $PORT -j $PARAM fi if [ "$PROTOCOL" == "udp" ] || [ -z "$PROTOCOL" ]; then iptables -t filter -A FORWARD -m state --state NEW $TAB $INTERFACE $NET $DEST -p udp $PORT -j $PARAM fi fi fi done else # The exception where we have both source and destination addresses if [ "$PORTS" == "any" ]; then iptables -t filter -A FORWARD -m state --state NEW $NET $DEST -j $PARAM else if [ "$PROTOCOL" == "tcp" ] || [ -z "$PROTOCOL" ]; then iptables -t filter -A FORWARD -m state --state NEW $NET $DEST -p tcp $PORT -j $PARAM fi if [ "$PROTOCOL" == "udp" ] || [ -z "$PROTOCOL" ]; then iptables -t filter -A FORWARD -m state --state NEW $NET $DEST -p udp $PORT -j $PARAM fi fi fi done done fi # For servers, only allow NEW connections to specified INPUT ports. For port forwarding, allow on FORWARD chain. for ITEM in $OPEN_PORTS $TRUSTED_PORTS; do NET="" if (( `echo "$ITEM:" | cut -d: -f2 | grep -c "."` )); then NET="-s `echo "$ITEM:" | cut -d: -f1`" ITEM=`echo "$ITEM:" | cut -d: -f2` fi PORTS=`echo "$ITEM" | cut -d/ -f1` PORTS=`echo "$PORTS" | cut -d- -f1,2 --output-delimiter=":"` PROTOCOL=`echo "$ITEM" | cut -d/ -f2` COUNT="0" for FORWARD in $PORT_FORWARDS; do IN_PORTS=`echo "$FORWARD" | cut -d: -f2 | cut -d- -f1,2 --output-delimiter=":"` if [ "`echo "$FORWARD" | cut -d: -f1`" == "$PROTOCOL" ] && [ "$PORTS" == "$IN_PORTS" ]; then DEST=`echo "$FORWARD" | cut -d: -f3` DPORTS=`echo "$FORWARD" | cut -d: -f4 | cut -d- -f1,2 --output-delimiter=":"` if [ -z "$DPORTS" ]; then DPORTS="$IN_PORTS" fi iptables -t filter -A FORWARD -m state --state NEW $NET -d $DEST -p $PROTOCOL --dport $DPORTS -j ACCEPT COUNT="1" if [ -z "$NET" ]; then continue 2 # i.e. This port forward is open to everyone. fi fi done if [ "$COUNT" == "0" ]; then iptables -t filter -A INPUT -m state --state NEW $NET -p $PROTOCOL --dport $PORTS -j ACCEPT fi done echo -n "." # For routers, allow routing of internal and routed networks on internal interfaces. Fix traceroutes under DNAT info-leak-bug. if [ "$IS_ROUTER" == "yes" ]; then COUNT="0" TAB="" for INTERFACE in $STATIC_INTERNAL_INTERFACES; do COUNT=$((COUNT + 1)) NETWORK=`echo "$INTERNAL_NETWORKS" | cut -d\ -f$COUNT` INTERFACE=`echo "$INTERFACE" | cut -d: -f1` iptables -t filter -A OUTPUT -o $INTERFACE -d $NETWORK -p icmp -j ACCEPT if [ -z "$DMZ_INTERFACES" ] || !(( `echo "$DMZ_INTERFACES" | grep -c "$INTERFACE"` )); then if [ "$SHARED_INTERNAL" == "yes" ]; then iptables -t filter -A FORWARD -m state --state NEW -i $INTERFACE -s $NETWORK -j ACCEPT else for DEST in $EXTERNAL_INTERFACES $DMZ_INTERFACES; do if !(( `echo "$DEST" | grep -c ":"` )); then iptables -t filter -A FORWARD -m state --state NEW -i $INTERFACE -s $NETWORK -o $DEST -j ACCEPT fi done fi else for DEST in $EXTERNAL_INTERFACES; do if !(( `echo "$DEST" | grep -c ":"` )); then iptables -t filter -A FORWARD -m state --state NEW -i $INTERFACE -s $NETWORK -o $DEST -j ACCEPT fi done fi if [ "$TRUST_ROUTED_NETWORKS" == "yes" ] && ( [ -z "$DMZ_INTERFACES" ] || \ !(( `echo "$DMZ_INTERFACES" | grep -c "$INTERFACE"` )) ); then iptables -t filter -A INPUT -m state --state NEW -i $INTERFACE -s $NETWORK -j ACCEPT fi if [ "$INTERNAL_DHCP" == "yes" ]; then if !(( `echo "$TAB" | grep -c "$INTERFACE"` )); then iptables -t filter -A INPUT -m state --state NEW -i $INTERFACE -p udp --dport 67 -j ACCEPT fi TAB="$TAB $INTERFACE" fi if [ -z "$DMZ_INTERFACES" ] || !(( `echo "$DMZ_INTERFACES" | grep -c "$INTERFACE"` )); then for NETWORK in $ADDITIONAL_ROUTED_NETWORKS; do iptables -t filter -A OUTPUT -o $INTERFACE -d $NETWORK -p icmp -j ACCEPT if [ "$SHARED_INTERNAL" == "yes" ]; then iptables -t filter -A FORWARD -m state --state NEW -i $INTERFACE -s $NETWORK -j ACCEPT else for DEST in $EXTERNAL_INTERFACES $DMZ_INTERFACES; do if !(( `echo "$DEST" | grep -c ":"` )); then iptables -t filter -A FORWARD -m state --state NEW -i $INTERFACE -s $NETWORK -o $DEST -j ACCEPT fi done fi if [ "$TRUST_ROUTED_NETWORKS" == "yes" ]; then iptables -t filter -A INPUT -m state --state NEW -i $INTERFACE -s $NETWORK -j ACCEPT fi done fi done for INTERFACE in $DYNAMIC_INTERNAL_INTERFACES; do iptables -t filter -A OUTPUT -o $INTERFACE -p icmp -j ACCEPT iptables -t filter -A FORWARD -m state --state NEW -i $INTERFACE -j ACCEPT if [ "$TRUST_ROUTED_NETWORKS" == "yes" ]; then iptables -t filter -A INPUT -m state --state NEW -i $INTERFACE -j ACCEPT fi done fi # ICMP DNAT information leak workaround. iptables -t filter -A OUTPUT -p icmp -m state --state INVALID -j DROP # Set up static address translations. if [ "$IS_ROUTER" == "yes" ]; then for FORWARD in $STATIC_INSIDE_OUTSIDE; do INSIDE=`echo "$FORWARD:" | cut -d: -f1` OUTSIDE=`echo "$FORWARD:" | cut -d: -f2` iptables -t nat -A POSTROUTING -s $INSIDE -j SNAT --to-source $OUTSIDE if !(( `echo "$INSIDE" | grep -c "/"` )); then for ITEM in $ALLOW_INBOUND; do NETWORK="-s `echo "$ITEM" | cut -d: -f1`" # Source if [ "$NETWORK" == "-s any" ]; then NETWORK="" fi NET=`echo "$ITEM" | cut -d: -f2` # Destination PORTS=`echo "$ITEM" | cut -d: -f3` if [ -n "$PORTS" ]; then PORT="--dport `echo "$PORTS/" | cut -d/ -f1 | cut -d- -f1,2 --output-delimiter=":"`" PROTOCOL=`echo "$PORTS/" | cut -d/ -f2` fi if [ "$NET" != "any" ]; then # If there is a specific destination -- NET1="$INSIDE" # Determine if this is part of it. xbits MASK=`echo "$NET/" | cut -d/ -f2` if [ -z "$MASK" ]; then MASK=32 fi fi if [ "$NET" == "any" ] || [ "$XBITS" -ge "$MASK" ]; then if [ "$RFC_1122_COMPLIANT" == "yes" ]; then iptables -t nat -A PREROUTING $NETWORK -d $OUTSIDE \ -p icmp --icmp-type echo-request -j DNAT --to-destination $INSIDE fi if [ "$PORTS" == "any" ]; then iptables -t nat -A PREROUTING $NETWORK -d $OUTSIDE -p tcp -j DNAT --to-destination $INSIDE iptables -t nat -A PREROUTING $NETWORK -d $OUTSIDE -p udp -j DNAT --to-destination $INSIDE else if [ "$PROTOCOL" == "tcp" ] || [ "$PROTOCOL" == "udp" ]; then iptables -t nat -A PREROUTING $NETWORK -d $OUTSIDE -p $PROTOCOL $PORT -j DNAT --to-destination $INSIDE else iptables -t nat -A PREROUTING $NETWORK -d $OUTSIDE -p tcp $PORT -j DNAT --to-destination $INSIDE iptables -t nat -A PREROUTING $NETWORK -d $OUTSIDE -p udp $PORT -j DNAT --to-destination $INSIDE fi fi fi done for NETWORK in $PERMIT; do iptables -t nat -A PREROUTING -s $NETWORK -d $OUTSIDE -j DNAT --to-destination $INSIDE done COUNT="0" NET1="$INSIDE" for INTERFACE in $STATIC_INTERNAL_INTERFACES; do COUNT=$((COUNT + 1)) NET=`echo $INTERNAL_NETWORKS | cut -d\ -f$COUNT` INTERFACE=`echo $INTERFACE | cut -d: -f1` iptables -t nat -A PREROUTING -s $NET -d $OUTSIDE -j DNAT --to-destination $INSIDE xbits MASK=`echo "$NET/" | cut -d/ -f2` if [ -z "$MASK" ]; then MASK=32 fi ADDRESS=`echo $INTERNAL_ADDRESSES | cut -d\ -f$COUNT` if [ "$XBITS" -ge "$MASK" ]; then iptables -t nat -A POSTROUTING -s $NET -o $INTERFACE -d $INSIDE -j SNAT --to-source $ADDRESS fi for NET in $ADDITIONAL_ROUTED_NETWORKS; do xbits if [ "$XBITS" -ge "$MASK" ]; then iptables -t nat -A POSTROUTING -s $NET -o $INTERFACE -d $INSIDE -j SNAT --to-source $ADDRESS fi iptables -t nat -A PREROUTING -s $NET -d $OUTSIDE -j DNAT --to-destination $INSIDE done done for INTERFACE in $DYNAMIC_INTERNAL_INTERFACES; do iptables -t nat -A PREROUTING -s $NETWORK -d $OUTSIDE -j DNAT --to-destination $INSIDE done fi # Lets not have people mistaking the router for the internal host. iptables -t filter -I INPUT -d $OUTSIDE -j DROP done fi # Configure NAT. if [ "$IS_ROUTER" == "yes" ]; then COUNT="0" for INTERFACE in $STATIC_NAT_INTERFACES; do COUNT=$((COUNT + 1)) ADDRESS=`echo "$NAT_ADDRESSES" | cut -d\ -f$COUNT` if [ -n "$DYNAMIC_INTERNAL_INTERFACES" ]; then iptables -t nat -A POSTROUTING -o $INTERFACE -j SNAT --to-source $ADDRESS else for NETWORK in $NAT_NETWORKS $ADDITIONAL_ROUTED_NETWORKS; do iptables -t nat -A POSTROUTING -s $NETWORK -o $INTERFACE -j SNAT --to-source $ADDRESS done fi done for INTERFACE in $DYNAMIC_NAT_INTERFACES; do if [ -n "$DYNAMIC_INTERNAL_INTERFACES" ]; then iptables -t nat -I POSTROUTING -o $INTERFACE -j MASQUERADE else for NETWORK in $NAT_NETWORKS $ADDITIONAL_ROUTED_NETWORKS; do iptables -t nat -I POSTROUTING -s $NETWORK -o $INTERFACE -j MASQUERADE done fi done fi echo -n "." # Configure port forwarding. for FORWARD in $PORT_FORWARDS; do PROTOCOL=`echo "$FORWARD" | cut -d: -f1` IN_PORTS=`echo "$FORWARD" | cut -d: -f2 | cut -d- -f1,2 --output-delimiter=":"` DEST=`echo "$FORWARD" | cut -d: -f3` PORTS=`echo "$FORWARD" | cut -d: -f4` if [ -z "$PORTS" ]; then PORTS="$IN_PORTS" fi DPORTS=`echo "$PORTS" | cut -d- -f1,2 --output-delimiter=":"` # Support DNAT for locally generated connections, new in iptables 1.2.6a and kernel 2.4.19 iptables -t nat -A OUTPUT -o lo -p $PROTOCOL --dport $IN_PORTS -j DNAT --to-destination $DEST:$PORTS > /dev/null 2>&1 COUNT="0" while (( `echo "${INTERFACE_TAB[$((COUNT + 1))]}" | grep -c "."` )); do COUNT=$((COUNT + 1)) if (( `echo "$DYNAMIC_INTERFACES" | grep -c "${INTERFACE_TAB[$COUNT]}"` )); then iptables -t nat -I POSTROUTING -m mark --mark "$COUNT" -o ${INTERFACE_TAB[$COUNT]} -d $DEST \ -p $PROTOCOL --dport $DPORTS -j MASQUERADE else iptables -t nat -I POSTROUTING -m mark --mark "$COUNT" -o ${INTERFACE_TAB[$COUNT]} -d $DEST \ -p $PROTOCOL --dport $DPORTS -j SNAT --to-source ${ADDRESS_TAB[$COUNT]} fi if (( `echo "$DYNAMIC_INTERNAL_INTERFACES" | grep -c "${INTERFACE_TAB[$COUNT]}"` )) && \ [ "$PORT_FWD_ROUTED_NETWORKS" == "yes" ]; then iptables -t nat -A PREROUTING -i ${INTERFACE_TAB[$COUNT]} \ -p $PROTOCOL --dport $IN_PORTS -j DNAT --to-destination $DEST:$PORTS iptables -t mangle -A PREROUTING -i ${INTERFACE_TAB[$COUNT]} \ -p $PROTOCOL --dport $IN_PORTS -j MARK --set-mark "$COUNT" continue # We will accept anything on this interface. fi for ADDRESS in $PORT_FORWARD_ADDRESSES; do for ITEM in $OPEN_PORTS $TRUSTED_PORTS; do if (( `echo "$ITEM:" | cut -d: -f2 | grep -c "."` )); then NET="-s `echo "$ITEM:" | cut -d: -f1`" ITEM=`echo "$ITEM:" | cut -d: -f2` else NET="" fi PORT=`echo "$ITEM/" | cut -d/ -f1` PORT=`echo "$PORT" | cut -d- -f1,2 --output-delimiter=":"` if [ "$PROTOCOL" == "`echo "$ITEM/" | cut -d/ -f2`" ] && [ "$PORT" == "$IN_PORTS" ]; then if (( `echo "$DYNAMIC_NAT_INTERFACES" | grep -c "${INTERFACE_TAB[$COUNT]}"` )); then iptables -t nat -A PREROUTING $NET -i ${INTERFACE_TAB[$COUNT]} \ -p $PROTOCOL --dport $IN_PORTS -j DNAT --to-destination $DEST:$PORTS iptables -t mangle -A PREROUTING $NET -i ${INTERFACE_TAB[$COUNT]} \ -p $PROTOCOL --dport $IN_PORTS -j MARK --set-mark "$COUNT" else iptables -t nat -A PREROUTING $NET -d $ADDRESS -i ${INTERFACE_TAB[$COUNT]} \ -p $PROTOCOL --dport $IN_PORTS -j DNAT --to-destination $DEST:$PORTS iptables -t mangle -A PREROUTING $NET -d $ADDRESS -i ${INTERFACE_TAB[$COUNT]} \ -p $PROTOCOL --dport $IN_PORTS -j MARK --set-mark "$COUNT" fi if [ -z "$NET" ]; then continue 2 # This port forward is open to everyone. fi fi done for NETWORK in ${NETWORK_TAB[$COUNT]}; do if (( `echo "$DYNAMIC_NAT_INTERFACES" | grep -c "${INTERFACE_TAB[$COUNT]}"` )); then iptables -t nat -A PREROUTING -i ${INTERFACE_TAB[$COUNT]} -s $NETWORK \ -p $PROTOCOL --dport $IN_PORTS -j DNAT --to-destination $DEST:$PORTS iptables -t mangle -A PREROUTING -i ${INTERFACE_TAB[$COUNT]} -s $NETWORK \ -p $PROTOCOL --dport $IN_PORTS -j MARK --set-mark "$COUNT" else iptables -t nat -A PREROUTING -d $ADDRESS -i ${INTERFACE_TAB[$COUNT]} -s $NETWORK \ -p $PROTOCOL --dport $IN_PORTS -j DNAT --to-destination $DEST:$PORTS iptables -t mangle -A PREROUTING -d $ADDRESS -i ${INTERFACE_TAB[$COUNT]} -s $NETWORK \ -p $PROTOCOL --dport $IN_PORTS -j MARK --set-mark "$COUNT" fi done for NETWORK in $PERMIT; do if (( `echo "$DYNAMIC_NAT_INTERFACES" | grep -c "${INTERFACE_TAB[$COUNT]}"` )); then iptables -t nat -A PREROUTING -i ${INTERFACE_TAB[$COUNT]} -s $NETWORK \ -p $PROTOCOL --dport $IN_PORTS -j DNAT --to-destination $DEST:$PORTS iptables -t mangle -A PREROUTING -i ${INTERFACE_TAB[$COUNT]} -s $NETWORK \ -p $PROTOCOL --dport $IN_PORTS -j MARK --set-mark "$COUNT" else iptables -t nat -A PREROUTING -d $ADDRESS -i ${INTERFACE_TAB[$COUNT]} -s $NETWORK \ -p $PROTOCOL --dport $IN_PORTS -j DNAT --to-destination $DEST:$PORTS iptables -t mangle -A PREROUTING -d $ADDRESS -i ${INTERFACE_TAB[$COUNT]} -s $NETWORK \ -p $PROTOCOL --dport $IN_PORTS -j MARK --set-mark "$COUNT" fi done # Done with sources if (( `echo "$DYNAMIC_NAT_INTERFACES" | grep -c "${INTERFACE_TAB[$COUNT]}"` )); then break fi done # Done with destination addresses done # Done with interfaces done # Done with forwards # Source nat outbound connections generated by the local machine to address defined in FIREWALL_IP. for ADDRESS in $FIREWALL_IP; do OUTSIDE=`echo "$ADDRESS:" | cut -d: -f1` INSIDE=`echo "$ADDRESS:" | cut -d: -f2` iptables -t nat -A POSTROUTING -s $OUTSIDE -j SNAT --to-source $INSIDE done # Accept new connections from the loopback interface (localhost). iptables -t filter -A INPUT -i lo -m state --state NEW -j ACCEPT # Jump to the trusted chain if this packet establishes a NEW connection. iptables -t filter -A INPUT -m state --state NEW -j TRUSTED if [ "$IS_ROUTER" == "yes" ]; then iptables -t filter -A FORWARD -m state --state NEW -j TRUSTED fi # Enable TTL stealth router mode. if [ "$TTL_STEALTH_ROUTER" == "yes" ]; then iptables -t mangle -I FORWARD -j TTL --ttl-inc "1" fi # Now that everything is configured we can enable ip_forward for routers. if [ "$IS_ROUTER" == "yes" ]; then echo "1" > /proc/sys/net/ipv4/ip_forward fi # Print exit message. echo " [ DONE ]" if [ -n "$EXTERNAL_ADDRESSES" ]; then echo "-> Successfully secured the following addresses: `echo $EXTERNAL_ADDRESSES | sed s/\ /,\ /g`." fi if [ "$IS_ROUTER" == "yes" ]; then if [ -n "$DYNAMIC_EXTERNAL_INTERFACES" ]; then echo "-> Successfully secured the following external interfaces: `echo $DYNAMIC_EXTERNAL_INTERFACES | sed s/\ /,\ /g`." fi if [ -n "$INTERNAL_NETWORKS" ] || [ -n "$ADDITIONAL_ROUTED_NETWORKS" ]; then echo "-> Routing is enabled for the following networks: `echo $INTERNAL_NETWORKS $ADDITIONAL_ROUTED_NETWORKS | \ sed s/\ /,\ /g`." fi if [ -n "$DYNAMIC_INTERNAL_INTERFACES" ]; then echo "-> Alert! Routing is enabled for ALL connections through: `echo $DYNAMIC_INTERNAL_INTERFACES \ | sed s/\ /,\ /g`." fi fi # Write a configuration file if passed appropriate arguments. if [ "$1" == "save" ] || [ "$1" == "update" ]; then if [ -a "$CONFIG" ]; then if !(( `head -1 "$CONFIG" | grep -c "# Linux Firewall configuration -- http://Projectfiles.org/firewall/"` )); then echo "-> WARNING: The file $CONFIG is associated with another program!" echo "-> Press any key to overwrite, or CTRL-C to abort." read -rsn1 fi fi cat << EOF > $CONFIG # Linux Firewall configuration -- http://Projectfiles.org/firewall/ # Generated by '`echo $0 | sed s#^\./#$PWD/#` $1 `echo $2 | sed s#^\./#$PWD/#`' # on `date`. # Generated with version: "$VERSION". PERMIT="$ORIG_PERMIT" INTERNAL_INTERFACES="$ORIG_INTERNAL_INTERFACES" DYNAMIC_INTERFACES="$ORIG_DYNAMIC_INTERFACES" DENY_OUTBOUND="$ORIG_DENY_OUTBOUND" ALLOW_INBOUND="$ORIG_ALLOW_INBOUND" BLACKLIST="$BLACKLIST" STATIC_INSIDE_OUTSIDE="$ORIG_STATIC_INSIDE_OUTSIDE" PORT_FORWARDS="$ORIG_PORT_FORWARDS" PORT_FWD_ALL="$PORT_FWD_ALL" PORT_FWD_ROUTED_NETWORKS="$PORT_FWD_ROUTED_NETWORKS" ADDITIONAL_ROUTED_NETWORKS="$ADDITIONAL_ROUTED_NETWORKS" TRUST_ROUTED_NETWORKS="$TRUST_ROUTED_NETWORKS" SHARED_INTERNAL="$SHARED_INTERNAL" FIREWALL_IP="$FIREWALL_IP" TRUST_LOCAL_EXTERNAL_NETWORKS="$TRUST_LOCAL_EXTERNAL_NETWORKS" DMZ_INTERFACES="$DMZ_INTERFACES" NAT_EXTERNAL="$NAT_EXTERNAL" ADDITIONAL_NAT_INTERFACES="$ADDITIONAL_NAT_INTERFACES" IGNORE_INTERFACES="$IGNORE_INTERFACES" LOGGING="$LOGGING" NO_RP_FILTER_INTERFACES="$NO_RP_FILTER_INTERFACES" INTERNAL_DHCP="$INTERNAL_DHCP" RFC_1122_COMPLIANT="$RFC_1122_COMPLIANT" DROP_NEW_WITHOUT_SYN="$DROP_NEW_WITHOUT_SYN" DUMP_TCP_ON_INIT="$DUMP_TCP_ON_INIT" TTL_STEALTH_ROUTER="$TTL_STEALTH_ROUTER" LOG_LIMIT="$LOG_LIMIT" LOG_BURST="$LOG_BURST" LOG_LEVEL="$LOG_LEVEL" return EOF iptables-save >> $CONFIG chown root:root $CONFIG chmod 600 $CONFIG echo "-> Firewall configuration saved to $CONFIG" fi # Dump current TCP sessions if requested. if [ "$DUMP_TCP_ON_INIT" == "yes" ]; then dump_tcp fi # Done!