#!/bin/sh # # firewall Configures Linux firewall services # # # chkconfig: 345 11 89 # description: Configure firewalling and ip forwarding using Linux 2.4's # netfilter. # Source functions test -e /etc/rc.d/init.d/functions && { . /etc/rc.d/init.d/functions } || { action() { echo "$1" shift sh -c "$@" } } # Changelog: # 2001/12/12: Fix MASQ # 2001/08/23: Added UDP to do_port_forward() # 2001/08/21: Fixed the FORWARD policy # 2001/02/26: Added the ip_conntrack* modules to the list of required NAT # modules. # # # IPTABLES="/sbin/iptables" IFCONFIG="/sbin/ifconfig" ARP="/sbin/arp" # # All of the following variables accept space separated lists of items # # SPOOF_PROTECTION can be set to a device name, or "ALL". This will enable # the Linux kernel's IP spoofing protection on the named devices. SPOOF_PROTECTION_ON="ALL" # PARANOID_DEV and PARANOID_ADDR allow you to specify interfaces which should # be as protected as possible. This should include all interfaces which are # open to the internet at large, like "ppp0" for dial up users. These # interfaces will have all ports under 1024 closed, as well as 6000-6010. # # Under some situations, specifying a dev doesn't work well, particularly on # routers. In other cases, like web servers with many addr's on a single # interface, the device name is much simpler. Either is available, most # users will list the name of their publicly accessible device here. # # To make a given service available to the internet, you must specifically # open that port using PARANOIA_ALLOWS_PORTS. The example only opens port # 22 for ssh. # PARANOIA_EXTRA_PORTS can be used to close specific ports in addition to # those normally closed. The example closes ports 2049 (nfs), 3306 (MySQL), # 5432 (PostgreSQL), 7100 (xfs), and 8000 (junkbuster). It's common to run # these services on a Linux box for internal use, but usually users on the # internet have no business accessing them. PARANOID_DEV="eth1" #PARANOID_ADDR="192.168.0.2" PARANOIA_ALLOWS_PORTS="22" PARANOIA_EXTRA_PORTS="2049 3306 5432 7100 8000" # MASQ_NET allows you to specify hosts or networks that should be masqueraded. # Users who wish to masqerade their internal networks should set this to the # network number and netmask of their internal network. MASQ_NET="192.168.1.0/24" # FORWARD_NET allows you to specify networks whose IP traffic will be # forwarded/routed. Users who wish to act as a standard router for any network # blocks should list those network numbers and netmasks here. Note that this # script does not provide for the protection of the hosts on these networks. # If you have hosts with publicly routable IP's, then you should either add # rules to this script, or run firewalls on those machines, as well. #FORWARD_NET="192.168.10.0/24" # Proxy arp addresses specifies addresses of machines that reside behind # the firewall which you want to transparently firewall using the proxy # arp features of Linux. By doing this, the firewall will advertise that # it owns the listed ip address to the outside world, and forward packets # recieved to the internal network. Make sure that you have routes to # the internal IP's set properly. # You can control access to the internal IP's using the HOSTS_ALLOW # settings. # According to the "arp" man page, this should be done automatically. # I haven't seen it happen yet. If I'm wrong, then I'll remove this # section. # PROXY_ARP="eth0-192.168.0.5" # IP Virtual Servers: # #VIRTUAL_SERVER="63.164.112.16-192.168.11.10 # 63.164.112.3-192.168.11.3" # This is a little weird, but I wanted to provide a simple way to # do it, so here's the best you get: # format: local_ip(local_port)-remote_ip(remote_port) # e.g.: 192.168.0.2(80)-192.168.1.5(80) # # In this example, 192.168.0.2 is the address of the interface that the # internet can connect to (I use a DSL modem that does NAT, which is why # that looks funny). 192.168.1.5 is the address of the machine inside # my private network that I want to forward traffic to. If you wanted # to be able to ssh directly to one of your internal hosts, you might use # something like "192.168.0.2(5155)-192.168.1.5(22)". From outside your # network, you could do "ssh -p 5155 name.of.my.host.org", and a connection # would be established to 192.168.1.5, inside your private network. # This only works to hosts that you are masquerading. # #PORT_FORWARDS="192.168.0.2(5155)-192.168.1.5(22)" # These rules allow you to specify additional rules for host based access # control. These rules are similar to those for port forwarding, above. # format: remote_ip(remote_port)-local_ip(local_port) # # To allow 232.123.123.6 to access all privliged ports, even on paranoid # devices, 232.123.123.5 to access rsh, but only if the connection came from # a secure port (under 1024), and deny all access to 232.123.123.3, use the # following: #HOSTS_ALLOW="232.123.123.6()-192.168.0.2(:1024) # 232.123.123.5(:1024)-192.168.0.2(514)" #HOSTS_DENY="232.123.123.3()-192.168.0.2()" # # # ifconfig_get_netmask() { $IFCONFIG $1 | awk '{if (/Mask/) {gsub("Mask:", "", $4); print $4}}' } ifconfig_get_broadcast() { $IFCONFIG $1 | awk '{if (/Bcast/) {gsub("Bcast:", "", $3); print $3}}' } configure_system() { # This doesn't autoload: action "Loading ip_tables module" modprobe ip_tables # Turn on Source Address Verification and get # spoof protection on all current and future interfaces. if [ -e /proc/sys/net/ipv4/conf/all/rp_filter ] ; then if [ "$SPOOF_PROTECTION_ON" = "ALL" ]; then echo -n "Setting up IP spoofing protection..." for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 1 > $f done echo "done" fi else echo "SPOOF PROTECTION NOT AVAILABLE ON THIS SYSTEM." fi # # Flush the old rules, so that we don't duplicate them. # This is important if the rules have changed. # action "Flushing old firewalling rules" $IPTABLES -F if [ ! -f /proc/sys/net/ipv4/ip_forward ] ; then echo "/proc/sys/net/ipv4/ip_forward is missing --" \ "cannot control IP forwarding" >&2 return 1 fi # # All of the following is routing related. There is no need # to continue if there are no routing rules specified # if [ -z "${MASQ_NET}" -a -z "${FORWARD_NET}" ] ; then return 0 fi if [ 1 != "`cat /proc/sys/net/ipv4/ip_forward`" ]; then echo "Routing has not been enabled." >&2 if [ -e /etc/sysctl.conf ] ; then echo "Set net.ipv4.ip_forward and net.ipv4.ip_always_defrag = 1 " >&2 echo " in /etc/sysctl.conf" >&2 else echo "Please set FORWARD_IPV4=\"yes\" in /etc/sysconfig/network" >&2 fi echo " or use your network configuration tool to enable ip forwarding." >&2 return 1 fi action "Flushing forwarded ports" $IPTABLES -F -t nat # # Set the default for packet forwarding to REJECT. We only want to # forward packets for those in our own network. # action "Denying packet forwarding by default" \ $IPTABLES -P FORWARD DROP # Load all available ip_masq modules. Newer modutils packages # will not modprobe if the given argument has the # trailing ".o", so strip it off with sed. if [ -n "${MASQ_NET}" ] ; then pushd /lib/modules/`uname -r`/kernel/net/ipv4/netfilter/ >/dev/null action "Loading iptables NAT module" modprobe iptable_nat ls ip_nat* ip_conntrack* | sed 's/.o$//' | while read masqmod ; do action "Loading masquerade module $masqmod " \ modprobe "$masqmod" done popd >/dev/null fi } lock_down() { DEST="$1 $2" action "Disallowing incoming connections on $2" \ $IPTABLES -A INPUT $DEST \ -p tcp --destination-port :1023 --syn -j REJECT $IPTABLES -A INPUT $DEST \ -p udp --destination-port :1023 -j REJECT $IPTABLES -A INPUT $DEST \ -p tcp --destination-port 6000:6010 --syn -j REJECT $IPTABLES -A INPUT $DEST \ -p udp --destination-port 6000:6010 -j REJECT [ -n "$PARANOIA_EXTRA_PORTS" ] && for PORTS in $PARANOIA_EXTRA_PORTS; do action " including extra port $PORTS" \ $IPTABLES -A INPUT $DEST \ -p tcp --destination-port "$PORTS" --syn -j REJECT $IPTABLES -A INPUT $DEST \ -p udp --destination-port "$PORTS" -j REJECT done [ -n "$PARANOIA_ALLOWS_PORTS" ] && for PORTS in $PARANOIA_ALLOWS_PORTS; do action " except for port $PORTS" \ $IPTABLES -I INPUT 1 $DEST \ -p tcp --destination-port "$PORTS" --syn -j ACCEPT $IPTABLES -I INPUT 1 $DEST \ -p udp --destination-port "$PORTS" -j ACCEPT done [ -e /proc/sys/net/ipv4/conf/all/rp_filter ] && for DEV in "$SPOOF_PROTECTION_ON"; do [ "$DEV" = "$2" ] && action "Setting up IP spoofing protection on $2" \ echo 1 > /proc/sys/net/ipv4/conf/"$2"/rp_filter done } do_hosts_deny() { ARG_DENY=$1 LOCAL_DENY=`echo $ARG_DENY | cut -f2 -d-` REMOTE_DENY=`echo $ARG_DENY | cut -f1 -d-` LOCAL_IP=`echo $LOCAL_DENY | sed "s/(.*)//g"` LOCAL_PORT=`echo $LOCAL_DENY | sed "s/.*(\|)//g"` REMOTE_IP=`echo $REMOTE_DENY | sed "s/(.*)//g"` REMOTE_PORT=`echo $REMOTE_DENY | sed "s/.*(\|)//g"` action " removing access from $REMOTE_IP $REMOTE_PORT to $LOCAL_IP $LOCAL_PORT" \ $IPTABLES -I INPUT 1 -p tcp \ -s $REMOTE_IP --sport $REMOTE_PORT \ -d $LOCAL_IP --dport $LOCAL_PORT -j REJECT $IPTABLES -I INPUT 1 -p udp \ -s $REMOTE_IP --sport $REMOTE_PORT \ -d $LOCAL_IP --dport $LOCAL_PORT -j REJECT } do_hosts_allow() { ARG_ALLOW=$1 LOCAL_ALLOW=`echo $ARG_ALLOW | cut -f2 -d-` REMOTE_ALLOW=`echo $ARG_ALLOW | cut -f1 -d-` LOCAL_IP=`echo $LOCAL_ALLOW | sed "s/(.*)//g"` LOCAL_PORT=`echo $LOCAL_ALLOW | sed "s/.*(\|)//g"` REMOTE_IP=`echo $REMOTE_ALLOW | sed "s/(.*)//g"` REMOTE_PORT=`echo $REMOTE_ALLOW | sed "s/.*(\|)//g"` action " allowing $REMOTE_IP $REMOTE_PORT to access $LOCAL_IP $LOCAL_PORT" \ $IPTABLES -I INPUT 1 -p tcp \ -s $REMOTE_IP --sport $REMOTE_PORT \ -d $LOCAL_IP --dport $LOCAL_PORT -j ACCEPT $IPTABLES -I INPUT 1 -p udp \ -s $REMOTE_IP --sport $REMOTE_PORT \ -d $LOCAL_IP --dport $LOCAL_PORT -j ACCEPT } masq_network() { ARG_MASQ_NET=$1 forward_network "$ARG_MASQ_NET" action "Activating masquerading for network $ARG_MASQ_NET" \ $IPTABLES -t nat -A POSTROUTING -s $ARG_MASQ_NET -d 0/0 -j MASQUERADE } forward_network() { ARG_FWD_NET=$1 action "Allowing network $ARG_FWD_NET to be forwarded" \ $IPTABLES -A FORWARD -s $ARG_FWD_NET -d 0/0 -j ACCEPT $IPTABLES -A FORWARD -d $ARG_FWD_NET -s 0/0 -j ACCEPT } do_port_forward() { ARG_PORT_FORWARD=$1 LOCAL_F=`echo $ARG_PORT_FORWARD | cut -f1 -d-` REMOTE_F=`echo $ARG_PORT_FORWARD | cut -f2 -d-` LOCAL_IP=`echo $LOCAL_F | sed "s/(.*)//g"` LOCAL_PORT=`echo $LOCAL_F | sed "s/.*(\|)//g"` REMOTE_IP=`echo $REMOTE_F | sed "s/(.*)//g"` REMOTE_PORT=`echo $REMOTE_F | sed "s/.*(\|)//g"` action "Forwarding $LOCAL_F tcp to $REMOTE_F" \ $IPTABLES -A PREROUTING -t nat -p tcp \ -d "$LOCAL_IP" --dport "$LOCAL_PORT" -j DNAT --to "$REMOTE_IP":"$REMOTE_PORT" action "Forwarding $LOCAL_F udp to $REMOTE_F" \ $IPTABLES -A PREROUTING -t nat -p udp \ -d "$LOCAL_IP" --dport "$LOCAL_PORT" -j DNAT --to "$REMOTE_IP":"$REMOTE_PORT" } do_virtual_server() { ARG_VS=$1 PUBLIC_IP=`echo $ARG_VS | cut -f1 -d-` INTERNAL_IP=`echo $ARG_VS | cut -f2 -d-` action "Setting up $PUBLIC_IP as virtual server to $INTERNAL_IP" \ $IPTABLES -A PREROUTING -t nat \ -d "$PUBLIC_IP" -j DNAT --to-destination "$INTERNAL_IP" $IPTABLES -A POSTROUTING -t nat \ -s "$INTERNAL_IP" -j SNAT --to-source "$PUBLIC_IP" } do_proxy_arp() { ARG_PROXY_ARP=$1 LOCAL_IF=`echo $ARG_PROXY_ARP | cut -f1 -d-` REMOTE_IP=`echo $ARG_PROXY_ARP | cut -f2 -d-` LOCAL_MAC=`$IFCONFIG $LOCAL_IF | grep HWaddr | sed 's/.*HWaddr //'` action "Adding proxy arp entry for $REMOTE_IP on $LOCAL_IF" \ $ARP -i $LOCAL_IF -s $REMOTE_IP $LOCAL_MAC pub } do_not_proxy_arp() { ARG_PROXY_ARP=$1 LOCAL_IF=`echo $ARG_PROXY_ARP | cut -f1 -d-` REMOTE_IP=`echo $ARG_PROXY_ARP | cut -f2 -d-` action "Deleting proxy arp entry for $REMOTE_IP on $LOCAL_IF" \ $ARP -i $LOCAL_IF -d $REMOTE_IP pub } #----------------------- case "$1" in start) configure_system [ -n "$PARANOID_DEV" ] && for PD in $PARANOID_DEV; do lock_down -i $PD done [ -n "$PARANOID_ADDR" ] && for PD in $PARANOID_ADDR; do lock_down -d $PD done [ -n "$HOSTS_ALLOW" ] && for ALLOW in $HOSTS_ALLOW; do do_hosts_allow $ALLOW done [ -n "$HOSTS_DENY" ] && for DENY in $HOSTS_DENY; do do_hosts_deny $DENY done [ -n "$MASQ_NET" ] && for MN in $MASQ_NET; do masq_network $MN done [ -n "$FORWARD_NET" ] && for FN in $FORWARD_NET; do forward_network $FN done [ -n "$PORT_FORWARDS" ] && for PF in $PORT_FORWARDS ; do do_port_forward $PF done [ -n "$VIRTUAL_SERVER" ] && for VS in $VIRTUAL_SERVER ; do do_virtual_server $VS done [ -n "$PROXY_ARP" ] && for PA in $PROXY_ARP ; do do_proxy_arp $PA done ;; stop) action "Flushing old firewalling rules" $IPTABLES -F $IPTABLES -P FORWARD ACCEPT action "Flushing forwarded ports" $IPTABLES -F -t nat [ -n "$PROXY_ARP" ] && for PA in $PROXY_ARP ; do do_not_proxy_arp $PA done ;; status) echo "Current firewalling rules are:" ; $IPTABLES -L if [ -n "${MASQ_NET}" ] ; then echo ; $IPTABLES -L -t nat ; fi ;; restart) $0 stop $0 start ;; *) echo "Usage: firewall {start|stop|restart|status}" exit 1 esac