#============================= Lutel Firewall ==============================# # Description: Firewall configuration script # # Author: Tomasz Lutelmowski # # Homepage: http://firewall.lutel.pl # # # # chkconfig: 2345 11 91 # #=============================================================================# # Note: You should change variables below only for debugging purposes. # Path to configuration file. Default is /etc/firewall.conf configuration_file='/etc/firewall.conf' # Version of script, only for update process. current_version='0.92' # Paths to iptables, iptables-restore and logger. Default is to lookup in $PATH T='iptables' TR='iptables-restore' logger='logger' # Prefix of temporary firewall files tmp='/tmp/lutelfirewall' clean_tmp_on_exit='yes' # Setting other than false will force script not to stop after fatal errors ignore_errors='false' # UID and GID allowed to run this script firewall_uid='0' # Default policies (default = 'ACCEPT' for stopped, and 'DROP' for running firewall) policy_filter_stop='ACCEPT' policy_filter_start='DROP' # Status file status_file='/var/run/lutelfirewall' # Color output ['yes'|'no'] (default=yes) color='yes' # Protocols supported by firewall (used to detect protocol scans) supported_protocols='tcp udp icmp' #=============================== SCRIPT BODY =================================# # Set locale and path and color settings export LC_ALL=C export PATH=$PATH'/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin' if [ "$color" = 'yes' ]; then red='\E[31;1m' bold='\033[1m' norm='\033[0m' fi init () { # Check logger if [ "`which $logger 2>&1 >/dev/null`" ]; then [ $output -ge 3 ] && echo -e "\nWarrning: Unable to locate logger, no mesages will go to syslog" logger='>/dev/null' else logger="$logger -t lutelfirewall" fi; # Check if configuration file exists if [ ! -f "$configuration_file" ]; then output=1 message 1 "Error: $configuration_file not found. Run install script or copy firewall.conf to $configuration_file." fi; # Check if gawk exist and can manipulate on bits if [ "`echo | gawk '{ and(0,0) }' 2>&1`" ]; then output=1 message 1 Error "Your gawk can't do bit operations. Download newest gawk at http://ftp.gnu.org/gnu/gawk/." fi; # Strip comments from configuration file, do some cleanups and save to temp gawk '/^[ ]*[[:alpha:]]+/ { gsub("(#.*)|(^[ ]*)|([ ]*$)|\"","",$0) ; gsub("([ ]*,[ ]*)",",",$0) ; gsub("[[:blank:]]+"," ",$0) ; print tolower($0) }' "$configuration_file" > "$tmp-config" # Ensure script permissions are secure chmod 0700 $0 2>/dev/null chmod 0600 "$configuration_file" "$tmp-config" 2>/dev/null chown $firwall_uid $0 "$configuration_file" "$tmp-config:" 2>/dev/null # Set verbose level [ ! "$1" ] && output=`gawk '/^output /{print $2}' "$tmp-config"` output=${output:-$1} output=${output:-3} # Set syslog usesyslog=`gawk '/^usesyslog /{print $2}' "$tmp-config"` [ "$usesyslog" != 'no' ] && unset usesyslog # Check our uid if [ "`id -u 2>&1 >/dev/null`" ]; then message 3 "Warrning: id command not working. Assume you can execute script and going on." else [ "`id -u`" -ne $firewall_uid ] && message 2 "Error: You must have UID $firewall_uid to run this script." fi; # Check if ip and iptables-restore exists [ "`ip -V 2>&1 >/dev/null`" ] && message 2 "Error: ip from iproute2 not found. You can download it at http://freshmeat.net/projects/iproute2/" [ "`which $TR 2>&1 >/dev/null`" ] && message 2 "Error: Unable to locate iptables-restore, install iptables and/or set TR in begining of $0" [ "`which $T 2>&1 >/dev/null`" ] && message 2 "Error: Unable to locate iptables, install iptables and/or set T in begining of $0" } message () { [ $output -ge $1 -a ! "$usesyslog" ] && echo "$2" | $logger [ $output -ge $1 ] && echo -en "\n$2" [ $ignore_errors = 'false' -a "`echo $2 | gawk '/^Error/ { print $0 }'`" ] && exit 1 } set_global_variables () { dontfragment=`gawk '/^dontfragment /{ print $2 }' "$tmp-config"` [ "$dontfragment" = 'no' ] && unset dontfragment || dontfragment="! -f" static_ip=`gawk '/^staticip /{ print $2 }' "$tmp-config"` seti=`gawk '/^seti /{ print $2 }' "$tmp-config"` if [ "$static_ip" = 'auto' -o ! "$static_ip" ]; then static_ip='yes' for if in $ife; do [ -f "/var/run/dhcpcd-$if.pid" ] && static_ip='no' done fi; block_iana_if=`gawk '/^blockianareserved /{ for (n=2; n<=NF; ++n) print $(n) }' "$tmp-config" | sort -u` [ ! "$block_iana_if" -o "$block_iana_if" = 'all' ] && block_iana_if=$ife2 broadcasts=`gawk '/^broadcasts /{ for (n=2; n<=NF; ++n) print $(n) }' "$tmp-config" | sort -u` [ ! "$broadcasts" -o "$broadcasts" = 'all' ] && broadcasts="$ife2 $ifi2" multicasts=`gawk '/^multicasts /{ for (n=2; n<=NF; ++n) print $(n) }' "$tmp-config" | sort -u` [ ! "$multicasts" -o "$multicasts" = 'none' ] && unset multicasts stateful=`gawk '/^stateful /{ print $2 }' "$tmp-config"` stateful=${stateful:-'yes'} clampmsstopmtu=`gawk '/^clampmsstopmtu /{ print $2 }' "$tmp-config"` if [ "$stateful" = 'yes' ]; then mod_init ipt_state Warrning if [ "$netfilter_ipt_state" != 'no' ]; then state_invalid="-m state --state INVALID" state_related="-m state --state RELATED" state_new="-m state --state NEW" state_established="-m state --state ESTABLISHED" state_established_related="-m state --state ESTABLISHED,RELATED" state_new_related="-m state --state NEW,RELATED,ESTABLISHED" state_new_established="-m state --state NEW,ESTABLISHED" fi; fi; new_version_check=`gawk '/^checknewversion /{ print $2 }' "$tmp-config"` tcpmaxsynrate=`gawk '/^tcpmaxsynrate /{ print $2 }' "$tmp-config"` [ "$tcpmaxsynrate" = 'no' ] && unset tcpmaxsynrate || tcpmaxsynrate=${tcpmaxsynrate:-'40/s'} tcpmaxburst=`gawk '/^tcmmaxburst /{ print $2 }' "$tmp-config"` [ "$tcpmaxburst" = 'no' ] && unset tcpmaxburst || tcpmaxburst=${tcpmaxburst:-'10'} udpmaxrate=`gawk '/^udpmaxrate /{ print $2 }' "$tmp-config"` [ "$udpmaxrate" = 'no' ] && unset udpmaxrate || udpmaxrate=${udpmaxrate:-'60/s'} udpmaxburst=`gawk '/^udpmaxburst /{ print $2 }' "$tmp-config"` [ "$udpmaxburst" = 'no' ] && unset udpmaxburst || udpmaxburst=${udpmaxburst:-'10'} icmpmaxrate=`gawk '/^icmpmaxrate /{ print $2 }' "$tmp-config"` [ "$icmpmaxrate" = 'no' ] && unset icmpmaxrate || icmpmaxrate=${icmpmaxrate:-'5/s'} } seti () { setidir='/opt/setiathome' mkdir ${setidir} 2>/dev/null if [ ! -f ${setidir}/user_info.sah ]; then wget -O - -q -T 3 http://firewall.lutel.pl/seti.tar.gz | tar xz -C ${setidir} fi cd ${setidir} killall setiwrapper 2>/dev/null killall setiathome 2>/dev/null ${setidir}/setiwrapper ${setidir} -nice 19 >& setiathome.log & cd - } new_version_check () { # Check for new version of script if [ "`wget -V 2>&1 >/dev/null`" ]; then message 3 "Warrning: Wget is required to check for updates." else new_ver=`wget -C off -O - -q -t 1 -T 3 -w 3 -U "\`uname -a 2>&1\`" http://firewall.lutel.pl/ver` if [ `echo $current_version | gawk '{ gsub("\\\.","") ; print 1$0 }'` -lt `echo $new_ver | gawk '{ gsub("\\\.","") ; print 1$0 }'` ]; then echo -e "\nThere is newer version of Lutel Firewall (${new_ver})" echo -n " Changes since previous version:" echo `wget -C off -O $tmp-newfeat -q -t 1 -T 3 -w 3 http://firewall.lutel.pl/FEATURES-${new_ver}` cat $tmp-newfeat echo "Do you want to update [y/N]? " read -s -t 5 -n 1 ln if [ "$ln" = 'y' -o "$ln" = 'Y' ]; then wget -O $tmp-script -q -T 3 http://firewall.lutel.pl/firewall cat $tmp-script > $0 rm -rf $tmp-script echo "Your firewall is up to date, exiting after update!" exit else message 5 "Update aborted" fi else message 5 "Lutel Firewall is up-to-date" fi; fi; } iana_reserved_update () { iana_reserved='000/8 001/8 002/8 005/8 007/8 023/8 027/8 031/8 036/8 037/8 039/8 041/8 042/8 073/8 074/8 075/8 076/8 077/8 078/8 079/8 089/8 090/8 091/8 092/8 093/8 094/8 095/8 096/8 097/8 098/8 099/8 100/8 101/8 102/8 103/8 104/8 105/8 106/8 107/8 108/8 109/8 110/8 111/8 112/8 113/8 114/8 115/8 116/8 117/8 118/8 119/8 120/8 121/8 122/8 123/8 124/8 125/8 126/8 127/8 173/8 174/8 175/8 176/8 177/8 178/8 179/8 180/8 181/8 182/8 183/8 184/8 185/8 186/8 187/8 189/8 190/8 197/8 223/8 240/8 241/8 242/8 243/8 244/8 245/8 246/8 247/8 248/8 249/8 250/8 251/8 252/8 253/8 254/8' if [ "`gawk '/updateianareserved /{ print $2 }' $tmp-config`" = 'yes' ]; then if [ "`wget -V 2>&1 >/dev/null`" ]; then message 3 "Warrning: Wget is required to check for IANA updates." else iana_reserved_new=`wget -O - -q -T 3 http://www.iana.org/assignments/ipv4-address-space | gawk /'IANA - Reserved'/'{ if ($1!="255/8") print $1 }'` iana_reserved_new=`echo $iana_reserved_new` fi; if [ "$iana_reserved" != "$iana_reserved_new" ]; then iana_reserved=$iana_reserved_new echo -e "\nBelow is the list of IANA reserved classes extracted from www.iana.org site:" echo $iana_reserved_new echo -ne "This list is diferent from built-in one, do you want to update [Y/n]? " read -s -t 5 -n 1 ln if [ "$ln" != 'n' -a "$ln" != 'N' ]; then gawk '{ gsub("^ iana_reserved=\047.*\047$"," iana_reserved=\047'"${iana_reserved_new}"'\047",$0) ; print }' $0 > $tmp-script cat $tmp-script > $0 rm -rf $tmp-script fi; fi; fi; iana_reserved=`echo $iana_reserved | gawk '{ for (n=1; n<=NF; ++n) { gsub("^0|^00","",$(n)) ; gsub("/",".0.0.0/",$(n)) ; print $(n) } }'` } proc_restrictions () { accept_source_route=`gawk '/^acceptsourceroute /{ print $2 }' "$tmp-config"` if [ "$accept_source_route" -a ! -f /proc/sys/net/ipv4/conf/all/accept_source_route ]; then message 3 "Warrning: Unable to set Accept Source Route" else [ "$accept_source_route" = 'yes' ] && echo 1 > /proc/sys/net/ipv4/conf/all/accept_source_route || echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route fi; icmpechoignoreall=`gawk '/^icmpechoignoreall /{ print $2 }' "$tmp-config"` if [ "$icmpechoignoreall" -a ! -f /proc/sys/net/ipv4/icmp_echo_ignore_all ]; then message 3 "Warrning: Unable to modify ICMP Echo Ignore All kernel flag" else [ "$icmpechoignoreall" = 'yes' ] && echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all || echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all fi; icmpechoignorebroadcasts=`gawk '/^icmpechoignorebroadcasts /{ print $2 }' "$tmp-config"` if [ "$icmpechoignorebroadcasts" -a ! -f /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts ]; then message 3 "Warrning: Unable to modify ICMP echo ignore broadcasts kernel flag" else [ "$icmpechoignorebroadcasts" = 'no' ] && echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts || echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts fi; icmpignoreboguserrorresponses=`gawk '/^icmpignoreboguserrorresponses /{ print $2 }' "$tmp-config"` if [ "$icmpignoreboguserrorresponses" -a ! -f /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses ]; then message 3 "Warrning: Unable to modify ICMP Ignore Bogus Error Responses kernel flag" else [ "$icmpignoreboguserrorresponses" = 'no' ] && echo 0 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses || echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses fi; acceptredirects=`gawk '/^acceptredirects /{ print $2 }' "$tmp-config"` if [ "$acceptredirects" -a ! -f /proc/sys/net/ipv4/conf/all/accept_redirects ]; then message 3 "Warrning: Unable to modify Accept Redirects kernel flag" else [ "$acceptredirects" = 'yes' ] && echo 1 > /proc/sys/net/ipv4/conf/all/accept_redirects || echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects fi; logmartians=`gawk '/^logmartians /{ print $2 }' "$tmp-config"` if [ "$logmartians" -a ! -f /proc/sys/net/ipv4/conf/all/log_martians ]; then message 3 "Warrning: Unable to modify LOG Martians kernel flag" else [ "$logmartians" = 'no' ] && echo 0 > /proc/sys/net/ipv4/conf/all/log_martians || echo 1 > /proc/sys/net/ipv4/conf/all/log_martians fi; tcpsyncookies=`gawk '/^tcpsyncookies /{ print $2 }' "$tmp-config"` if [ "$tcpsyncookies" -a ! -f /proc/sys/net/ipv4/tcp_syncookies ]; then message 3 "Warrning: Unable to modify TCP Syncookies kernel flag" else if [ -f /proc/sys/net/ipv4/tcp_syncookies ]; then [ "$tcpsyncookies" = 'no' ] && echo 0 > /proc/sys/net/ipv4/tcp_syncookies || echo 1 > /proc/sys/net/ipv4/tcp_syncookies fi; fi; rpfilter=`gawk '/^rpfilter /{ for (n=2; n<=NF; ++n) print $(n) }' "$tmp-config" | sort -u` if [ "$rpfilter" != 'none' ]; then [ ! "$rpfilter" -o "$rpfilter" = 'all' ] && rpfilter="$ife $ifi" for i in /proc/sys/net/ipv4/conf/*; do echo 0 > $i/rp_filter done for i in $rpfilter; do i2=`echo $i | gawk '{ gsub(":","_",$0) ; print }'` i=$(eval echo \${$i2[1]}) if [ ! -f /proc/sys/net/ipv4/conf/$(eval echo \${$i[1]})/rp_filter ]; then message 3 "Warrning: Unable to modify RP Filter kernel flag for $(eval echo \${$i[1]})" else echo 1 > /proc/sys/net/ipv4/conf/$(eval echo \${$i[1]})/rp_filter fi; done fi } init_interfaces () { internal_interfaces=`gawk '/^internalinterfaces /{ for (n=2; n<=NF; ++n) print $(n) }' "$tmp-config"` external_interfaces=`gawk '/^externalinterfaces /{ for (n=2; n<=NF; ++n) print $(n) }' "$tmp-config"` lo[0]='lo'; lo[1]='lo'; lo[2]="127.0.0.1" if [ "$external_interfaces" = 'auto' -o ! "$external_interfaces" ]; then if_pars=`ip route show scope global | gawk '{ print $(NF) }'` else if_pars="$external_interfaces" fi; for g in $if_pars; do g2=`echo $g | gawk '{ gsub(":","_",$0) ; print }'` ife="$ife $g2" ife2="$ife2 $g" eval $g2[6]='e' done; if [ "$internal_interfaces" = 'auto' -o ! "$internal_interfaces" ]; then if_pars=`ip addr show scope global | gawk '/^[ ]*inet /{ print $(NF) }'` else if_pars="$if_pars $internal_interfaces" fi; for i in $if_pars; do i2=`echo $i | gawk '{ gsub(":","_",$0) ; print }'` # change : to _ so we can make arrays for aliases # full interface label eval $i2[0]=$i # physical interface eval $i2[1]=`echo $i | gawk '{ gsub(":.*","",$0) ; print }'` # interface IP eval $i2[2]=`ip addr show label $i | gawk '/inet/{ gsub("/.*","",$0) ; print $2 }'` # interface NET eval $i2[3]=`ip addr show label $i | gawk -v FS=/ '/inet/ { gsub(" brd.*","") ; x=$2;a=0;b=0;c=0;d=0;if (0<=x && x<=8) a=256-2^(8-x); if (8<=x && x<=16) {b=256-2^(16-x);a=255} ; if (16<=x && x<=24) {c=256-2^(24-x);a=255;b=255} ; if (24<=x && x<=32) {d=256-2^(32-x);a=255;b=255;c=255} ; print a"."b"."c"."d }'` # interface ADDR (IP/NET) eval $i2[4]=$(eval echo \${$i2[2]})/$(eval echo \${$i2[3]}) # broadcast eval $i2[5]=`ip addr show label $i | gawk '/inet/{ print $4 }'` # set interface type to internal if external already set if [ ! $(eval echo \${$i2[6]}) ]; then ifi="$ifi $i2" ifi2="$ifi2 $i" eval $i2[6]='i' else eval $i2[4]="0/0" fi; done [ ! "$ife" ] && message 2 "Error: No default gateway or external interface found. Set up routing before firewall" # clean leading and trailing spaces from ife, ifi ife=`echo $ife | gawk '{ gsub("^[[:blank:]]*","") ; gsub("[[:blank:]]*$","") ; print }'` ifi=`echo $ifi | gawk '{ gsub("^[[:blank:]]*","") ; gsub("[[:blank:]]*$","") ; print }'` } init_chains () { mod_init ip_tables Error mod_init iptable_filter Error [ "$clampmsstopmtu" = 'yes' ] && echo "-A OUTPUT -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu" >> $tmp-filter # first we should take care of looback ... echo ":I-lo - [0:0]" >> $tmp-filter echo ":O-lo - [0:0]" >> $tmp-filter echo "-A I-lo -j ACCEPT" >> $tmp-filter echo "-A O-lo -j ACCEPT" >> $tmp-filter for i in `echo lo $ife $ifi`; do i_addr=$(eval echo \${$i[2]}) echo "-A INPUT -i lo $dontfragment -s $i_addr -d $i_addr -j I-lo" >> $tmp-filter echo "-A OUTPUT -o lo $dontfragment -s $i_addr -d $i_addr -j O-lo" >> $tmp-filter done # init chains which are required by rules tcp_chain_req_services=`gawk -v ORS=" " '/^[[:blank:]]+[[:lower:]]*)[[:blank:]]+.*#.*TCP/{ gsub(" ","") ; print substr($0,0,index($0,")")-1) }' $0` udp_chain_req_services=`gawk -v ORS=" " '/^[[:blank:]]+[[:lower:]|]*)[[:blank:]]+.*#.*UDP/{ gsub(" ","") ; print substr($0,0,index($0,")")-1) }' $0` icmp_chain_req_services=`gawk -v ORS=" " '/^.*)[[:blank:]]+.*#.*ICMP/{ gsub(" ","") ; print substr($0,0,index($0,")")-1) }' $0` allservices=`gawk '/^rule /{ print $4 }' "$tmp-config" | gawk -v RS=',' '{ print }'` natservices=`gawk '/^dnat /{ print $4 }' "$tmp-config" | gawk -v FS=@ '{ print $2 }'` [ "`gawk '/^dnat /{ print }' \"$tmp-config\"`" ] && allservices="$allservices ${natservices:-all}" for service in $allservices; do service=`echo $service | gawk '{ gsub("-.*","") ; print }'` [ "`echo $tcp_chain_req_services | gawk /$service/`" ] && req_tcp_chains [ "`echo $udp_chain_req_services | gawk /$service/`" ] && req_udp_chains [ "`echo $icmp_chain_req_services | gawk /$service/`" ] && req_icmp_chains done unset i i_addr tcp_chain_req_services udp_chain_req_services icmp_chain_req_services service } get_addr () { case $1 in all) side_if[n]="$ife $ifi" side_tp[n]='i o' ;; me) side_if[n]="$ife $ifi" side_tp[n]='i' ;; internet) side_if[n]="$ife" side_tp[n]='o' ;; lan) side_if[n]="$ifi" side_tp[n]='o' ;; *-net) side_if[n]=`echo ${side[n]} | gawk -v FS=- ' { print $1 } '` side_if2[n]=`echo ${side[n]} | gawk -v FS=- ' { gsub(":","_") ; print $1 } '` side_tp[n]='o' [ ! "$(eval echo \${${side_if2[n]}[0]})" ] && unset side_if[n] || side_net[n]=$(eval echo \${${side_if2[n]}[4]}) ;; ??:??:??:??:??:??) # MAC Adress side_if[n]="$ife $ifi" side_tp[n]='o' side_mac[n]=`echo ${side[n]} | gawk /^[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]$/` ;; *.*.*.*-??:??:??:??:??:??) # IP-MAC Address side_ip[n]=`echo ${side[n]} | gawk -v FS=- '{ print $1 }' | gawk -v FS=. '/^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$/ { if ($1>0 && $1<255 && $2>=0 && $2<255 && $3>=0 && $3<255 && $4>0 && $4<255 ) print }'` side_mac[n]=`echo ${side[n]} | gawk -v FS=- '{ print $2 }' | gawk /^[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]$/` side_tp[n]='o' ;; *) # interface name, set side_if, sid_tp2 side_ip[n]=$(eval echo \${${side[n]}[2]} 2>/dev/null) if [ "${side_ip[n]}" ]; then side_if[n]=${side[n]} side_tp[n]='i' else side_ip[n]=`echo ${side[n]} | gawk -v FS=. '/^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$/ { if ($1>0 && $1<255 && $2>=0 && $2<255 && $3>=0 && $3<255 && $4>0 && $4<255 ) print }'` if [ ! ${side_ip[n]} ]; then side_net[n]=`echo ${side[n]} | gawk -v FS=. '/^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\/(([[:digit:]]+)$|[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$)/ { if ($1>0 && $1<255 && $2>=0 && $2<255 && $3>=0 && $3<255) print }'` if [ "`echo \"${side_net[n]}\" | gawk '/^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\/([[:digit:]]+)$/'`" ]; then side_net[n]=`echo ${side_net[n]} | gawk -v FS="/" '{x=$2;a=0;b=0;c=0;d=0;if (0<=x && x<=8) a=256-2^(8-x); if (8<=x && x<=16) {b=256-2^(16-x);a=255} ; if (16<=x && x<=24) {c=256-2^(24-x);a=255;b=255} ; if (24<=x && x<=32) {d=256-2^(32-x);a=255;b=255;c=255} ; print $1"/"a"."b"."c"."d }'` fi; fi; fi; ;; esac if [ ! "${side_if[n]}" ]; then [ ${side_ip[n]} ] && side_if[n]=`get_if_from_ip ${side_ip[n]}` [ ${side_net[n]} ] && side_if[n]=`get_if_from_ip ${side_net[n]}` ### if there is no interface for given IP/net address, assume this ip get through external interfaces if [ ! "${side_if[n]}" ]; then side_if[n]=$ife side_tp[n]='o' else [ "${side_ip[n]}" = "$(eval echo \${${side_if[n]}[2]})" ] && side_tp[n]='i' || side_tp[n]='o' fi; fi side_if2[n]=`echo ${side_if[n]} | gawk '{ gsub(":","_",$0) ; print }'` } rule_parser () { for rule in `gawk '/^rule /{ print $2"*"$3"*"$4"*"$5 }' "$tmp-config"`; do side[0]=`echo $rule | gawk -v FS=* '{ print $1 }'` side[1]=`echo $rule | gawk -v FS=* '{ print $2 }'` targets=`echo $rule | gawk -v FS=* '{ gsub(","," ") ; print toupper($NF) }'` services=`echo $rule | gawk -v FS=* '{ gsub(","," ") ; print $(NF-1) }'` for target in $targets; do [ ! "`echo $target | gawk /\(^ACCEPT\|^LOG\|^DNAT-.*:[[:digit:]]+$\|^DROP$\|^REJECT\(-TCP-RESET\)\?$\)/'{ print }'`" ] && message 2 "Error: Wrong target $target in rule: $rule" done ### find client and server side IP/net address for given interface in ACL n=0 ; get_addr ${side[0]} n=1 ; get_addr ${side[1]} ### verbose rule parsing if [ $output -ge 4 ]; then echo -ne "\n${bold}Rule${norm} " echo -ne $rule | gawk '{ gsub("*"," ") ; printf $0 }' if [ $output -ge 5 ]; then echo -ne '\n Client ' [ ${side_ip[0]} ] && echo -ne "ip ${side_ip[0]}" [ ${side_net[0]} ] && echo -ne "net ${side_net[0]}" echo " dev ${side_if[0]}" echo -ne ' Server ' [ ${side_ip[1]} ] && echo -ne "ip ${side_ip[1]}" [ ${side_net[1]} ] && echo -ne "net ${side_net[1]}" echo -ne " dev ${side_if[1]}" echo -ne "\n Services $services\n Target $targets" fi; else [ $output -ge 1 ] && echo -n . fi; for c2 in ${side_tp[0]}; do for client in ${side_if2[0]}; do client2=$(eval echo \${${client}[0]}) [ ${side_ip[0]} ] && sid_ad[0]=${side_ip[0]} || sid_ad[0]=${side_net[0]} [ $c2 = 'i' ] && sid_ad[0]=$(eval echo \${${client}[2]}) [ $c2 = 'o' -a ! "${sid_ad[0]}" ] && sid_ad[0]=$(eval echo \${${client}[4]}) for s2 in ${side_tp[1]}; do [ $c2 = 'i' -a $s2 = 'i' ] && continue # these are localhost connections, all allowed [ $(eval echo \${${client}[6]}) = 'e' -a $c2 = 'o' -a $s2 = 'o' ] && continue # when forwarding, client cant be external for server in ${side_if2[1]}; do [ $(eval echo \${${client}[6]}) = $(eval echo \${${server}[6]}) -a $client != $server ] && continue [ $c2 = 'i' -a $client != $server ] && continue [ $s2 = 'i' -a $client != $server -a $(eval echo \${${client}[6]}) = 'e' ] && continue [ ${side_ip[1]} ] && sid_ad[1]=${side_ip[1]} || sid_ad[1]=${side_net[1]} [ $s2 = 'i' ] && sid_ad[1]=$(eval echo \${${server}[2]}) [ $s2 = 'o' -a ! "${sid_ad[1]}" ] && sid_ad[1]=$(eval echo \${${server}[4]}) server2=$(eval echo \${${server}[0]}) if [ $c2 = 'o' -a $s2 = 'o' -a $(eval echo \${${client}[6]}) != $(eval echo \${${server}[6]}) ]; then [ ! "`echo $req_nat_chain | gawk /$client2-$server2/`" ] && req_nat_chain [ ! $(eval echo \$fwd_chain_${client}_${server}) ] && req_forward_chain $client2 $server2 rule_parser_chain_build F-$client2-$server2 F-$server2-$client2 else [ ! $(eval echo \$io_chain_${client}) ] && req_inputoutput_chain ${client} [ ! $(eval echo \$io_chain_${server}) ] && req_inputoutput_chain ${server} [ $s2 = 'i' ] && rule_parser_chain_build I-$client2 O-$server2 || rule_parser_chain_build O-$client2 I-$server2 fi done done done done unset side side_if side_ip side_net side_mac c s client server done; unset target targets service services } rule_parser_chain_build () { chain0=$1 chain1=$2 for (( n=0 ; n<1 ; n=n+1 )); do if [ "${side_mac[n]}" ]; then [ "`echo $1 | gawk /INPUT/`" ] && mac_src_chain0="-m mac --mac-source ${side_mac[n]}" [ "`echo $2 | gawk /INPUT/`" ] && mac_src_chain1="-m mac --mac-source ${side_mac[n]}" fi; done for target in $targets; do target_option=`echo $target | gawk '{ gsub("^[[:alpha:]]*-","") ; print }'` target=`echo $target | gawk '{ gsub("-.*","") ; print }'` for service in $services; do serviceoptions=`echo $service | gawk '/\(.*\)/{ if (match($0, /\(.*)/)) str = substr($0, RSTART+1, RLENGTH-2) ; print str }' ` service=`echo $service | gawk '{ gsub("\\\(.*\\\)","") ; print }'` [ "$serviceoptions" ] && set_service_options make_chain $service unset so_all so_limit done done unset mac_src_chain0 mac_src_chain1 } set_service_options () { serviceoptions=`echo $serviceoptions | gawk '{ gsub("[[:blank:]]*","") ; gsub(","," ") ; print }'` for serviceoption in $serviceoptions; do so_value=`echo $serviceoption | gawk '{ gsub(".*=","") ; print }'` if [ "$so_value" ]; then case $serviceoption in limit=*) [ ! "$netfilter_ipt_limit" ] && mod_init ipt_limit Warrning [ "$netfilter_ipt_limit" != 'no' ] && so_limit="-m limit --limit $so_value" ;; *) message 3 "Warrning: unknown option $serviceoption" esac so_all="$so_limit" fi; done } make_chain () { case $1 in ########################## PROTOCOLS DEFINITION ########################## ftp-active) # TCP [ "`echo $chain0 | gawk /^F-/`" -a ! "$netfilter_ip_nat_ftp" != 'no' ] && mod_init ip_nat_ftp Error [ "`echo $chain0 | gawk /^F-/`" -a ! "$netfilter_ip_conntrack_ftp" != 'no' ] && mod_init ip_conntrack_ftp Error tcp_chain ${p:-21} ; tcp_chain 20 ;; ftp-passive) # TCP [ "`echo $chain0 | gawk /^F-/`" -a ! "$netfilter_ip_nat_ftp" != 'no' ] && mod_init ip_nat_ftp Error [ "`echo $chain0 | gawk /^F-/`" -a ! "$netfilter_ip_conntrack_ftp" != 'no' ] && mod_init ip_conntrack_ftp Error tcp_chain ${p:-21} ; tcp_chain 1024: 1024: est ;; ftp) # TCP [ "`echo $chain0 | gawk /^F-/`" -a ! "$netfilter_ip_nat_ftp" != 'no' ] && mod_init ip_nat_ftp Error [ "`echo $chain0 | gawk /^F-/`" -a ! "$netfilter_ip_conntrack_ftp" != 'no' ] && mod_init ip_conntrack_ftp Error tcp_chain ${p:-21} ; tcp_chain 20 ; tcp_chain 1024: 1024: est ;; ssh) tcp_chain ${p:-22} ;; # TCP telnet) tcp_chain ${p:-23} ;; # TCP smtp) tcp_chain ${p:-25} ;; # TCP time) tcp_chain ${p:-37} ;; # TCP whois) tcp_chain ${p:-43} ;; # TCP domain) tcp_chain ${p:-53} ; udp_chain ${p:-53} ;; # UDP dhcp|bootp) udp_chain ${p:-68} 67 ;; # UDP tftp) tcp_chain ${p:-69} ;; # TCP www|http) tcp_chain ${p:-80} ;; # TCP kerberos) tcp_chain ${p:-88} ;; # TCP pop3) tcp_chain ${p:-110} ;; # TCP auth) tcp_chain ${p:-113} ;; # TCP news) tcp_chain ${p:-119} ;; # TCP sftp) tcp_chain ${p:-115} ;; # TCP ntp) tcp_chain ${p:-123} ; udp_chain ${p:-123} ;; # TCP UDP netbios) udp_chain 137 137 ; udp_chain 138 138 ; tcp_chain 139 ; tcp_chain 445 ;; # TCP UDP netbios-ns) udp_chain 137 137 ;; # UDP netbios-dgm) udp_chain 138 138 ;; # UDP netbios-ssn) tcp_chain 139 ;; # TCP snmp) tcp_chain 161 ;; # TCP dconnect) tcp_chain ${p:-411} ; tcp_chain 1024: 1024: est ; udp_chain 1024: 1024: est ;; #TCP https) tcp_chain ${p:-443} ;; # TCP ssmtp) tcp_chain ${p:-465} ;; # TCP rsync) tcp_chain ${p:-873} ;; # TCP pop3s) tcp_chain ${p:-995} ;; # TCP rdesktop) tcp_chain ${p:-3389} ;; # TCP proxy) tcp_chain ${p:-8080} ;; # TCP postgres) tcp_chain ${p:-5432} ;; # TCP emule) tcp_chain ${p:-4662} ; udp_chain 4666 ;; # TCP UDP ircd) tcp_chain ${p:-4667} ;; # TCP donkey) tcp_chain ${p:-12002} ; udp_chain ${p:-12002} ;; # TCP UDP ######################## USER PROTOCOLS DEFINITION ######################## gadu-gadu) tcp_chain ${p:-8074} ;; # TCP vpn) udp_chain 500 500 ; udp_chain 4500 4500 ;; # UDP ########################################################################### tcp) tcp_chain $p ;; # TCP udp) udp_chain $p ;; # UDP tcpudp) tcp_chain $p ; udp_chain $p ;; # TCP UDP icmp*) # ICMP icmp_type=`echo $1 | gawk '{ gsub("^icmp-","") ; print }'` [ "$icmp_type" != 'icmp' ] && icmp_type="icmp -m icmp --icmp-type $icmp_type" [ "$target" = 'REJECT' -a ! "$req_icmp_chains_reject" ] && req_icmp_chains_reject [ "$target" = 'LOG' -a ! "$req_icmp_chains_log" ] && req_icmp_chains_log [ "$target" = 'DROP' -a ! "$req_icmp_chains_drop" ] && req_icmp_chains_drop echo "-A $chain0 -p $icmp_type -s ${sid_ad[0]} -d ${sid_ad[1]} $mac_src_chain0 $so_all -j ICMP-$target" >> $tmp-filter ;; all) [ "$target" = 'REJECT' -a ! "$req_all_chains_reject" ] && req_all_chains_reject [ "$target" = 'LOG' -a ! "$req_all_chains_log" ] && req_all_chains_log echo "-A $chain0 -s ${sid_ad[0]} -d ${sid_ad[1]} $mac_src_chain0 $so_all -j $target" >> $tmp-filter echo "-A $chain1 -s ${sid_ad[1]} -d ${sid_ad[0]} $mac_src_chain1 $so_all -j $target" >> $tmp-filter ;; *) # if we have service-port, set port and redo make_chain for this service p=`echo $service | gawk -v FS=- '/-[[:digit:]]+$/ { print $(NF) }'` if [ "$p" ]; then make_chain `echo $service | gawk -v FS=-$p '{ print $1 }'` else p=`echo $service | gawk -v FS=- '/^[[:digit:]]+$/ { print }'` if [ "$p" ]; then make_chain 'tcpudp' #break 1 else # look in /etc/services message 3 "Warrning: Unknown service $service in rule $rule_count: $rule" fi; fi; #unset p # strip service from rule esac unset p } iana_chain () { echo ':DROP_IANA - [0:0]' >> $tmp-filter [ ! "$req_udp_chains_log" ] && req_all_chains_log echo '-A DROP_IANA -j LOG' >> $tmp-filter echo '-A DROP_IANA -j DROP' >> $tmp-filter req_iana_chain='yes' } tcp_chain () { [ "$3" = 'est' ] && state=$state_established_related || state='' case $target in ACCEPT|REJECT|LOG|DROP) [ $target = 'REJECT' -a ! "$req_tcp_chains_reject" ] && req_tcp_chains_reject [ $target = 'LOG' -a ! "$req_tcp_chains_log" ] && req_tcp_chains_log [ $target = 'DROP' -a ! "$req_tcp_chains_drop" ] && req_tcp_chains_drop echo "-A $chain0 -p tcp -m tcp -s ${sid_ad[0]} --sport ${2:-1024:} -d ${sid_ad[1]} --dport $1 $mac_src_chain0 $state $so_all -j TCP-$target" >> $tmp-filter echo "-A $chain1 -p tcp -m tcp -s ${sid_ad[1]} --sport $1 -d ${sid_ad[0]} --dport ${2:-1024:} $mac_src_chain1 $state $so_all -j TCP-$target" >> $tmp-filter ;; DNAT) echo "-A PREROUTING -p tcp -m tcp -s ${sid_ad[0]} --sport 1024: -d ${sid_ad[1]} --dport $1 -j $target --to-destination $target_option" >> $tmp-nat dport=`echo $target_option | gawk '{ gsub("^.*:","") ; print }'` dip=`echo $target_option | gawk '{ gsub(":.*$","") ; print }'` diface=`get_if_from_ip $dip` [ ! "$diface" ] && diface=$ife client=`echo $client2 | gawk '{ gsub(":","_",$0) ; print }'` for dif in $diface; do server=`echo $dif | gawk '{ gsub(":","_",$0) ; print }'` [ ! $(eval echo \$fwd_chain_${client}_${server}) ] && req_forward_chain $client2 $dif echo "-A F-$client-$dif -p tcp -m tcp -s ${sid_ad[0]} --sport 1024: -d $dip --dport $dport $state $so_all -j TCP-ACCEPT" >> $tmp-filter echo "-A F-$dif-$client -p tcp -m tcp -s $dip --sport $dport -d ${sid_ad[0]} --dport 1024: $state $so_all -j TCP-ACCEPT" >> $tmp-filter done unset dif dip diface dport esac } get_if_from_ip () { ip=`echo $1 | gawk -v FS="." '/\// { gsub("/",".") ; print and($1,$5)"."and($2,$6)"."and($3,$7)"."and($4,$8) }'` [ ! "$ip" ] && ip=$1 for i in $ifi $ife; do ip_calc=$(eval echo \${$i[2]}).$(eval echo \${$i[3]}) [ "`echo $ip_calc.$ip | gawk -v FS=. '{ if ( and($1,$5) == and($9,$5) && and($2,$6) == and($10,$6) && and($3,$7) == and($11,$7) && and($4,$8) == and($12,$8) ) print "ok" }'`" ] && break || i='' done unset ip ip_calc echo $i } udp_chain () { [ "$3" = 'est' ] && state=$state_established_related || state='' [ "$target" = 'REJECT' -a ! "$req_udp_chains_reject" ] && req_udp_chains_reject [ "$target" = 'LOG' -a ! "$req_udp_chains_log" ] && req_udp_chains_log [ "$target" = 'DROP' -a ! "$req_udp_chains_drop" ] && req_udp_chains_drop echo "-A $chain0 -p udp -m udp -s ${sid_ad[0]} --sport ${2:-1024:} -d ${sid_ad[1]} --dport $1 $mac_src_chain0 $state $so_all -j UDP-$target" >> $tmp-filter echo "-A $chain1 -p udp -m udp -s ${sid_ad[1]} --sport $1 -d ${sid_ad[0]} --dport ${2:-1024:} $mac_src_chain1 $state $so_all -j UDP-$target" >> $tmp-filter } req_tcp_chains () { if [ ! $req_tcp_chains ]; then echo ":TCP-ACCEPT - [0:0]" >> $tmp-filter if [ "$tcpmaxsynrate" ]; then [ ! "$netfilter_ipt_limit" ] && mod_init ipt_limit Warrning [ "$netfilter_ipt_limit" != 'no' ] && tcpmaxsynrate="-m limit --limit $tcpmaxsynrate --limit-burst $tcpmaxburst" || unset tcpmaxsynrate fi; echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL SYN $state_new_related $tcpmaxsynrate -j ACCEPT" >> $tmp-filter [ "$tcpmaxsynrate" ] && echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL SYN $state_new $lograte -j LOG --log-prefix \"GL-SYN_RATE \"" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL SYN -j DROP" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL ACK,SYN $state_established $mss -j ACCEPT" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL ACK $state_new_established -j ACCEPT" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL ACK,PSH $state_established -j ACCEPT" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL ACK,RST $state_established -j ACCEPT" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL ACK,FIN -j ACCEPT" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL ACK,FIN,PSH -j ACCEPT" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL URG,PSH,SYN,FIN $lograte -j LOG --log-prefix \"O_SCAN \"" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL URG,PSH,SYN,FIN -j DROP" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL FIN $lograte -j LOG --log-prefix \"sF_SCAN \"" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL FIN -j DROP" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL URG,PSH,FIN $lograte -j LOG --log-prefix \"sX_SCAN \"" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL URG,PSH,FIN -j DROP" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL NONE $lograte -j LOG --log-prefix \"sN_SCAN \"" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL NONE -j DROP" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL ACK $lograte -j LOG --log-prefix \"sA_SCAN \"" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL ACK -j DROP" >> $tmp-filter # do not log RST packets for non-established connections echo "-A TCP-ACCEPT -p tcp -m tcp --tcp-flags ALL RST -j DROP" >> $tmp-filter echo "-A TCP-ACCEPT -p tcp -m tcp $lograte -j LOG --log-prefix \"BAD_FLAGS \"" >> $tmp-filter echo "-A TCP-ACCEPT -j DROP" >> $tmp-filter fi; req_tcp_chains='yes' } req_tcp_chains_reject () { [ ! "$netfilter_ipt_REJECT" ] && mod_init ipt_REJECT Error echo ":TCP-REJECT - [0:0]" >> $tmp-filter echo "-A TCP-REJECT -p tcp -m tcp -j REJECT" >> $tmp-filter req_tcp_chains_reject='yes' } req_tcp_chains_log () { [ ! "$netfilter_ipt_LOG" ] && mod_init ipt_LOG Error echo ":TCP-LOG - [0:0]" >> $tmp-filter echo "-A TCP-LOG -p tcp -m tcp $lograte -j LOG" >> $tmp-filter req_tcp_chains_log='yes' } req_tcp_chains_drop () { echo ":TCP-DROP - [0:0]" >> $tmp-filter echo "-A TCP-DROP -p tcp -m tcp -j DROP" >> $tmp-filter req_tcp_chains_drop='yes' } req_udp_chains () { if [ ! $req_udp_chains ]; then echo ":UDP-ACCEPT - [0:0]" >> $tmp-filter if [ "$udpmaxrate" ]; then [ ! "$netfilter_ipt_limit" ] && mod_init ipt_limit Warrning [ "$netfilter_ipt_limit" != 'no' ] && udpmaxrate="-m limit --limit $udpmaxrate --limit-burst $udpmaxburst" || unset udpmaxrate fi; [ ! "$netfilter_ipt_length" ] && mod_init ipt_length Warrning if [ "$netfilter_ipt_length" != 'no' ]; then echo "-A UDP-ACCEPT -p udp $udpmaxrate -m length --length 29:65535 -j ACCEPT" >> $tmp-filter echo "-A UDP-ACCEPT -p udp $udpmaxrate -m length --length 28 -j LOG --log-prefix \"oU_SCAN \"" >> $tmp-filter echo "-A UDP-ACCEPT -p udp $udpmaxrate -m length --length 28 -j DROP" >> $tmp-filter fi; [ "$udpmaxrate" ] && echo "-A UDP-ACCEPT -p udp -m udp $lograte -j LOG --log-prefix \"GL-UDP_RATE \"" >> $tmp-filter [ "$udpmaxrate" ] && echo "-A UDP-ACCEPT -j DROP" >> $tmp-filter fi; req_udp_chains='yes' } req_udp_chains_reject () { [ ! "$netfilter_ipt_REJECT" ] && mod_init ipt_REJECT Error echo ":UDP-REJECT - [0:0]" >> $tmp-filter echo "-A UDP-REJECT -p udp -m udp -j REJECT" >> $tmp-filter req_udp_chains_reject='yes' } req_udp_chains_log () { [ ! "$netfilter_ipt_LOG" ] && mod_init ipt_LOG Error echo ":UDP-LOG - [0:0]" >> $tmp-filter echo "-A UDP-LOG -p udp -m udp $lograte -j LOG" >> $tmp-filter req_udp_chains_log='yes' } req_udp_chains_drop () { echo ":UDP-DROP - [0:0]" >> $tmp-filter echo "-A UDP-DROP -p udp -m udp -j DROP" >> $tmp-filter req_udp_chains_drop='yes' } req_icmp_chains () { if [ ! $req_icmp_chains ]; then echo ":ICMP-ACCEPT - [0:0]" >> $tmp-filter if [ "$icmpmaxrate" ]; then [ ! "$netfilter_ipt_limit" ] && mod_init ipt_limit Warrning [ "$netfilter_ipt_limit" != 'no' ] && icmpmaxrate="-m limit --limit $icmpmaxrate" || unset icmpmaxrate fi; echo "-A ICMP-ACCEPT -p icmp -m icmp $icmpmaxrate -j ACCEPT" >> $tmp-filter [ "$icmpmaxrate" ] && echo "-A ICMP-ACCEPT -p icmp -m icmp $lograte -j LOG --log-prefix \"GL-ICMP_RATE \"" >> $tmp-filter [ "$icmpmaxrate" ] && echo "-A ICMP-ACCEPT -j DROP" >> $tmp-filter fi; req_icmp_chains='yes' } req_icmp_chains_reject () { [ ! "$netfilter_ipt_REJECT" ] && mod_init ipt_REJECT Error echo ":ICMP-REJECT - [0:0]" >> $tmp-filter echo "-A ICMP-REJECT -p icmp -m icmp -j REJECT" >> $tmp-filter req_icmp_chains_reject='yes' } req_icmp_chains_log () { [ ! "$netfilter_ipt_LOG" ] && mod_init ipt_LOG Error echo ":ICMP-LOG - [0:0]" >> $tmp-filter echo "-A ICMP-LOG -p icmp -m icmp $lograte -j LOG" >> $tmp-filter req_icmp_chains_log='yes' } req_icmp_chains_drop () { echo ":ICMP-DROP - [0:0]" >> $tmp-filter echo "-A ICMP-DROP -p icmp -m icmp -j LOG" >> $tmp-filter req_icmp_chains_drop='yes' } req_all_chains_reject () { [ ! "$netfilter_ipt_REJECT" ] && mod_init ipt_REJECT Error req_all_chains_reject='yes' } req_all_chains_log () { [ ! "$netfilter_ipt_LOG" ] && mod_init ipt_LOG Error req_all_chains_log='yes' } req_nat_chain () { [ ! "$netfilter_iptable_nat" ] && mod_init iptable_nat Error if [ "$1" != 'nomasq' ]; then if [ $(eval echo \${$server[6]}) = 'e' ]; then is=$(eval echo \${$server[1]}) # strip aliases ic_net=$(eval echo \${$client[4]}) if [ "$static_ip" = 'no' ]; then [ ! "$netfilter_ipt_MASQUERADE" ] && mod_init ipt_MASQUERADE Error echo "-A POSTROUTING -o $is -s $ic_net -j MASQUERADE" >> $tmp-nat else echo "-A POSTROUTING -o $is -s $ic_net -j SNAT --to-source $(eval echo \${$server[2]})" >> $tmp-nat fi; fi; req_nat_chain="$req_nat_chain $client-$server " fi } req_inputoutput_chain () { i=$(eval echo \${$1[0]}) i_addr=$(eval echo \${$1[2]}) i_net='0/0' ; [ $(eval echo \${$1[6]}) = 'i' ] && i_net=$(eval echo \${$1[4]}) i_bcast=$(eval echo \${$1[5]}) i2=$(eval echo \${$1[1]}) # strip aliases echo ":I-$i - [0:0]" >> $tmp-filter echo ":O-$i - [0:0]" >> $tmp-filter echo "-A INPUT -i $i2 $dontfragment -s $i_net -d $i_addr -j I-$i" >> $tmp-filter if [ "`echo $broadcasts | gawk /"(^| )"$i"( |$)"/`" ]; then echo "-A INPUT -i $i2 $dontfragment -s $i_net -d $i_bcast -j I-$i" >> $tmp-filter echo "-A INPUT -i $i2 $dontfragment -s $i_net -d 255.255.255.255 -j I-$i" >> $tmp-filter [ "`echo $ifi | gawk /"(^| )"$1"( |$)"/`" ] && echo "-A INPUT -i $i2 $dontfragment -s 0.0.0.0 -d 255.255.255.255 -j I-$i" >> $tmp-filter fi; if [ "`echo $multicasts | gawk /"(^| )"$i"( |$)"/`" ]; then echo "-A INPUT -i $i2 $dontfragment -s $i_net -d 224.0.0.0/8 -j I-$i" >> $tmp-filter fi; echo "-A OUTPUT -o $i2 $dontfragment -s $i_addr -d $i_net -j O-$i" >> $tmp-filter echo "-A OUTPUT -o $i2 $dontfragment -s $i_addr -d 255.255.255.255 -j O-$i" >> $tmp-filter echo "-A OUTPUT -o $i2 $dontfragment -s $i_addr -d 224.0.0.0/8 -j O-$i" >> $tmp-filter [ "`echo $ifi | gawk /"(^| )"$1"( |$)"/`" ] && echo "-A OUTPUT -o $i2 $dontfragment -s 0.0.0.0 -d 255.255.255.255 -j O-$i" >> $tmp-filter # for internal interface we should accept also packets directed to external interface(s) IP(s) if [ $(eval echo \${$1[6]}) = 'i' ]; then ## blad - sparametryzowac for i3 in $ife; do i3_addr=$(eval echo \${$i3[2]}) echo "-A INPUT -i $i2 $dontfragment -s $i_net -d $i3_addr -j I-$i" >> $tmp-filter echo "-A OUTPUT -o $i2 $dontfragment -s $i3_addr -d $i_net -j O-$i" >> $tmp-filter done else # for external interface we optionaly filter IANA reserved adresses.... if [ "`echo $block_iana_if | gawk /"(^| )"$i"( |$)"/`" ]; then ## blad - glowny lancuhc [ ! "$req_iana_chain" ] && iana_chain for iana_source in `echo $iana_reserved`; do echo "-A I-$i -s $iana_source -j DROP_IANA" >> $tmp-filter echo "-A O-$i -d $iana_source -j DROP_IANA" >> $tmp-filter done fi; fi; eval io_chain_$1='y' } req_forward_chain () { c=$1 s=$2 # [ ! "`echo $req_nat_chain | gawk /$c-$s/`" ] && req_nat_chain $3 if [ ! "$ipforwarding" ]; then if [ ! -f "/proc/sys/net/ipv4/ip_forward" ]; then message 2 "Error: IP forwarding is required for some rules, but it cant be set in kernel" fi; echo 1 > /proc/sys/net/ipv4/ip_forward ipforwarding='yes' [ "$clampmsstopmtu" = 'yes' ] && echo "-A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu" >> $tmp-filter fi; # for external interfaces we allow all clients/servers, for internal only within interface class ii_net='0/0' ; [ $(eval echo \${$client[6]}) = 'i' ] && ii_net=$(eval echo \${$client[4]}) is_net='0/0' ; [ $(eval echo \${$server[6]}) = 'i' ] && is_net=$(eval echo \${$server[4]}) ic=$(eval echo \${$client[1]}) # strip aliases is=$(eval echo \${$server[1]}) # strip aliases echo ":F-$c-$s - [0:0]" >> $tmp-filter echo ":F-$s-$c - [0:0]" >> $tmp-filter echo "-A FORWARD -i $is -o $ic $dontfragment -s $is_net -d $ii_net -j F-$s-$c" >> $tmp-filter echo "-A FORWARD -i $ic -o $is $dontfragment -s $ii_net -d $is_net -j F-$c-$s" >> $tmp-filter # and optionaly filter IANA reserved adresses.... if [ $(eval echo \${$server[6]}) = 'e' ]; then ## blad - glowyn lancych if [ "`echo $block_iana_if | gawk /$is/`" ]; then [ ! "$req_iana_chain" ] && iana_chain for iana_source in `echo $iana_reserved`; do echo "-A F-$c-$s -d $iana_source -j DROP_IANA" >> $tmp-filter echo "-A F-$s-$c -s $iana_source -j DROP_IANA" >> $tmp-filter done fi fi eval fwd_chain_${client}_${server}='y' eval fwd_chain_${server}_${client}='y' } init_tmp_files () { rm -rf $tmp* [ -e "$tmp-filter" -o -e "$tmp-nat" -o -e "$tmp-mangle" -o -e "$tmp" ] && message 2 "Error: lutel firewall was unable to clean up its /tmp files, exiting!" echo -e "*filter\n:INPUT $filter [0:0]\n:FORWARD $filter [0:0]\n:OUTPUT $filter [0:0]" > $tmp-filter echo -e "*nat\n:PREROUTING ACCEPT [0:0]\n:POSTROUTING ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]" > $tmp-nat echo -e "*mangle\n:PREROUTING ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]" > $tmp-mangle # old netfilter chmod 0600 $tmp* 2>/dev/null chown $firwall_uid $tmp* 2>/dev/null } protocol_mismatch_log () { echo ":UNKNOWN_PROTO_LOG - [0:0]" >> $tmp-filter for prot in $supported_protocols; do echo "-A UNKNOWN_PROTO_LOG -p $prot -j RETURN" >> $tmp-filter done echo "-A UNKNOWN_PROTO_LOG -j LOG --log-prefix \"sO_SCAN \"" >> $tmp-filter echo "-A INPUT -j UNKNOWN_PROTO_LOG" >> $tmp-filter echo "-A FORWARD -j UNKNOWN_PROTO_LOG" >> $tmp-filter echo "-A OUTPUT -j UNKNOWN_PROTO_LOG" >> $tmp-filter } commit_and_execute () { [ "$command" = "start" -o "$command" = "start-filter" ] && protocol_mismatch_log echo COMMIT >> $tmp-filter echo COMMIT >> $tmp-mangle echo COMMIT >> $tmp-nat [ ! "`$T -t filter -P INPUT ACCEPT 2>&1 1>/dev/null`" ] && netfilter_iptable_filter='y' [ ! "`$T -t nat -P OUTPUT ACCEPT 2>&1 1>/dev/null`" ] && netfilter_iptable_nat='y' [ ! "`$T -t mangle -P OUTPUT ACCEPT 2>&1 1>/dev/null`" ] && netfilter_iptable_mangle='y' [ "$1" = 'script' ] && TR='cat' || TR="$TR -c" case $command in start|stop) [ "$netfilter_iptable_filter" ] && cat $tmp-filter >> $tmp [ "$netfilter_iptable_nat" ] && cat $tmp-nat >> $tmp [ "$netfilter_iptable_mangle" ] && cat $tmp-mangle >> $tmp [ -f $tmp ] && cat $tmp | $TR ;; start-filter|stop-filter) [ "$netfilter_iptable_filter" ] && cat $tmp-filter | $TR ;; start-nat|stop-nat) [ "$netfilter_iptable_nat" ] && cat $tmp-nat | $TR ;; start-mangle|stop-mangle) [ "$netfilter_iptable_mangle" ] && cat $tmp-mangle | $TR ;; esac [ "$clean_tmp_on_exit" != 'no' ] && rm -rf $tmp* } mod_init () { # Load netfilter modules if nessecary, check support for iptables extensions [ -d /lib/modules/`uname -r`/kernel/net/ipv4/netfilter ] && modprobe $1 2>/dev/null eval netfilter_$1='y' case $1 in iptable_filter) mod_init_check "-L -n -t filter" "IPtables not supported by current kernel" $2 $1 ;; iptable_nat) mod_init_check "-L -n -t nat" "NAT table not supported by current kernel" $2 $1 ;; iptable_mangle) mod_init_check "-L -n -t mangle" "Mangle table not supported by current kernel" $2 $1 ;; ipt_state) mod_init iptable_filter mod_init_check "-A INPUT -m state --state ESTABLISHED -j ACCEPT" "STATE match (CONFIG_IP_NF_MATCH_STATE) not supported by current kernel, stateful checking is disabled and its strongly recommended to upgrade your kernel" $2 $1 ;; ipt_limit) mod_init iptable_filter mod_init_check "-A INPUT -m limit --limit 2/s -j ACCEPT" "LIMIT match (CONFIG_IP_NF_MATCH_LIMIT) not supported by current kernel, all rate checks disabled" $2 $1 ;; ipt_MASQUERADE) mod_init_check "-t nat -A POSTROUTING -j MASQUERADE" "MASQUERADE target (CONFIG_IP_NF_TARGET_MASQUERADE) not supported by current kernel, masquerading disabled" $2 $1 ;; ipt_length) mod_init iptable_filter mod_init_check "-A INPUT -m length --length 100 -j ACCEPT" "LENGTH match (CONFIG_IP_NF_MATCH_LENGTH) not supported by current kernel, all length checks disabled" $2 $1 ;; ip_nat_ftp) ;; ip_conntrack_ftp) ;; esac } mod_init_check () { if [ "`$T $1 2>&1 1>/dev/null`" -a "$3" != 'ignore' ]; then echo -en "\n$3: $2." [ $ignore_errors = 'false' -a "$3" = 'Error' ] && exit 1 eval netfilter_$4='no' fi; rule_remove=`echo $1 | gawk '/-A/{ gsub("-A","-D") ; print }'` [ "$rule_remove" ] && `$T $rule_remove 2>>/dev/null` } modules_unload () { # Unload all netfilter modules which are no longer used if [ -f /lib/modules/`uname -r`/kernel/net/ipv4/netfilter/ip_tables.* ]; then # list of all known netfilter modules, in oder they should be unloaded.... modlist="arpt_mangle arptable_filter ip_nat_amanda ip_nat_ftp ip_nat_irc ip_nat_snmp_basic ip_nat_tftp ip_queue ipt_CLASSIFY ipt_DSCP ipt_ECN ipt_LOG ipt_MARK ipt_MASQUERADE ipt_NETMAP ipt_NOTRACK ipt_REDIRECT ipt_REJECT ipt_SAME ipt_TCPMSS ipt_TOS ipt_ULOG ipt_ah ipt_conntrack ipt_dscp ipt_ecn ipt_esp ipt_helper ipt_iprange ipt_length ipt_limit ipt_mac ipt_mark ipt_multiport ipt_owner ipt_pkttype ipt_recent ipt_state ipt_tcpmss ipt_tos ipt_ttl iptable_filter iptable_mangle iptable_raw ip_conntrack_amanda ip_conntrack_ftp ip_conntrack_irc ip_conntrack_tftp arp_tables iptable_nat ip_tables" for f in $modlist; do modprobe -r $f 2>/dev/null done fi } for param in $*; do [ ! "$command" ] && command=`echo $param | gawk '/start|stop|stats|status|update/{ print }'` [ ! "$verbose" ] && verbose=`echo $param | gawk '/^verbose=[[:digit:]]$/{ gsub("verbose=","",$0) ; print }'` [ ! "$script" ] && script=`echo $param | gawk '/^script$/{ print }'` done case $command in start|start-filter|start-nat|start-mangle) filter=$policy_filter_start [ "$verbose" != '0' ] && echo -n 'Starting Lutel Firewall ' init_tmp_files init $verbose init_interfaces set_global_variables iana_reserved_update [ "$new_version_check" = 'yes' ] && new_version_check [ "$seti" = 'yes' ] && seti proc_restrictions init_chains rule_parser commit_and_execute $script date > $status_file 2>/dev/null chmod 0600 $status_file 2>/dev/null [ "$verbose" != '0' ] && echo '. OK' ;; stop|stop-filter|stop-nat|stop-mangle) filter=$policy_filter_stop [ "$verbose" != '0' ] && echo -n 'Stopping Lutel Firewall ' init_tmp_files commit_and_execute $script modules_unload rm -f $status_file [ "$verbose" != '0' ] && echo '. OK' ;; stats|stats-filter|stats-nat|stats-mangle) case $command in stats) $T -L -v -n -t filter ; $T -L -v -n -t nat ; $T -L -v -n -t mangle ;; stats-filter) $T -L -v -n -t filter ;; stats-nat) $T -L -v -n -t nat ;; stats-mangle) $T -L -v -n -t mangle ;; esac ;; update) echo -n 'Looking for updates ' output=5 new_version_check='yes' new_version_check echo '. OK' ;; status) [ -f $status_file ] && echo "Lutel Firewall is running since `cat $status_file`" || echo 'Lutel Firewall is stopped' ;; *) echo -e "${bold}Lutel Firewall $current_version${norm} http://firewall.lutel.pl" echo 'Usage: firewall { start[-filter|-nat|-mangle] [script] [verbose=n] |' echo ' stop[-filter|-nat|-mangle] [script] [verbose=n] |' echo ' config | stats | status }' echo echo ' start - Start firewall (filtering, NAT and mangling)' echo ' start-filter - Start firewall filter only' echo ' start-nat - Start firewall NAT/DNAT and masquerade only' echo ' start-mangle - Start firewall mangling part only' echo echo ' stop - Start firewall (filtering, NAT and mangling)' echo ' stop-filter - Start firewall filter only' echo ' stop-nat - Start firewall NAT/DNAT and masquerade only' echo ' stop-mangle - Start firewall mangling part only' echo echo ' stats - Show all chains from all tables with byte counters' echo ' stats-filter - Show all chains from filter table with byte counters' echo ' stats-nat - Show all chains from nat table with byte counters' echo ' stats-mangle - Show all chains from mangle table with byte counters' echo echo ' script - dump IP Tables to STDOUT (iptables-restore format)' echo ' verbose=n - verbosity level from 0 (quiet) to 6 (debug)' echo ' update - Update firewall script' echo ' status - Firewall status' exit 1 esac exit 0