#!/bin/sh
#
# This will be universal firewalling script in near future
# Can be started by init or by hand.
#
# Developed by Lubomir Host 'rajo' <rajo AT platon.sk>
# Copyright (c) 2003 Platon SDG, http://platon.sk/
# Licensed under terms of GNU General Public License.
# All rights reserved.
#
# $Platon: $
#
#
# Config:
#
DESC="firewall"
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DEFAULT_POLICY="DROP"
# which modules to load
MODULES="ipt_LOG ipt_REJECT ip_conntrack_ftp"
LOG_LIMIT="-m limit --limit 12/h --limit-burst 10"
# Paths:
IPTABLES="/sbin/iptables"
#IPTABLES=":" # for testing only - does nothing
IFCONFIG="/sbin/ifconfig"
DEPMOD="/sbin/depmod"
MODPROBE="/sbin/modprobe"
RMMOD="/sbin/rmmod"
AWK="/usr/bin/awk"
# interface connected to cruel world (internet jungle)
INET_IFACE="eth0"
INET_IP="IP_$INET_IFACE"
# loopback interface
LO_IFACE="lo"
LO_IP="IP_$LO_IFACE"
# Which ports will be allowed on INPUT (TCP connections)
# 21 - ftp, 22 - ssh, 25 - smtp, 53 - DNS server TCP, 80 - www, 110 - POP3
# 143 - IMAP, 443 - HTTPS, 873 - rsync server
# 123 137 138 139 631 - samba
ACCEPT_INPUT_TCP="123 137 138 139 631 22 80"
# Which ports will be allowed on INPUT (UDP connections)
# 53 - DNS server, 517 - talk, 518 - ntalk
ACCEPT_INPUT_UDP="123 137 138 139 631"
# allow some ICMP packets - needed for ping etc.
ACCEPT_ICMP_PACKETS="echo-reply destination-unreachable echo-request time-exceeded"
# load necessary modules from $MODULES variable
load_modules()
{ # {{{
echo "# Loading modules"
for mod in $MODULES; do
echo " $MODPROBE $mod"
$MODPROBE $mod
done
} # }}}
# unload necessary modules from $MODULES variable
unload_modules()
{ # {{{
# reverse modules
echo "# Removing modules"
R_MODULES=`echo "$MODULES" | tr ' ' '\012' | tac | tr '\012' ' '`
for mod in $R_MODULES; do
echo " $RMMOD $mod"
$RMMOD $mod
done
} # }}}
# print status of found interfaces
print_iface_status()
{ # {{{
# Print interfaces:
echo "# iface | IP addr | broadcast | netmask | HW addr"
for iface in $interfaces; do
IP="IP_$iface"; Bcast="Bcast_$iface"; Mask="Mask_$iface"; HWaddr="HWaddr_$iface";
echo "$iface | ${!IP} | ${!Bcast} | ${!Mask} | ${!HWaddr}"
done
} # }}}
# set default policy (variable $DEFAULT_POLICY)
set_default_policy()
{ # {{{
# Set default policy
for chain in INPUT OUTPUT FORWARD; do
$IPTABLES -P $chain $DEFAULT_POLICY
done
} # }}}
antispoof_on()
{ # {{{
for interface in /proc/sys/net/ipv4/conf/*/rp_filter; do
echo "1" > ${interface}
done
} # }}}
# clear status of iptable chains
remove_chains()
{ # {{{
$IPTABLES -F # clear all chains
$IPTABLES -X # remove all chains
} # }}}
# all packets on loopback are accted
set_loopback()
{ # {{{
$IPTABLES -A INPUT -j ACCEPT -i $LO_IFACE
$IPTABLES -A OUTPUT -j ACCEPT -o $LO_IFACE
} # }}}
# DROP packages from nmap(1)
nmap_scan_filter()
{ # {{{
echo -en "Turning on nmap scan filter "
for chain in INPUT FORWARD; do
echo -en "."
# Nie je nastaveny ziaden bit
$IPTABLES -A $chain -p tcp --tcp-flags ALL NONE $LOG_LIMIT -j LOG --log-prefix "nmap scan $chain ALL NONE: "
$IPTABLES -A $chain -p tcp --tcp-flags ALL NONE -j DROP
# dva odporujuuce si flagy su nastavene:
for flags in SYN,FIN SYN,RST FIN,RST ; do
echo -en "."
$IPTABLES -A $chain -p tcp --tcp-flags $flags $flags $LOG_LIMIT -j LOG --log-prefix "nmap scan $chain $flags: "
$IPTABLES -A $chain -p tcp --tcp-flags $flags $flags -j DROP
done
# je nastavene len $flags bez predpokladaneho ACK
for flags in FIN PSH URG ; do
echo -en "."
$IPTABLES -A $chain -p tcp --tcp-flags ACK,$flags $flags $LOG_LIMIT -j LOG --log-prefix "nmap scan $chain ACK,$flags: "
$IPTABLES -A $chain -p tcp --tcp-flags ACK,$flags $flags -j DROP
done
done
echo "done."
} # }}}
# drop packets in state INVALID
invalid_packet_filter()
{ # {{{
echo -en "Turning on INVALID packet filter "
for chain in INPUT OUTPUT FORWARD; do
echo -en "."
$IPTABLES -A $chain -m state --state INVALID $LOG_LIMIT -j LOG --log-prefix "INVALID $chain: "
$IPTABLES -A $chain -m state --state INVALID -j DROP
done
echo "done."
} # }}}
syn_flood()
{ # {{{
$IPTABLES -N syn-flood
$IPTABLES -A syn-flood -m limit --limit 1/s --limit-burst 4 -j RETURN
$IPTABLES -A syn-flood -j DROP
$IPTABLES -A INPUT -i $INET_IFACE -p tcp --syn -j syn-flood
# Paket je označený jako NEW, ale nemá nastavený SYN flag - pryč s ním
$IPTABLES -A INPUT -i $INET_IFACE -p tcp ! --syn -m state --state NEW -j DROP
} # }}}
anti_spoof_filter()
{ # {{{
# http://www.iana.com/assignments/ipv4-address-space
$IPTABLES -N spoof
echo "Turning on antispoof filter for interface $INET_IFACE "
# Ochrana proti Spoogingu zo spetnej slucky
$IPTABLES -A spoof -i $INET_IFACE -s 127.0.0.0/8 $LOG_LIMIT -j LOG --log-prefix "Reserved IP:127.0.0.0/8 src"
$IPTABLES -A spoof -i $INET_IFACE -s 127.0.0.0/8 -j DROP
$IPTABLES -A spoof -i $INET_IFACE -d 127.0.0.0/8 $LOG_LIMIT -j LOG --log-prefix "Reserved IP:127.0.0.0/8 dest"
$IPTABLES -A spoof -i $INET_IFACE -d 127.0.0.0/8 -j DROP
# Ochrana proti Spoofingu Internetu z adries urcenych pre lokalne siete
$IPTABLES -A spoof -i $INET_IFACE -s 192.168.0.0/16 $LOG_LIMIT -j LOG --log-prefix "Reserved IP:192.168.0.0/16 src"
$IPTABLES -A spoof -i $INET_IFACE -s 192.168.0.0/16 -j DROP # RFC1918
$IPTABLES -A spoof -i $INET_IFACE -s 172.16.0.0/12 $LOG_LIMIT -j LOG --log-prefix "Reserved IP:172.16.0.0/12 src"
$IPTABLES -A spoof -i $INET_IFACE -s 172.16.0.0/12 -j DROP # RFC1918
$IPTABLES -A spoof -i $INET_IFACE -s 10.0.0.0/8 $LOG_LIMIT -j LOG --log-prefix "Reserved IP:10.0.0.0/8 src"
$IPTABLES -A spoof -i $INET_IFACE -s 10.0.0.0/8 -j DROP # RFC1918 len pre sietovy interface do Internetu, kedze 10.0.0.0 je adresa LAN
$IPTABLES -A spoof -i $INET_IFACE -s 96.0.0.0/4 $LOG_LIMIT -j LOG --log-prefix "Reserved IP:96.0.0.0/4 src"
$IPTABLES -A spoof -i $INET_IFACE -s 96.0.0.0/4 -j DROP # IANA
echo "... done."
} # }}}
mangle_prerouting()
{ # {{{
echo "Optimizing PREROUTING TOS"
# TOS flagy slouzi k optimalizaci datovych cest. Pro ssh, ftp a telnet
# pozadujeme minimalni zpozdeni. Pro ftp-data zase maximalni propostnost
$IPTABLES -t mangle -A PREROUTING -p tcp --sport ssh -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A PREROUTING -p tcp --dport ssh -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A PREROUTING -p tcp --sport ftp -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A PREROUTING -p tcp --dport ftp -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A PREROUTING -p tcp --dport telnet -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A PREROUTING -p tcp --sport ftp-data -j TOS --set-tos Maximize-Throughput
} # }}}
mangle_output()
{ # {{{
echo "Optimizing OUTPUT TOS"
# TOS flagy slouzi k optimalizaci datovych cest. Pro ssh, ftp a telnet
# pozadujeme minimalni zpozdeni. Pro ftp-data zase maximalni propostnost
$IPTABLES -t mangle -A OUTPUT -o $INET_IFACE -p tcp --sport ssh -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -o $INET_IFACE -p tcp --dport ssh -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -o $INET_IFACE -p tcp --sport ftp -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -o $INET_IFACE -p tcp --dport ftp -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -o $INET_IFACE -p tcp --dport telnet -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -o $INET_IFACE -p tcp --sport ftp-data -j TOS --set-tos Maximize-Throughput
} # }}}
# accept TCP packets for ports in $ACCEPT_INPUT_TCP
# accept UDP packets for ports in $ACCEPT_INPUT_UDP
allow_input()
{ # {{{
if [ ! -z "$ACCEPT_INPUT_TCP" ]; then
echo -en "Accepting INPUT TCP connections on ports: "
for port in $ACCEPT_INPUT_TCP; do
echo -en " $port"
$IPTABLES -A INPUT -i $INET_IFACE -d ${!INET_IP} -p TCP --dport $port -j ACCEPT
done
echo "."
fi
if [ ! -z "$ACCEPT_INPUT_UDP" ]; then
echo -en "Accepting INPUT UDP connections on ports: "
for port in $ACCEPT_INPUT_UDP; do
echo -en " $port"
#$IPTABLES -A INPUT -i $INET_IFACE -d ${!INET_IP} -p UDP --dport $port -j ACCEPT
$IPTABLES -A INPUT -i $INET_IFACE -p UDP --dport $port -j ACCEPT
done
echo "."
fi
} # }}}
# ACCEPT all packets from our IP address
allow_output()
{ # {{{
# Povolíme odchozí pakety, které mají naše IP adresy
echo "Accepting OUTPUT packets from ${!LO_IP} ${!INET_IP}"
$IPTABLES -A OUTPUT -s ${!LO_IP} -j ACCEPT
$IPTABLES -A OUTPUT -s ${!INET_IP} -j ACCEPT
} # }}}
allow_icmp()
{ # {{{
echo -en "Accepting ICMP packets:"
# Službu AUTH není dobré filtrovat pomocí DROP, protože to může
# vést k prodlevám při navazování některých spojení. Proto jej
# sice zamítneme, ale vygenerujeme korektní ICMP chybovou zprávu
$IPTABLES -A INPUT -i $INET_IFACE -p TCP --dport 113 -j REJECT --reject-with tcp-reset #AUTH server
# accept only allowed ICMP packets
for type in $ACCEPT_ICMP_PACKETS; do
echo -en " $type"
$IPTABLES -A INPUT -i $INET_IFACE -p ICMP --icmp-type $type -j ACCEPT
done
echo " done."
} # }}}
log_input_drop()
{ # {{{
prefix="input drop: "
echo "Input drop is logged with prefix '$prefix'"
$IPTABLES -A INPUT $LOG_LIMIT -j LOG --log-prefix "$prefix"
} # }}}
log_output_drop()
{ # {{{
prefix="output drop: "
echo "Output drop is logged with prefix '$prefix'"
# Ostatní pakety logujeme (neměly by být žádné takové)
$IPTABLES -A OUTPUT $LOG_LIMIT -j LOG --log-prefix "$prefix"
} # }}}
accept_related()
{ # {{{
echo "Accepting ESTABLISHED, RELATED packets for IP ${!INET_IP}"
$IPTABLES -A INPUT -d ${!INET_IP} -m state --state ESTABLISHED,RELATED -j ACCEPT
} # }}}
accept_loopback()
{ # {{{
# Loopback není radno omezovat
echo "Accepting loopback"
$IPTABLES -A INPUT -i $LO_IFACE -j ACCEPT
} # }}}
# Parse output from ifconfig: - tested on Linux and FreeBSD
# -- creates shell variables like IP_eth0="192.168.1.123"
# http://platon.sk/cvs/cvs.php/scripts/shell/firewall/ifconfig-parse.sh
parse_ifconfig()
{ # {{{
# Parse output from ifconfig:
eval `$IFCONFIG | \
$AWK 'BEGIN { interfaces=""; }
/^[a-zA-Z0-9]+[ \t]+/ { # Linux
iface=$1;
interfaces = sprintf("%s %s", interfaces, iface);
printf "\nIFACE_%s=\"%s\"; export IFACE_%s;\n", iface, iface, iface;
printf "HWaddr_%s=\"%s\"; export HWaddr_%s;\n", iface, $5, iface;
}
/^[ \t]+inet addr:/ { # Linux
split($0, fields, "[ \t:]+");
printf "IP_%s=\"%s\"; export IP_%s;\n", iface, fields[4], iface;
printf "Bcast_%s=\"%s\"; export Bcast_%s;\n", iface, fields[6], iface;
printf "Mask_%s=\"%s\"; export Mask_%s;\n", iface, fields[8], iface;
}
/^[a-zA-Z0-9]+:/ { # FreeBSD
iface = $1;
sub(":", "", iface);
interfaces = sprintf("%s %s", interfaces, iface);
printf "\nIFACE_%s=\"%s\"; export IFACE_%s;\n", iface, iface, iface;
}
/^[ \t]+inet [0-9]+/ { # FreeBSD
printf "IP_%s=\"%s\"; export IP_%s;\n", iface, $2, iface;
printf "Bcast_%s=\"%s\"; export Bcast_%s;\n", iface, $6, iface;
printf "Mask_%s=\"%s\"; export Mask_%s;\n", iface, $4, iface;
}
/^[ \t]+ether/ { # FreeBSD
printf "HWaddr_%s=\"%s\"; export HWaddr_%s;\n", iface, $2, iface;
}
END { printf "\ninterfaces=\"%s\"; export interfaces;\n", interfaces; }
'`
# Now we have defined variables like this:
# IFACE_eth0 HWaddr_eth0 IP_eth0 Bcast_eth0 Mask_eth0
# IFACE_lo HWaddr_lo IP_lo Bcast_lo Mask_lo
# interfaces
} # }}}
parse_ifconfig
case "$1" in
start)
echo -n "Starting $DESC: "
# Inicialize modules
$DEPMOD -a
load_modules
#
# (un)commnet next lines as needed
#
set_default_policy
set_loopback
nmap_scan_filter
invalid_packet_filter
#anti_spoof_filter
syn_flood
mangle_prerouting
mangle_output
allow_input
allow_output
accept_related
accept_loopback
log_input_drop
log_output_drop
;;
stop)
echo -n "Stopping $DESC: "
unload_modules
remove_chains
set_default_policy
;;
status)
print_iface_status; echo
$IPTABLES -L -nv
;;
*)
echo "Usage: $0 {start|stop|stop}" >&2
exit 1
;;
esac
exit 0
# vim600: fdm=marker fdl=0 fdc=3
Platon Group <platon@platon.org> http://platon.org/
|