#!/bin/bash ### BEGIN INIT INFO # Provides: firewall # Required-Start: $remote_fs $syslog $network # Required-Stop: $remote_fs $syslog $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Iptables firewall # Description: An iptables firewall ### END INIT INFO . /lib/lsb/init-functions NAME="firewall" abort() { message=$@ log_failure_msg "$message" exit 1 } if [ -f "/etc/firewall/firewall.conf" ]; then source /etc/firewall/firewall.conf else abort "No configuration file /etc/firewall/firewall.conf" fi clean() { $IPTABLES -t filter -F $IPTABLES -t filter -X $IPTABLES -t filter -P INPUT ACCEPT $IPTABLES -t filter -P FORWARD ACCEPT $IPTABLES -t filter -P OUTPUT ACCEPT $IPTABLES -t nat -F $IPTABLES -t nat -X $IPTABLES -t nat -P PREROUTING ACCEPT $IPTABLES -t nat -P OUTPUT ACCEPT $IPTABLES -t nat -P POSTROUTING ACCEPT $IPTABLES -t mangle -F $IPTABLES -t mangle -X $IPTABLES -t mangle -P PREROUTING ACCEPT $IPTABLES -t mangle -P INPUT ACCEPT $IPTABLES -t mangle -P FORWARD ACCEPT } test_config() { # FIXME: test if the interface and the ip exist if [ ! "$WAN_INT" -o ! "$IP" ]; then abort "Bad configuration please check /etc/firewall/firewall.conf" fi } critical_return() { if [ `echo $?` != 0 ]; then log_failure_msg "Error on the last command firewall will be stop" stop exit 1 fi } forward_port() { if [ $# != 4 ]; then log_warning_msg "Bad syntax for port forward : $*" return fi local source=$1 local port=$2 local destination=$3 local proto=$4 if echo "$destination" | grep -q ":"; then dest_ip=$(echo $destination | cut -d ":" -f1) dest_port=$(echo $destination | cut -d ":" -f2) if [ ! "$LAN_INT" ]; then log_warning_msg "You must add a LAN interface (LAN_INT) for a port forward" else log_action_msg "Forward $port to $destination for protocol $proto" $IPTABLES -A FORWARD -i $WAN_INT -o $LAN_INT -p $proto -s $source -d $dest_ip --dport $dest_port -m state --state ESTABLISHED,RELATED,NEW -j ACCEPT $IPTABLES -t nat -A PREROUTING -i $WAN_INT -p $proto -s $source -d $IP --dport $port -j DNAT --to $destination fi fi } open_port() { if [ $# == 4 ]; then local destination=$2 local proto=$3 local ports=$4 elif [ $# == 3 ]; then local destination=$IP local proto=$2 local ports=$3 else log_warning_msg "Open port bad syntax : $*" fi source=$1 log_action_msg "Open port(s) $ports from $source to $destination for protocol $proto" $IPTABLES -A INPUT -i $WAN_INT -p $proto -s $source -d $destination -m multiport --dports $ports -m state --state NEW -j ACCEPT critical_return } port_redirection() { if [ $# != 4 ]; then log_warning_msg "Bad syntax for port redirection : $*" return fi local if=$1 local proto=$2 local srcport=$3 local destport=$4 log_action_msg "Redirect $if port $srcport to $destport for portocol $proto" iptables -t nat -A PREROUTING -i $if -p $proto --dport $srcport -j REDIRECT --to-port $destport } port_knocking() { if [ $# != 3 ]; then log_warning_msg "Bad syntax for port knocking : $*" return fi local ports=$1 local knock_ports=$2 local knock_number=$3 local i=0 for kport in $(echo $knock_ports | sed 's/,/ /g'); do ((i++)) tock_number=$knock_number$i if [ $i -gt 1 ]; then iptables -N toc${tock_number} iptables -A toc${tock_number} -m recent --name toc$((${tock_number}-1)) --remove iptables -A toc${tock_number} -m recent --name toc${tock_number} --set iptables -A INPUT -i $WAN_INT -p tcp --dport $kport -m recent --rcheck --name toc$((${tock_number}-1)) -j toc${tock_number} else iptables -A INPUT -i $WAN_INT -p tcp --dport $kport -m recent --set --name toc${tock_number} fi done log_action_msg "Port knocking for $ports with combinaison $knock_ports on $WAN_INT" for port in $(echo $ports | sed 's/,/ /g'); do iptables -A INPUT -i $WAN_INT -p tcp --dport $port -m recent --rcheck --seconds 15 --name toc${tock_number} -m state --state NEW -j ACCEPT done } start() { test_config modprobe ip_conntrack clean # default policies $IPTABLES -P INPUT DROP $IPTABLES -P FORWARD DROP $IPTABLES -P OUTPUT DROP ## allow packets coming from the machine $IPTABLES -A INPUT -i lo -j ACCEPT $IPTABLES -A OUTPUT -o lo -j ACCEPT log_action_msg "Allow WAN outgoing traffic" $IPTABLES -A OUTPUT -o $WAN_INT -p all -m state --state ESTABLISHED,RELATED,NEW -j ACCEPT $IPTABLES -A INPUT -i $WAN_INT -p all -m state --state ESTABLISHED,RELATED -j ACCEPT critical_return if [ $LAN == 1 ]; then log_action_msg "Allow WAN outgoing traffic from lan" $IPTABLES -A FORWARD -i $WAN_INT -o $LAN_INT -p all -d $LAN_NETWORK -m state --state RELATED,ESTABLISHED -j ACCEPT $IPTABLES -A FORWARD -i $LAN_INT -o $WAN_INT -p all -s $LAN_NETWORK -m state --state ESTABLISHED,RELATED,NEW -j ACCEPT log_action_msg "Allow local network" $IPTABLES -A OUTPUT -o $LAN_INT -s $LAN_NETWORK -p all -j ACCEPT $IPTABLES -A INPUT -i $LAN_INT -d $LAN_NETWORK -p all -j ACCEPT fi ## block spoofing log_action_msg "Block spoofing, scan port, Xmas Tree, null scanning, SYN/RST and SYN/FIN" echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter ## NMAP FIN/URG/PSH $IPTABLES -A INPUT -i $WAN_INT -p tcp --tcp-flags ALL FIN,URG,PSH -j LOG --log-prefix 'iptables: Port scan: ' --log-level 4 $IPTABLES -A INPUT -i $WAN_INT -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP ## stop Xmas Tree type scanning $IPTABLES -A INPUT -i $WAN_INT -p tcp --tcp-flags ALL ALL -j LOG --log-prefix "iptables: Xmas tree: " --log-level 4 $IPTABLES -A INPUT -i $WAN_INT -p tcp --tcp-flags ALL ALL -j DROP $IPTABLES -A INPUT -i $WAN_INT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j LOG --log-prefix "iptables: Xmas tree: " --log-level 4 $IPTABLES -A INPUT -i $WAN_INT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP ## stop null scanning $IPTABLES -A INPUT -i $WAN_INT -p tcp --tcp-flags ALL NONE -j LOG --log-prefix "iptables: Null scanning: " --log-level 4 $IPTABLES -A INPUT -i $WAN_INT -p tcp --tcp-flags ALL NONE -j DROP ## SYN/RST $IPTABLES -A INPUT -i $WAN_INT -p tcp --tcp-flags SYN,RST SYN,RST -j LOG --log-prefix "iptables: SYN/RST: " --log-level 4 $IPTABLES -A INPUT -i $WAN_INT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP ## SYN/FIN $IPTABLES -A INPUT -i $WAN_INT -p tcp --tcp-flags SYN,FIN SYN,FIN -j LOG --log-prefix "iptables: SYN/FIN: " --log-level 4 $IPTABLES -A INPUT -i $WAN_INT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP ## stop sync flood log_action_msg "Block Syn flood" echo "1" >/proc/sys/net/ipv4/tcp_syncookies echo "1024" > /proc/sys/net/ipv4/tcp_max_syn_backlog if [ $PING == 1 ]; then log_action_msg "PING allowed" iptables -A INPUT -p icmp --icmp-type ping -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type ping -j ACCEPT iptables -A FORWARD -p icmp --icmp-type ping -j ACCEPT fi if [ $FTP == 1 ]; then log_action_msg "FTP allowed" modprobe ip_conntrack_ftp $IPTABLES -A INPUT -i $WAN_INT -d $IP -p tcp --dport ftp -m state --state NEW,ESTABLISHED -j ACCEPT $IPTABLES -A OUTPUT -o $WAN_INT -s $IP -p tcp --sport ftp -m state --state ESTABLISHED -j ACCEPT # Data $IPTABLES -A INPUT -i $WAN_INT -d $IP -p tcp --dport ftp-data -m state --state ESTABLISHED -j ACCEPT $IPTABLES -A OUTPUT -o $WAN_INT -s $IP -p tcp --sport ftp-data -m state --state ESTABLISHED,RELATED -j ACCEPT # Passive mod $IPTABLES -A INPUT -i $WAN_INT -d $IP -p tcp --sport 1024: --dport 1024: -m state --state ESTABLISHED -j ACCEPT $IPTABLES -A OUTPUT -o $WAN_INT -s $IP -p tcp --sport 1024: --dport 1024: -m state --state ESTABLISHED,RELATED -j ACCEPT fi ## Open Ports for args in "${OPEN_PORTS[@]}"; do open_port $args done ## Port knocking local i=1 for args in "${PORT_KNOCK[@]}"; do port_knocking $args $i ((i++)) done ## Port forwading for args in "${TRAFFICS[@]}"; do forward_port $args done ## Port redirection for args in "${REDIRECTIONS[@]}"; do port_redirection $args done ## Old: Whitelist for arg in "${WHITELIST_SSH[@]}"; do log_warning_msg "WHITELIST_SSH is obsolete: this option will be removed in next version" open_port $arg tcp ssh done for ip in "${WHITELIST[@]}"; do for args in "${WHITELIST_OPEN_PORTS[@]}"; do open_port $ip $args done done ## NAT if [ $NAT == 1 ]; then log_action_msg "Activate nat" for proto in ftp irc sip h323; do modprobe nf_nat_$proto; done $IPTABLES -t nat -A POSTROUTING -o $WAN_INT -s $LAN_NETWORK -j SNAT --to-source $IP fi ipt_hook ## LOG ## Create a LOGDROP chain to log and drop packets $IPTABLES -N LOGDROP $IPTABLES -A LOGDROP -p tcp -m limit --limit 1/min -j LOG --log-prefix "iptables: denied tcp: " --log-level 4 $IPTABLES -A LOGDROP -p udp -m limit --limit 1/min -j LOG --log-prefix "iptables: denied udp: " --log-level 4 $IPTABLES -A LOGDROP -p icmp -m limit --limit 1/min -j LOG --log-prefix "iptables: denied icmp: " --log-level 4 $IPTABLES -A LOGDROP -j DROP $IPTABLES -A INPUT -j LOGDROP $IPTABLES -A OUTPUT -j LOGDROP $IPTABLES -A FORWARD -j LOGDROP } stop() { clean } case "$1" in start|restore) log_daemon_msg "Starting firewall" if [ -f /etc/network/iptables-save ]; then iptables-restore < /etc/network/iptables-save else log_warning_msg "No iptables rules saved please use test and save script options" fi log_end_msg 0 ;; stop) log_daemon_msg "Stopping firewall" stop || exit 1 log_end_msg 0 ;; test) log_action_msg "Testing new rules" log_action_msg "You have 30 seconds to test your new rules" start || exit 1 log_end_msg 0 log_action_msg "... Please test your rules" sleep 30 log_action_msg "---- The test is finished ----" if [ -f /etc/network/iptables-save ]; then iptables-restore < /etc/network/iptables-save log_action_msg "Old rules restored" else stop log_action_msg "Rules flushed" fi log_action_msg "If you are happy with this new rules please use save option" ;; save) log_action_msg "Starting and saving new rules" start || exit 1 iptables-save > /etc/network/iptables-save log_end_msg 0 ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|restore|save|test|stop}" exit 2 ;; esac exit 0