home *** CD-ROM | disk | FTP | other *** search
Wrap
#!/bin/bash # # The Linux Firewall Project Graphical Installation Utility # Version 1.1 -- 1/21/03 # http://projectfiles.com/firewall/ # # Linux Firewall # Copyright (C) 2001-2002 Scott Bartlett <srb@mnsolutions.com> # # Graphical Installation Utility # Copyright (C) 2002 Vincent Rivellino <var@mnsolutions.com> # and Scott Bartlett <srb@mnsolutions.com> # # 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 # # ############################################## # -- Administrative Configuration Options -- # ############################################## # # LONG_NETWORK_NAME below should be a character string to be displayed # by the installer as an explanation of the list of networks and/or # hosts defined in LOCAL_NETWORK. SHORT_NETWORK_NAME should be a single # word that will be used when highlighting your choice of networks. # The LOCAL_NETWORK variable should consist of a space # delimited list of networks and hosts with netmasks between 0 and 32 # in the format: <host or network address>[/<netmask>] # WARNING: None of these options are checked for input errors. Please # enter information carefully. LONG_NETWORK_NAME="" SHORT_NETWORK_NAME="" LOCAL_NETWORK="" ########################################################### # -- Nothing below this point should need modification -- # ########################################################### # Set version information. GUI_VERSION="1.1" FW_VERSION="2.0rc9" # Set PATH explicitly. export PATH="/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin" # Set variables. TMPFILE="/tmp/firewall.temp$$" FW_TMPFILE="/tmp/rc.firewall" FW_INSTALL="/etc/rc.d/rc.firewall" FW_PERM="750" permit_opt="" int_iface_opt="" dyn_iface_opt="" status="welcome" if [ "$1" == "fast" ]; then INIT="fast" else INIT="start" fi # Make sure we are root. if [ "$EUID" != "0" ]; then echo "You must have root privileges to run this utility!!!" exit 1 fi # remove the TMPFILE ... rm -rf $TMPFILE > /dev/null 2>&1 # Define a default LONG_NETWORK_NAME if none exists. This will be ignored if # there is no corresponding LOCAL_NETWORK. if [ -z "$LONG_NETWORK_NAME" ]; then LONG_NETWORK_NAME="predefined network" fi # Do the same for SHORT_NETWORK_NAME. if [ -z "$SHORT_NETWORK_NAME" ]; then SHORT_NETWORK_NAME="local" fi # Define exit subroutine. goodbye() { rm -f $TMPFILE > /dev/null 2>&1 clear echo "Configuration terminated. Goodbye." exit } # Convert a provided netmask of 255.255.252.0 to /24 notation if necessary. make_mask() { if [ "X$1" == "X" ]; then echo -1 return fi if [ "X`echo $1 | cut -s -f 1 -d '.'`" == "X" ]; then if [ "$1" -ge "32" ]; then echo -1 else echo $1 fi return fi MASK=$1 LAST=1 for OCTET in 1 2 3 4; do BINARY=`echo "$MASK" | cut -s -d . -f $OCTET` if [ "X$BINARY" == "X" ]; then echo -1 exit fi for SUBTRACT in 128 64 32 16 8 4 2 1; do if [ "$((BINARY - SUBTRACT))" -ge "0" ]; then BINARY=$((BINARY - SUBTRACT)) STROKE=$((STROKE + 1)) if [ "$LAST" != "1" ]; then echo -1 exit fi else LAST=0 fi done done echo $STROKE } # Given a servicename, return a string to add to the PERMIT option. get_pstr() { case "$1" in '"ftp"') echo "21/tcp" ;; '"ssh"') echo "22/tcp" ;; '"smtp"') echo "25/tcp" ;; '"dns"') echo "53" ;; '"finger"') echo "79/tcp" ;; '"http"') echo "80/tcp" ;; '"pop3"') echo "110/tcp" ;; '"auth"') echo "113/tcp" ;; '"imap"') echo "143/tcp" ;; '"https"') echo "443/tcp" ;; '"syslog"') echo "514/udp" ;; '"lpd"') echo "515/tcp" ;; '"imaps"') echo "993/tcp" ;; '"pop3s"') echo "995/tcp" ;; *) echo "other" esac } # Given a port from PERMIT, return a service name. get_sstr() { case "$1" in '21/tcp') echo "FTP [21/tcp]" ;; '22/tcp') echo "SSH [22/tcp]" ;; '25/tcp') echo "SMTP [25/tcp]" ;; '53') echo "DNS [53/udp 53/tcp]" ;; '79/tcp') echo "FINGER [79/tcp]" ;; '80/tcp') echo "HTTP [80/tcp]" ;; '110/tcp') echo "POP3 [110/tcp]" ;; '113/tcp') echo "AUTH [113/tcp]" ;; '143/tcp') echo "IMAP [143/tcp]" ;; '443/tcp') echo "HTTPS [443/tcp]" ;; '514/udp') echo "SYSLOG [514/udp]" ;; '515/tcp') echo "LPD [515/tcp]" ;; '993/tcp') echo "IMAPS [993/tcp]" ;; '995/tcp') echo "POP3S [995/tcp]" ;; *) echo "PORT $1" # other esac } # Check dialog version. if (( `which dialog 2>&1 | grep -c "which: no dialog in"` )); then echo "Required program 'dialog' not found." exit 1 fi DIALOG_VERSION=`dialog --version 2>&1` if (( `echo "$DIALOG_VERSION" | grep -c "0.9b"` )); then DEFAULT_NO="--defaultno" NO_CANCEL="--nocancel" CANCEL_BACK="--cancel-label Back" CANCEL_QUIT="--cancel-label Quit" elif (( `echo "$DIALOG_VERSION" | grep -c "0.9a"` )); then DEFAULT_NO="--defaultno" NO_CANCEL="--nocancel" CANCEL_BACK="" CANCEL_QUIT="" else DEFAULT_NO="" NO_CANCEL="" CANCEL_BACK="" CANCEL_QUIT="" fi # Begin installer. while [ "$status" != "exit" ]; do case "$status" in 'welcome') dialog --title "Linux Firewall Configuration Utility" $CANCEL_QUIT \ --menu "Welcome to installer version $GUI_VERSION for Linux Firewall version $FW_VERSION. You can abort this installation at any time by pressing the [ESC] key. Please select your desired installation type below. The default installation will close all ports so that no services will be available to remote hosts. A custom installation will allow you to configure remote access and provide an opportunity to enable Internet connection sharing for hosts on an attached private network." 18 55 2 \ "default" "Default Installation" \ "custom" "Custom Installation" 2> $TMPFILE if [ $? != 0 ]; then goodbye; fi if [ "`cat $TMPFILE`" == "default" ]; then status="writefile" else status="portlist" fi ;; 'portlist') dialog --title "Open Ports" --checklist "Below is a list of common services available on Linux systems. Using the space bar, select the services ** running on this machine ** you wish to make available to remote hosts. In the next section you will be given a chance to specify who is allowed to connect to each service. Afterwards you will be given an opportunity to specify hosts and networks allowed to bypass the firewall altogether." 25 55 10 \ "ftp" "File Transfer Protocol [21/tcp]" off \ "ssh" "Secure Shell [22/tcp]" on \ "smtp" "Incoming Email (sendmail) [25/tcp]" off \ "dns" "Domain Name Service [53/udp & 53/tcp]]" off \ "finger" "Finger Service [79/tcp]" off \ "http" "Web Server [80/tcp]" off \ "pop3" "POP3 mail server [110/tcp]" off \ "auth" "Ident Auth service [113/tcp]" off \ "imap" "IMAP mail server [143/tcp]" off \ "https" "Secure Web Server [443/tcp]" off \ "syslog" "Remote System Logging [514/udp]" off \ "lpd" "LPR Print Spooler [515/tcp]" off \ "imaps" "Secure IMAP mail server [993/tcp]" off \ "pop3s" "Secure POP3 mail server [995/tcp]" off \ "other" "other port(s) not listed" off 2> $TMPFILE status=$? if [ "$status" == "255" ]; then goodbye elif [ "$status" == "0" ]; then permit_opt="" for option in `cat $TMPFILE` ; do option=`get_pstr $option` if [ "$option" == "other" ]; then status="otherports" else permit_opt="$permit_opt $option" fi done if [ "$status" != "otherports" ]; then status="openports" fi else status="natquestion" fi ;; 'otherports') dialog $CANCEL_BACK --title "Specify Open Ports" --inputbox "Numerically list additional ports or port ranges available to other connecting hosts. In the next section you will be given a chance to specify who is allowed to connect to each port or port range. Protocols 'tcp' and 'udp' can optionally be specified here. If no protocol is specified, then connections to either protocol will be accepted. Format: <port or port-range>[/<protocol>] Example: \"901/tcp 92 2400-2500/tcp\" This will open up TCP port 901, port 92 for both TCP and UDP, and TCP ports 2400 through 2500." \ 19 55 2> $TMPFILE status=$? if [ "$status" == "255" ]; then goodbye elif [ "$status" == "0" ]; then status="openports" permit_opt="$permit_opt `cat $TMPFILE`" else status="portlist" fi ;; 'openports') option="" portnum=`echo $permit_opt | wc` portnum=`echo $portnum | cut -f 2 -d ' '` curport=0 for port in $permit_opt ; do curport=`expr $curport + 1` portstr=`get_sstr $port` if [ -n "$LOCAL_NETWORK" ]; then dialog $NO_CANCEL --title "Port $curport of $portnum - $portstr" --menu "Who can access $portstr?" 10 55 3 \ "any" "Allow from anywhere" \ "$SHORT_NETWORK_NAME" "Allow from $LONG_NETWORK_NAME" \ "specify" "Specify Access" 2> $TMPFILE else dialog $NO_CANCEL --title "Port $curport of $portnum - $portstr" --menu "Who can access $portstr?" 9 55 2 \ "any" "Allow from anywhere" \ "specify" "Specify Access" 2> $TMPFILE fi status=$? if [ "$status" == "255" ]; then goodbye elif [ "$status" == "0" ]; then case "`cat $TMPFILE`" in 'any') option="$option $port" ;; "$SHORT_NETWORK_NAME") for net in $LOCAL_NETWORK ; do option="$option $net:$port" done ;; 'specify') status="loop" while [ "$status" == "loop" ]; do dialog $NO_CANCEL --title "Specify access to $portstr" --inputbox "Please specify which hosts and/or networks may connect to $portstr by entering a space-delimited list of hosts and/or networks. Format: <host or network address>[/<netmask>] Example: \"207.198.61.33 198.82.0.0/16\"" \ 13 55 2> $TMPFILE status=$? if [ "$status" == "255" ]; then goodbye elif [ "$status" == "0" ]; then for combo in `cat $TMPFILE` ; do if [ "X`echo $combo | cut -s -f 1 -d '/'`" == "X" ]; then option="$option $combo:$port" status="not a loop" else host=`echo $combo | cut -s -f 1 -d '/'` mask=`echo $combo | cut -s -f 2 -d '/'` newmask=`make_mask $mask` if [ "$newmask" == "-1" ]; then dialog --title "Invalid Bitmask" --msgbox "The host/netmask you specified (${host}/${mask}) was invalid. Re-enter the full list of hosts and/or networks for port ${portstr}." \ 7 55 status=$? if [ "$status" == "255" ]; then goodbye else status="loop" fi else option="$option ${host}/${newmask}:$port" status="not a loop" fi fi done fi done ;; *) esac fi done permit_opt=`echo $option` status="natquestion" ;; 'natquestion') dialog --title "Internet Connection Sharing" $DEFAULT_NO --yesno "Do you wish to share your Internet connection with a private internal network?" \ 6 55 status=$? if [ "$status" == "255" ]; then goodbye elif [ "$status" == "0" ]; then dialog $CANCEL_BACK --title "List Internal Interfaces" --inputbox "Enter one or more ethernet interfaces connected to private internal networks in a space delimited list. Example: \"eth1 eth2\"" \ 9 55 2> $TMPFILE status=$? if [ "$status" == "255" ]; then goodbye elif [ "$status" == "0" ]; then int_iface_opt=`cat $TMPFILE` if [ -n "$int_iface_opt" ]; then dialog --title "Dial-up Information" $DEFAULT_NO --yesno "Does this system access the Internet through a telephone dial-up modem? This information is required in order to configure Internet connection sharing and will not effect your Internet access in any way." \ 9 55 status=$? if [ "$status" == "255" ]; then goodbye elif [ "$status" == "0" ]; then dyn_iface_opt="ppp0" fi fi status="trustednet" else status="natquestion" fi else status="trustednet" fi ;; 'trustednet') if [ "X$int_iface_opt" == "X" ]; then xtratxt="" height="14" else xtratxt=" (besides existing private internal networks)" height="15" fi status="loop" while [ "$status" == "loop" ]; do dialog --title "Trusted Networks" --inputbox "If there are any hosts or networks${xtratxt} that should be able to bypass the firewall altogether and connect to any services running on this system, please list them here. This might include hosts allowed to connect here for administrative purposes. Format: <host or network address>[/<netmask>] Example: \"207.198.61.33 128.173.0.0/16\"" \ $height 55 2> $TMPFILE status=$? if [ "$status" == "255" ]; then goodbye elif [ "$status" == "0" ]; then for combo in `cat $TMPFILE` ; do if [ "X`echo $combo | cut -s -f 1 -d '/'`" == "X" ]; then option="$permit_opt $combo" permit_opt=`echo $option` status="not a loop" else host=`echo $combo | cut -s -f 1 -d '/'` mask=`echo $combo | cut -s -f 2 -d '/'` newmask=`make_mask $mask` if [ "$newmask" == "-1" ]; then dialog --title "Invalid Bitmask" --msgbox "The host/netmask you specified (${host}/${mask}) was invalid. Re-enter the complete full-access list." \ 7 55 status=$? if [ "$status" == "255" ]; then goodbye status="loop" fi else option="$permit_opt ${host}/${newmask}" permit_opt=`echo $option` status="not a loop" fi fi done fi done status="writefile" ;; 'debug') echo "PERMIT: $permit_opt" echo "INTERNAL_INTERFACES: $int_iface_opt" echo "DYNAMIC_INTERFACES: $dyn_iface_opt" read junk status="writefile" ;; 'test') dialog --title "System Configuration Testing" --yesno "Your firewall is now ready to be installed. Would you like to verify your system configuration first? This is a recommended step if this is the first time you are installing a firewall on this host. The testing procedure will not modify your current firewall configuration. Note that this opperation may take some time depending on the speed of your computer and the complexity of your firewall configuration." \ 13 55 status=$? if [ "$status" == "255" ]; then goodbye elif [ "$status" == "0" ]; then clear echo "Running './rc.firewall check'. Output will follow ..." echo #BK changed sh to bash... bash $FW_TMPFILE check status=$? if [ "$status" != "0" ]; then echo echo "Errors were detected in your system configuration." echo "See the output above for specific details." echo echo "A copy of the Linux Firewall initialization script preconfigured by this" echo "program is located in $FW_TMPFILE" echo rm -f $TMPFILE > /dev/null 2>&1 exit 1 fi echo echo -n "Press any key to continue ... " read -rsn1 fi status="install" ;; 'install') dialog --title "Firewall Installation" --yesno "The firewall is now ready to be enabled. Your system configuration will also be modified so that the firewall will be started each time your computer is booted. If you choose not to continue, a copy of the Linux Firewall initialization script, preconfigured by this program, can be found here: '$FW_TMPFILE'. Would you like to continue?" \ 12 55 status=$? if [ "$status" == "255" ]; then goodbye elif [ "$status" == "0" ]; then if [ -f $FW_INSTALL ]; then mv $FW_INSTALL ${FW_INSTALL}.old fi mv $FW_TMPFILE $FW_INSTALL status=$? if [ "$status" != "0" ]; then clear echo "INSTALLATION FAILED with the following message:" echo echo "\"Unable to write file to $FW_INSTALL.\"" echo "A copy of the Linux Firewall initialization script preconfigured by this" echo "program is located in $FW_TMPFILE." echo rm -f $TMPFILE > /dev/null 2>&1 exit 1 fi if [ -f /etc/rc.d/rc.local ]; then grep $FW_INSTALL /etc/rc.d/rc.local > /dev/null 2>&1 || cat << EOF >> /etc/rc.d/rc.local if [ -x $FW_INSTALL ]; then $FW_INSTALL $INIT fi EOF clear if [ "$INIT" == "fast" ]; then echo "$FW_INSTALL save" echo $FW_INSTALL save echo fi echo "$FW_INSTALL $INIT" echo $FW_INSTALL $INIT echo echo " *** Installation Complete ***" echo echo "The firewall is now running on your system. The firewall initialization" echo "script has been installed here: $FW_INSTALL" echo "and will run each time you boot your system. Advanced users can modify their" echo "firewall configuration by configuring the above file with any text editor." echo "After making changes you will need to run the rc.firewall script again for" echo "changes to take effect." echo echo "For more information, please visit:" echo echo " http://projectfiles.com/firewall/" echo rm -f $TMPFILE > /dev/null 2>&1 exit else clear echo "INSTALLATION FAILED with the following message:" echo echo "\"Unable to write information to /etc/rc.d/rc.local. If your distribution does" echo "not have an /etc/rc.d/rc.local (e.i. debian) then bug us to add support for" echo "your distribution.\"" echo echo "A copy of the Linux Firewall initialization script preconfigured by this" echo "program is located in $FW_TMPFILE." echo rm -f $TMPFILE > /dev/null 2>&1 exit 1 fi fi status="exit" ;; 'writefile') ### FOR INTERNAL USE. ### Place the following AFTER the escaped firewall script ... #FIREWALL_END_OF_FILE # # chmod $FW_PERM $FW_TMPFILE # status="test" # ;; # # *) # goodbye # esac #done # #goodbye ### Add in the following variables in the config section: ### permit_opt, int_iface_opt, and dyn_iface_opt cat << FIREWALL_END_OF_FILE > $FW_TMPFILE #!/bin/bash # # rc.firewall Linux Firewall version 2.0rc9 -- 05/02/03 # http://projectfiles.com/firewall/ # # Copyright (C) 2001-2003 Scott Bartlett <srb@mnsolutions.com> # # 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: <port or port-range>[/<protocol>] # 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: <host or network address>[/<netmask>] # 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:<host or network address>[/<netmask>]:<port or port-range>[/<protocol>] # Example: PERMIT="198.82.0.0/16:80/tcp" -- (Allow web traffic from 198.82.*.*) PERMIT="$permit_opt" # 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="$int_iface_opt" # 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="$dyn_iface_opt" # 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.com/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.com 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. #BK commented out... #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.com/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.com/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.com/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.com/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! FIREWALL_END_OF_FILE chmod $FW_PERM $FW_TMPFILE status="test" ;; *) goodbye esac done goodbye