#!/bin/bash # # build iptables and proxy-arp based firewalls # ck() { if [[ $EUID == 0 ]]; then "$@" || { echo "BAD: $@"; return 1;}; fi sudo "$@" || { echo "BAD: $@"; return 1;}; } ipt() { case "$1 $2" in "-t -"*) shift;; "-t "|"-t default") shift;shift;; esac ck iptables "$@" } ipt_list_tables() { awk '/^iptable_/{ print $1 }' /proc/modules | sed -e 's/^iptable_//'; echo "default"; } ipt_has_table() { table="$1" for t in $( ipt_list_tables ); do [[ $t == "$table" ]] && return 0 done return 1 } ipt_show() { [[ "$1" == "" ]] && { ipt_show "default"; return; } ipt -t $1 -L -n -v } ipt_reset() { for table in $( ipt_list_tables ); do ipt -t $table -L -n | grep '^Chain' | while read Chain chain Policy policy; do [[ "$policy" =~ "(policy" ]] && \ ipt -t $table -P $chain ACCEPT ipt -t $table -F $chain done done } ipt_port() { echo "$1" | sed -e 's/.*\///'; } ipt_proto() { echo "$1" | sed -e 's/\/.*//'; } block_local() { interface="$1"; shift for p in "$@"; do port=$( ipt_port $p ) proto=$( ipt_proto $p ) ipt -I INPUT -i $interface -p $proto --dport $port -j REJECT done } nonat() { src="$1"; shift for dst in "$@"; do [[ "$dst" = 'to' ]] && continue ipt -A FORWARD -s $src -d $dst -j ACCEPT ipt -t nat -A POSTROUTING -s $src -d $dst -j ACCEPT done } snat() { local int=$1; shift local int_if=$( intf_of_ip $int ) local ext_if=$( intf_of_ip 0.0.0.0 ) local ext=$( ip_of_intf $ext_if ) ipt -A FORWARD -i $int_if -p icmp -s $int -j ACCEPT ipt -t nat -A POSTROUTING -o $ext_if -s $int -j SNAT --to-source $ext for p in "$@"; do port=$( ipt_port $p ) proto=$( ipt_proto $p ) ipt -A FORWARD -i $int_if -o $ext_if -p $proto -s $int --dport $port -j ACCEPT done } dnat() { local ext=$1; shift local int=$1; shift ipt -A FORWARD -p icmp --icmp-type 8 -d $int -j ACCEPT ipt -t nat -A PREROUTING -p icmp -d $ext -j DNAT --to-destination $int ipt -t nat -A POSTROUTING -s $int -j SNAT --to-source $ext for p in "$@"; do port=$( ipt_port $p ) proto=$( ipt_proto $p ) ipt -A FORWARD -p $proto -d $int --dport $port -m state --state NEW -j ACCEPT ipt -t nat -A PREROUTING -p $proto -d $ext --dport $port -j DNAT --to-destination $int done local ext_if=$( intf_of_ip $ext) local int_if=$( intf_of_ip $int) ck sysctl net.ipv4.conf.${ext_if}.proxy_arp=1 ck gratuitous_arp $ext $ext_if ck ip route add ${ext}/32 dev $int_if } squid_transparent_proxy() { net="$1"; shift ipt -t nat -A PREROUTING -p tcp -s $net --dport 80 -j REDIRECT --to-port 3128 } gratuitous_arp() { ip="$1"; shift interface="$1"; shift /opt/fw/bin/grarp $ext $ext_if [[ $? == 0 ]] && return 0 arping -q -c 3 -A -I $interface $ip return $? } intf_reset() { dev="$1" ip route show dev $dev | awk '/scope link $/{ print $1 }' | while read ip; do ck ip route del ${ip}/32 dev $dev done } intf_of_ip() { ip="$1" ck ip route list match $ip | awk '{ print $NF }' } ip_of_intf() { ck ip addr show dev $1 | awk '/^ inet /{ print $2; exit 0; }' | sed -e 's#/.*##' } ipt_stop() { ck sysctl net.ipv4.ip_forward=0 intf_reset $int_if ipt_reset "" INPUT ACCEPT ipt_reset "" OUTPUT ACCEPT ipt_reset "" FORWARD DROP ipt_reset "-t nat" PREROUTING ACCEPT ipt_reset "-t nat" POSTROUTING ACCEPT } ipt_start() { ipt -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT ck sysctl net.ipv4.ip_forward=1 ck sysctl net.ipv4.conf.all.arp_ignore=0 ck sysctl net.ipv4.conf.all.accept_source_route=0 ck sysctl net.ipv4.conf.all.rp_filter=1 ck sysctl net.ipv4.conf.all.log_martians=0 ck sysctl net.ipv4.tcp_syncookies=1 ck sysctl net.ipv4.netfilter.ip_conntrack_udp_timeout=60 ck sysctl net.ipv4.netfilter.ip_conntrack_tcp_timeout_close=180 ck sysctl net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait=180 ck sysctl net.ipv4.netfilter.ip_conntrack_tcp_timeout_last_ack=180 ck sysctl net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait=180 ck sysctl net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait=180 ck sysctl net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_recv=180 ck sysctl net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_sent=180 } cat</dev/null # EXAMPLE SETUP fw_rules() { nonat 10.1.0.0/16 to 10.0.0.0/8 192.168.0.0/16 nonat 10.16.0.0/16 to 10.0.0.0/8 192.168.0.0/16 nonat 192.168.2.0/27 to 192.168.2.0/27 nonat 192.168.0.0/16 to 10.1.0.0/24 dnat $qunying_ext $qunying_int tcp/778 dnat $flashprd_ext $flashprd_int tcp/8088 dnat $appprd_ext $appprd_int tcp/http tcp/https dnat $mail1prd_ext $mail1prd_int tcp/imap tcp/imaps dnat $ldap1prd_ext $ldap1prd_int tcp/ldap dnat $mpsweb_ext $mpsweb_int tcp/http dnat $mpsmail_ext $mpsmail_int tcp/imap tcp/smtp tcp/submission dnat $mx3_ext $mx3_int tcp/smtp tcp/submission dnat $mx4_ext $mx4_int tcp/smtp tcp/submission snat 10.1.0.0/24 tcp/smtp udp/53 tcp/53 tcp/4000 tcp/5050 tcp/32323 tcp/1056 snat 10.0.0.0/8 $minion_ports snat 192.168.0.0/16 tcp/ftp-data tcp/ftp tcp/http block_local $ext_if tcp/22 udp/161 tcp/3128 } case $1 in stop) ipt_stop ;; start) sysctl net.ipv6.conf.all.accept_ra_defrtr=0 ifconfig vlan511 up ifconfig vlan512 up ip addr add ${gw_ip}/32 dev $int_if gratuitous_arp $gw_ip $int_if ipt_start fw_rules ipt_list > /tmp/firewall-rules #tcpdump -n -i $ext_if host haller.ws and port 25 ;; restart) $0 stop; $0 start;; *) echo "usage: $0 [start|stop|restart]" ;; esac EOF