#!/bin/sh # @(#) netmasq runs a masquerading firewall carl@carltm.com # Netmasq needs to be configured before you can run it. # Read the /usr/share/doc/netmasq-*/README file for more information. # Copyright 2005, 2008, Carl T. Miller, All Rights Reserved # This software comes with absolutely no warranties, and it is released under # the GNU General Public License. See /usr/share/doc/netmasq-*/license VersionNumber=3.4.3 trap "" 2 Version=netmasq-$VersionNumber Cmd=`basename $0` DocDir=/usr/share/doc/$Version Readme=$DocDir/README NetmasqDir=${NetmasqDir:=/etc/netmasq} ConfFile=${ConfFile:=$NetmasqDir/netmasq.conf} Ifconfig=/sbin/ifconfig Iptables=/sbin/iptables Modprobe=/sbin/modprobe ModuleDir=/lib/modules/`uname -r`/kernel/net/ipv4/netfilter if [ -f $ConfFile ] then . $ConfFile else cat >&2 << EoT $Cmd will not run until you configure it. Read $Readme You'll need to edit $ConfFile and create a .conf file in $NetmasqDir for each live interface. EoT fi PAGER=${PAGER:=more} LogPrefix=${LOG_PREFIX:="netmasq"} LogRate=${LOG_RATE:=6/hour} LogBurst=${LOG_BURST:=12} AllMods=${ALL_MODS:=yes} DynamicIp=${DYNAMIC_IP:=yes} BlockUnusedIp=${BLOCK_UNUSED_IP:=yes} Log="--match limit --limit $LogRate --limit-burst $LogBurst -j LOG" echo $LogRate | grep ^0/ >/dev/null && Log= V=${Verbosity:=0} find $NetmasqDir -exec chown root:root {} \; find $NetmasqDir -exec chmod 700 {} \; usage () { cat << EoT $Cmd: usage: $Cmd -h read this message $Cmd begin masquerading/firewall $Cmd -q quit masquerading/firewall (this removes all protections) $Cmd -L list all rules in all tables $Cmd -v set verbosity level, more v's means more verbose More info is available in $Readme EoT } mac () { echo -n; } svc () { echo -n; } rmt () { echo -n; } portfw () { echo -n; } icmp_block () { echo -n; } if echo $V | grep '[^0-9]' > /dev/null then echo "$Cmd: \$Verbosity must be a single digit." >&2; usage fi if [ "$1" = '-L' ] then for Table in `cat /proc/net/ip_tables_names|tac`; do echo; echo "Table: $Table" $Iptables -t $Table -L -n -v |\ sed 's/ *[pkts0-9KMG]* *[bytes0-9KMG]* */ /' done | $PAGER exit fi flush () { for Table in `cat /proc/net/ip_tables_names`; do $Iptables -t $Table -F done for Table in `cat /proc/net/ip_tables_names`; do $Iptables -t $Table -X done } while getopts :qv OPTION; do case $OPTION in q) echo -n Removing all firewall and masquerading services... flush echo done. echo Run $Cmd to restart services. exit;; v) V=`expr $V + 1`;; h) usage; exit;; *) usage; exit;; esac done shift `expr $OPTIND - 1` [ "$V" -gt 0 ] && echo netmasq $VersionNumber [ "$V" -gt 0 ] && echo '(c) Copyright 2005, 2008, Carl T. Miller, All Rights Reserved' [ "$V" -gt 1 ] && echo if ! cd $NetmasqDir then echo "Can't cd to the $NetmasqDir directory. Reinstall netmasq as root.">&2 exit 1 fi if ! which $Iptables > /dev/null 2>&1 then echo "$Cmd: $Iptables was not found in the path:" >&2 echo "$PATH" >&2 exit 2 fi NoConfig () { cat $NetmasqDir/default.conf | sed "s/default/$1/g" > $NetmasqDir/$1.conf chown root:root $NetmasqDir/$1.conf chmod 700 $NetmasqDir/$1.conf echo A new configuration file was created for interface $1. >&2 echo Edit $NetmasqDir/$1.conf as needed and rerun netmasq. >&2 [ -f $NetmasqDir/$1.conf_pre_$VersionNumber ] && \ echo The former file was saved as $NetmasqDir/$1.conf_pre_$VersionNumber >&2 } IfaceList=`$Ifconfig | grep -v '^ ' | grep -v ^$ | cut -d" " -f1 | grep -v :` for Iface in $IfaceList; do [ -f $NetmasqDir/$Iface.conf ] || NoConfig $Iface done CleanData () { sed 's/[ ][ ]*/ /g' | sed 's/^ //' | sed 's/[;#].*//' | grep -v '^$' } [ "$V" -gt 2 ] && echo General configuration: [ "$V" -gt 2 ] && echo # load modules if [ ! -d $ModuleDir ] then echo "The netfilter modules are not located in:" >&2 echo "$ModuleDir" >&2 echo "Perhaps you are not running a 2.4 or 2.6 kernel?" >&2 fi if [ "$AllMods" = yes ] then #available modules are in /lib/modules/`uname -r`/kernel/net/ipv4/netfilter [ "$V" -gt 0 ] && echo -n Loading all netfilter modules... [ "$V" -gt 3 ] && echo ls $ModuleDir |\ sed 's/.gz$//' |\ sed 's/.ko$//' |\ sed 's/.o$//' |\ egrep -v "^ipchains$|^ipfwadm$" |\ while read Mod; do [ "$V" -gt 3 ] && echo " $Mod" $Modprobe $Mod done [ "$V" -gt 3 ] && echo -n "Netfilter modules " [ "$V" -gt 0 ] && echo done. else [ "$V" -gt 0 ] && echo Loading connection tracking modules... [ "$V" -gt 3 ] && echo ls $ModuleDir | \ sed 's/.gz$//' | sed 's/.o$//' |\ grep -v ^ipchains$ | grep -v ^ipfwadm$ | grep ^ip_conntrack |\ while read Mod; do [ "$V" -gt 3 ] && echo " $Mod" $Modprobe $Mod done [ "$V" -gt 3 ] && echo -n "Connection tracking modules " [ "$V" -gt 0 ] && echo done. fi # let kernel know if IP addr is not static [ "$DynamicIp" = yes ] && echo 1 > /proc/sys/net/ipv4/ip_dynaddr # turn off forwarding while firewall loads [ "$V" -gt 0 ] && \ echo IP forwarding is disabled until configuration is complete. echo 0 > /proc/sys/net/ipv4/ip_forward # flush everything and delete all existing user tables [ "$V" -gt 0 ] && echo -n Deleting current filtering rules... flush [ "$V" -gt 0 ] && echo done. # setup and configuration for each live interface [ "$V" -gt 2 ] && echo [ "$V" -gt 2 ] && echo Interface configuration: for Iface in $IfaceList; do [ "$V" -gt 1 ] && echo [ "$V" -gt 0 ] && echo Configuring interface $Iface... IP=`$Ifconfig $Iface | grep inet | sed s/.*addr:// | cut -d" " -f1` NET=$IP/`$Ifconfig $Iface|grep Mask| sed s/.*Mask:// | cut -d" " -f1` [ "$V" -gt 2 ] && echo " IP/Network: $NET" unset AUTH_IP_PORT Config=`CleanData < $NetmasqDir/$Iface.conf` . $NetmasqDir/$Iface.conf if echo "$FIREWALL" | grep -i no >/dev/null then [ "$V" -gt 0 ] && echo " no firewall for $Iface" else [ "$V" -gt 0 ] && echo " setting up firewall for $Iface" [ "$V" -gt 1 ] && echo " preventing IP spoofing" echo 1 > /proc/sys/net/ipv4/conf/$Iface/rp_filter # setup MAC address authentication if [ $AUTH_IP_PORT ] then if touch $MAC_AUTH_FILE && chown $MAC_AUTH_FILE_OWNER:$MAC_AUTH_FILE_GROUP $MAC_AUTH_FILE && chmod 660 $MAC_AUTH_FILE then [ "$V" -gt 1 ] && echo " requiring MAC authentication" $Iptables -t mangle -N mactest_$Iface # process banned MAC addresses if [ -f bannedmac.conf ] then [ "$V" -gt 0 ] && echo -n " loading banned MAC addresses..." [ "$V" -gt 2 ] && echo CleanData < bannedmac.conf |\ while read Addr; do [ "$V" -gt 2 ] && echo " $Addr" [ "$Log" ] && $Iptables -t mangle -A mactest_$Iface -m mac \ --mac-source $Addr $Log --log-prefix "$LogPrefix:mac:banned: " $Iptables -t mangle -A mactest_$Iface -j MARK --set-mark 1 $Iptables -t mangle -A mactest_$Iface -j RETURN done [ "$V" -gt 2 ] && echo -n " banned MAC addresses " [ "$V" -gt 0 ] && echo done else [ "$V" -gt 0 ] && echo " no MAC addresses banned" fi # process trusted MAC addresses if [ -f trustedmac.conf ] then [ "$V" -gt 0 ] && echo -n " loading trusted MAC addresses..." [ "$V" -gt 2 ] && echo CleanData < trustedmac.conf |\ while read Addr; do [ "$V" -gt 2 ] && echo " $Addr" [ "$Log" ] && $Iptables -t mangle -A mactest_$Iface -m mac \ --mac-source $Addr $Log --log-prefix "$LogPrefix:mac:trusted: " $Iptables -t mangle -A mactest_$Iface -m mac --mac-source $Addr \ -j RETURN done [ "$V" -gt 2 ] && echo -n " trusted MAC addresses " [ "$V" -gt 0 ] && echo done else [ "$V" -gt 0 ] && echo " no MAC addresses trusted" fi # process authenticated MAC addresses if [ -f $MAC_AUTH_FILE ] then [ "$V" -gt 0 ] && echo -n " loading authenticated MAC addresses..." [ "$V" -gt 2 ] && echo CleanData < $MAC_AUTH_FILE |\ while read Addr; do [ "$V" -gt 2 ] && echo " $Addr" [ "$Log" ] && $Iptables -t mangle -A mactest_$Iface -m mac \ --mac-source $Addr $Log --log-prefix "$LogPrefix:mac:authen: " $Iptables -t mangle -A mactest_$Iface -m mac --mac-source $Addr \ -j RETURN done [ "$V" -gt 2 ] && echo -n " authenticated MAC addresses " [ "$V" -gt 0 ] && echo done else [ "$V" -gt 0 ] && echo " no MAC addresses authenticated" fi # setup services for all clients if echo "$Config" | grep '^mac ' > /dev/null then [ "$V" -gt 1 ] && echo " setting up mac services on $Iface" echo "$Config" | grep "^mac " |\ while read Line; do set $Line [ "$V" -gt 2 ] && echo " allowing $2 $3 to all hosts" $Iptables -I INPUT -i $Iface -p $2 -d $IP --dport $3 -j mac_$Iface $Iptables -I FORWARD -i $Iface -p $2 -d $IP --dport $3 -j mac_$Iface [ "$Log" ] && $Iptables -t mangle -A mactest_$Iface -i $Iface \ -p $2 --dport $3 $Log --log-prefix "$LogPrefix:mac:svc: " $Iptables -t mangle -A mactest_$Iface -i $Iface -p $2 --dport $3 \ -j RETURN done else [ "$V" -gt 1 ] && echo " no mac services on $Iface" fi # drop unauthenticated connections $Iptables -t mangle -A mactest_$Iface -j MARK --set-mark 1 $Iptables -t mangle -A mactest_$Iface -j RETURN $Iptables -t mangle -I PREROUTING -i $Iface -j mactest_$Iface [ "$V" -gt 0 ] && echo -n " redirecting new web clients" [ "$V" -gt 1 ] && echo " to $AUTH_IP_PORT" [ "$V" -gt 2 ] && echo [ "$Log" ] && $Iptables -t nat -A PREROUTING -m mark --mark 1 -p tcp \ --dport 80 $Log --log-prefix "$LogPrefix:mac:new: " $Iptables -t nat -A PREROUTING -m mark --mark 1 -p tcp --dport 80 \ -j DNAT --to-destination=$AUTH_IP_PORT [ "$V" -gt 0 ] && echo " dropping non-authenticated traffic" [ "$Log" ] && $Iptables -t nat -A PREROUTING -m mark --mark 1 \ $Log --log-prefix "$LogPrefix:mac:drop: " $Iptables -t nat -A PREROUTING -m mark --mark 1 -j DROP else echo " Warning: MAC Authentication is not in effect for $Iface!" echo " Check MAC_AUTH_FILE settings in $Iface.conf." fi fi # setup firewall rules $Iptables -N fwall_$Iface if echo "$ALLOW_ICMP" | grep -i yes >/dev/null then [ "$V" -gt 2 ] && echo " configuring connection types" [ "$V" -gt 2 ] && echo -n " " [ "$V" -gt 1 ] && echo " allowing icmp connections" $Iptables -I fwall_$Iface -p icmp -j ACCEPT [ "$V" -gt 2 ] && echo -n " " [ "$V" -gt 1 ] && echo " blocking malformed icmp connections" $Iptables -A OUTPUT -m state -p icmp --state INVALID -j DROP [ "$Log" ] && $Iptables -I fwall_$Iface -p icmp $Log \ --log-prefix "$LogPrefix:fwall_$Iface:accept: " if echo "$Config" | grep '^icmp_block ' > /dev/null then [ "$V" -gt 2 ] && echo -n " " [ "$V" -gt 1 ] && echo " blocking listed icmp types on $Iface" echo "$Config" | grep "^icmp_block " |\ while read Line; do set $Line [ "$V" -gt 2 ] && echo " blocking icmp type $2" $Iptables -I fwall_$Iface -p icmp --icmp-type $2 -j DROP [ "$Log" ] && $Iptables -I fwall_$Iface -p icmp --icmp-type $2 \ $Log --log-prefix "$LogPrefix:fwall_$Iface:drop:" done [ "$V" -gt 2 ] && echo " done blocking listed icmp types" else [ "$V" -gt 2 ] && echo " no icmp types blocked on $Iface" fi else [ "$V" -gt 2 ] && echo " dropping icmp connections" $Iptables -I fwall_$Iface -p icmp -j DROP [ "$Log" ] && $Iptables -I fwall_$Iface -p icmp $Log \ --log-prefix "$LogPrefix:fwall_$Iface:drop: " fi [ "$V" -gt 2 ] && echo -n " dropping new connections" [ "$V" -gt 2 ] && echo " not explicitly allowed" [ "$Log" ] && $Iptables -A fwall_$Iface -m state --state NEW $Log \ --log-prefix "$LogPrefix:fwall_$Iface:drop:" $Iptables -A fwall_$Iface -m state --state NEW -j DROP [ "$V" -gt 2 ] && echo " accepting established connections" [ "$Log" ] && $Iptables -A fwall_$Iface -m state --state ESTABLISHED \ $Log --log-prefix "$LogPrefix:fwall_$Iface:accept: " $Iptables -A fwall_$Iface -m state --state ESTABLISHED -j ACCEPT [ "$V" -gt 2 ] && echo " accepting related connections" [ "$Log" ] && $Iptables -A fwall_$Iface -m state --state RELATED $Log \ --log-prefix "$LogPrefix:fwall_$Iface:accept: " $Iptables -A fwall_$Iface -m state --state RELATED -j ACCEPT [ "$V" -gt 2 ] && echo " dropping invalid connections" [ "$Log" ] && $Iptables -A fwall_$Iface -m state --state INVALID $Log \ --log-prefix "$LogPrefix:fwall_$Iface:drop: " $Iptables -A fwall_$Iface -m state --state INVALID -j DROP [ "$V" -gt 2 ] && echo " dropping any other connections" [ "$Log" ] && $Iptables -A fwall_$Iface $Log --log-prefix \ "$LogPrefix:fwall_$Iface:drop: " $Iptables -A fwall_$Iface -j DROP $Iptables -A INPUT -i $Iface -j fwall_$Iface $Iptables -A FORWARD -i $Iface -j fwall_$Iface fi #setup remote connections if echo "$Config" | grep '^rmt ' > /dev/null then [ "$V" -gt 1 ] && echo " setting up remote connections on $Iface" $Iptables -N rmt_$Iface [ "$Log" ] && $Iptables -I rmt_$Iface $Log --log-prefix \ "$LogPrefix:rmt_$Iface:accept: " $Iptables -A rmt_$Iface -j ACCEPT echo "$Config" | grep "^rmt " |\ while read Line; do set $Line [ "$V" -gt 2 ] && echo " allowing $2 $3" $Iptables -I INPUT -i $Iface -p $2 -d ! $IP --dport $3 -j rmt_$Iface $Iptables -I FORWARD -i $Iface -p $2 -d ! $IP --dport $3 -j rmt_$Iface done else [ "$V" -gt 1 ] && echo " no remote connections on $Iface" fi # setup local services if echo "$Config" | grep '^svc ' > /dev/null then [ "$V" -gt 1 ] && echo " setting up services on $Iface" $Iptables -N svc_$Iface [ "$Log" ] && $Iptables -I svc_$Iface $Log --log-prefix \ "$LogPrefix:svc_$Iface:accept: " $Iptables -A svc_$Iface -j ACCEPT echo "$Config" | grep "^svc " |\ while read Line; do set $Line [ "$V" -gt 2 ] && echo " allowing $2 $3" $Iptables -I INPUT -i $Iface -p $2 -d $IP --dport $3 -j svc_$Iface $Iptables -I FORWARD -i $Iface -p $2 -d $IP --dport $3 -j svc_$Iface done else [ "$V" -gt 1 ] && echo " no services on $Iface" fi # setup port forwarding if echo "$Config" | grep '^portfw ' > /dev/null then [ "$V" -gt 1 ] && echo " setting up port forwarding on $Iface" $Iptables -t nat -N portfw_$Iface echo "$Config" | grep "^portfw " |\ while read Line; do set $Line [ "$V" -gt 2 ] && echo " forwarding $2 $3 to $5 $6" [ "$Log" ] && $Iptables -t nat -A portfw_$Iface -i $Iface -p $2 \ --dport $3 $Log --log-prefix "$LogPrefix:portfw_$Iface:dnat: " $Iptables -t nat -A portfw_$Iface -i $Iface -p $2 --dport $3 -j DNAT \ --to-destination $5:$6 $Iptables -I INPUT -i $Iface -p $2 --dport $3 -j ACCEPT [ "$Log" ] && $Iptables -I INPUT -i $Iface -p $2 --dport $3 $Log \ --log-prefix "$LogPrefix:input:accept" $Iptables -I FORWARD -i $Iface -p $2 --dport $3 -j ACCEPT [ "$Log" ] && $Iptables -I FORWARD -i $Iface -p $2 --dport $3 $Log \ --log-prefix "$LogPrefix:forward:accept: " $Iptables -t nat -A PREROUTING -i $Iface -p $2 --dport $3 -j portfw_$Iface [ "$Log" ] && $Iptables -t nat -A OUTPUT -o $Iface -p $2 -s $5 \ --dport $3 $Log --log-prefix "$LogPrefix:output:dnat: " $Iptables -t nat -A OUTPUT -o $Iface -p $2 -s $5 --dport $3 -j DNAT \ --to-destination $5:$6 done else [ "$V" -gt 1 ] && echo " no port forwarding on $Iface" fi # setup masquerading if echo "$MASQUERADE" | grep -i yes >/dev/null then [ "$V" -gt 0 ] && echo " configuring masquerading on $Iface" $Iptables -t nat -N masq_$Iface [ "$Log" ] && $Iptables -t nat -A masq_$Iface -o $Iface $Log \ --log-prefix "$LogPrefix:nat:masquerade: " $Iptables -t nat -A masq_$Iface -o $Iface -j MASQUERADE $Iptables -t nat -A POSTROUTING -o $Iface -j masq_$Iface else [ "$V" -gt 0 ] && echo " no masquerading on $Iface" fi [ "$V" -gt 0 ] && echo "Interface $Iface is configured." done [ "$V" -gt 2 ] && echo [ "$V" -gt 2 ] && echo General configuration: [ "$V" -gt 1 ] && echo # setup banned IP addresses if [ -f bannedip.conf ] then [ "$V" -gt 0 ] && echo -n "Loading banned IP addresses..." [ "$V" -gt 2 ] && echo $Iptables -N banned [ "$Log" ] && $Iptables -A banned -m state --state RELATED $Log \ --log-prefix "$LogPrefix:banned:accept: " $Iptables -A banned -m state --state RELATED -j ACCEPT [ "$Log" ] && $Iptables -A banned -m state --state ESTABLISHED $Log \ --log-prefix "$LogPrefix:banned:accept: " $Iptables -A banned -m state --state ESTABLISHED -j ACCEPT [ "$Log" ] && $Iptables -A banned $Log --log-prefix "$LogPrefix:banned:drop: " $Iptables -A banned -j DROP CleanData < bannedip.conf |\ while read Addr; do [ "$V" -gt 2 ] && echo " $Addr" $Iptables -I INPUT -s $Addr -j banned done [ "$V" -gt 2 ] && echo -n "Banned IP addresses " [ "$V" -gt 0 ] && echo done. else [ "$V" -gt 0 ] && echo "No IP addresses banned." fi # block unused IP addresses if [ "$BlockUnusedIp" = yes ] then [ "$V" -gt 0 ] && echo -n "Loading unused IP addresses..." [ "$V" -gt 2 ] && echo $Iptables -N unused CleanData < unusedip.conf |\ while read Addr; do [ "$V" -gt 2 ] && echo " $Addr" $Iptables -A INPUT -s $Addr -j unused done [ "$Log" ] && $Iptables -A unused -m state --state RELATED $Log \ --log-prefix "$LogPrefix:usused:accept: " $Iptables -A unused -m state --state RELATED -j ACCEPT [ "$Log" ] && $Iptables -A unused -m state --state ESTABLISHED $Log \ --log-prefix "$LogPrefix:usused:accept: " $Iptables -A unused -m state --state ESTABLISHED -j ACCEPT [ "$Log" ] && $Iptables -A unused $Log --log-prefix "$LogPrefix:usused:drop: " $Iptables -A unused -j DROP [ "$V" -gt 2 ] && echo -n "Unused IP addresses " [ "$V" -gt 0 ] && echo done. else [ "$V" -gt 0 ] && echo "Not blocking unused IP addresses." fi # setup trusted IP addresses if [ -f trustedip.conf ] then [ "$V" -gt 0 ] && echo -n "Loading trusted IP addresses..." [ "$V" -gt 2 ] && echo $Iptables -N trusted [ "$Log" ] && $Iptables -A trusted $Log --log-prefix \ "$LogPrefix:trusted:accept: " $Iptables -A trusted -j ACCEPT CleanData < trustedip.conf |\ while read Addr; do [ "$V" -gt 2 ] && echo " $Addr" $Iptables -I INPUT -s $Addr -j trusted done [ "$V" -gt 2 ] && echo -n "Trusted IP addresses " [ "$V" -gt 0 ] && echo done. else [ "$V" -gt 0 ] && echo "No IP addresses trusted." fi # setup blackholed IP addresses if [ -f blackhole.conf ] then [ "$V" -gt 0 ] && echo -n "Loading blackhole IP addresses..." [ "$V" -gt 2 ] && echo $Iptables -N blackhole [ "$Log" ] && $Iptables -A blackhole $Log --log-prefix \ "$LogPrefix:blackhole:drop: " $Iptables -A blackhole -j DROP CleanData < blackhole.conf |\ while read Addr; do [ "$V" -gt 2 ] && echo " $Addr" $Iptables -I INPUT -s $Addr -j blackhole done [ "$V" -gt 2 ] && echo -n "Blackhole IP addresses " [ "$V" -gt 0 ] && echo done. else [ "$V" -gt 0 ] && echo "No IP addresses blackholed." fi # setup other firewall rules [ "$V" -gt 1 ] && echo Dropping xmas and null packets. $Iptables -N xmas [ "$Log" ] && $Iptables -A xmas $Log --log-prefix "$LogPrefix:xmas:drop: " $Iptables -A xmas -j DROP $Iptables -I INPUT -p tcp --tcp-flags ALL ALL -j xmas $Iptables -I FORWARD -p tcp --tcp-flags ALL ALL -j xmas $Iptables -N null [ "$Log" ] && $Iptables -A null $Log --log-prefix "$LogPrefix:null:drop: " $Iptables -A null -j DROP $Iptables -I INPUT -p tcp --tcp-flags ALL NONE -j null $Iptables -I FORWARD -p tcp --tcp-flags ALL NONE -j null # re-enable packet forwarding echo 1 > /proc/sys/net/ipv4/ip_forward [ "$V" -gt 1 ] && echo [ "$V" -gt 0 ] && echo IP forwarding is re-enabled. exit 0