#!/bin/sh # # Inventec Firewall Configuration Script # # Modifications: # 2001-05-08 Christian d'Heureuse (chdh@inventec.ch): First version. # 2001-05-21 CHDH: Suppress logging of ACK+FIN packets from port 80. # 2001-05-29 CHDH: Statistics for local Inet trafic added. # 2001-06-11 CHDH: Nameserver reloading added. # 2001-07-02 CHDH: Extensions for port forwarding. # 2002-01-14 CHDH: Configuration parameters moved to /etc/inventec_firewall.conf # 2002-01-15 CHDH: "dev eth0" added for "ip route del default". "brd +" and "label" added for "ip addr del" # 2002-02-20 CHDH: Port forwarding fully implemented, also for UDP. # 2002-06-17 CHDH: Changes to support multiple Internet connections. # - The following configuration parameters are now arrays: # public_ip_addr, public_net_addr, public_net_prefix_len, gateway_ip_addr # and gateway_mac_add ### BEGIN INIT INFO # Provides: inventec_firewall # Required-Start: $network syslog rpc nfsserver rwhod SuSEfirewall_final personal-firewall_final squid inetd wpmd $named # Required-Stop: $network syslog # Default-Start: 3 5 # Default-Stop: # Description: Inventec Firewall configuration script. ### END INIT INFO . /etc/inventec_firewall.conf private_net="$private_net_addr/$private_net_prefix_len" primary_public_ip_addr="${public_ip_addr[primary_net]}" default_gateway_ip_addr="${gateway_ip_addr[primary_net]}" default_gateway_options="${gateway_options[primary_net]}" function connect_to_internet { for ((i=1; i<=public_nets; i++)); do # Add alias IP addr for the Ethernet adapter. ip addr add ${public_ip_addr[i]}/${public_net_prefix_len[i]} broadcast + dev eth0 label eth0:Alias$i table_nr=$((200+i)) ip route add ${private_net_addr}/${private_net_prefix_len} dev eth0 table $table_nr for ((j=1; j<=public_nets; j++)); do ip route add ${public_net_addr[j]}/${public_net_prefix_len[j]} dev eth0 table $table_nr done ip route add default via ${gateway_ip_addr[i]} table $table_nr ${gateway_options[i]} ip rule add from ${public_ip_addr[i]} table $table_nr done ip route add default via $default_gateway_ip_addr $default_gateway_options ip route flush cache } function disconnect_from_internet { ip route del default dev eth0 for ((i=1; i<=public_nets; i++)); do table_nr=$((200+i)) ip rule del from ${public_ip_addr[i]} table $table_nr ip route del default via ${gateway_ip_addr[i]} table $table_nr ${gateway_options[i]} for ((j=1; j<=public_nets; j++)); do ip route del ${public_net_addr[j]}/${public_net_prefix_len[j]} dev eth0 table $table_nr done ip route del ${private_net_addr}/${private_net_prefix_len} dev eth0 table $table_nr ip addr del ${public_ip_addr[i]}/${public_net_prefix_len[i]} broadcast + dev eth0 label eth0:Alias$i done } function load_netfilter_modules { modprobe ip_tables modprobe ip_conntrack modprobe iptable_nat modprobe ip_conntrack_ftp modprobe ip_nat_ftp } function clear_filter_table { iptables --flush iptables --delete-chain } function set_filter_table { # DropLog chain: iptables --new-chain DropLog # Suppress logging of TCP packets from port 21 (ftp) or 80 (httpd) without the SYN flag, # because they can occur during normal NAT operation. iptables -A DropLog -p TCP --sport 21 --tcp-flags SYN NONE -j DROP iptables -A DropLog -p TCP --sport 80 --tcp-flags SYN NONE -j DROP # Log iptables -A DropLog -m limit --limit 3/m --limit-burst 8 -j LOG --log-level warning --log-prefix "Firewall dropped: " iptables -A DropLog -j DROP # InetInputStatistics chain: iptables --new-chain InetInputStatistics for p in $inet_io_statistics_tcp_ports; do iptables -A InetInputStatistics -p TCP --dport $p -j RETURN iptables -A InetInputStatistics -p TCP --sport $p -j RETURN done iptables -A InetInputStatistics -p TCP -j RETURN for p in $inet_io_statistics_udp_ports; do iptables -A InetInputStatistics -p UDP --dport $p -j RETURN iptables -A InetInputStatistics -p UDP --sport $p -j RETURN done iptables -A InetInputStatistics -p UDP -j RETURN iptables -A InetInputStatistics -p ICMP -j RETURN iptables -A InetInputStatistics -j RETURN # InetOutputStatistics chain: iptables --new-chain InetOutputStatistics # Output for local public net for ((i=1; i<=public_nets; i++)); do public_net="${public_net_addr[i]}/${public_net_prefix_len[i]}" iptables -A InetOutputStatistics -d $public_net -j RETURN done for p in $inet_io_statistics_tcp_ports; do iptables -A InetOutputStatistics -p TCP --sport $p -j RETURN iptables -A InetOutputStatistics -p TCP --dport $p -j RETURN done iptables -A InetOutputStatistics -p TCP -j RETURN for p in $inet_io_statistics_udp_ports; do iptables -A InetOutputStatistics -p UDP --sport $p -j RETURN iptables -A InetOutputStatistics -p UDP --dport $p -j RETURN done iptables -A InetOutputStatistics -p UDP -j RETURN iptables -A InetOutputStatistics -p ICMP -j RETURN iptables -A InetOutputStatistics -j RETURN # InetInput chain: iptables --new-chain InetInput iptables -A InetInput -j InetInputStatistics # Accept packets that are part of or related to an already established connection. iptables -A InetInput -m state --state ESTABLISHED,RELATED -j ACCEPT # Reject packets that do not start a new connection. iptables -A InetInput -m state --state ! NEW -j DropLog # Reject packets that come from the Internet but have IP addresses of our private net (=route verification) iptables -A InetInput -s $private_net -j DropLog # Todo: Syn-Flood and ping-of-death protection...? # Accept ICMP packets. iptables -A InetInput -p ICMP -j ACCEPT # Accept TCP and UDP packets for selected ports. iptables -A InetInput -p TCP -m multiport --dport $public_tcp_ports -j ACCEPT iptables -A InetInput -p UDP -m multiport --dport $public_udp_ports -j ACCEPT # Drop all other packets. iptables -A InetInput -j DropLog # INPUT chain: # If the packet comes from one of the Internet gateways, direct it to the InetInput chain. for ((i=1; i<=public_nets; i++)); do iptables -A INPUT -i eth0 -m mac --mac-source ${gateway_mac_addr[i]} -j InetInput done # Accept packets that come from our local private net. iptables -A INPUT -i eth0 -s $private_net -j ACCEPT # Accept packets from the local loopback adapter. iptables -A INPUT -i lo -j ACCEPT # Drop all other packets. iptables -A INPUT -j DropLog # OUTPUT chain: iptables -A OUTPUT -o eth0 -d ! $private_net -j InetOutputStatistics # ForwardStatistics chain: iptables --new-chain ForwardStatistics for h in $private_net_statistics_hosts; do iptables -A ForwardStatistics -s $private_net_prefix.$h -j RETURN iptables -A ForwardStatistics -d $private_net_prefix.$h -j RETURN done iptables -A ForwardStatistics -j RETURN # InetForwardRx chain: iptables --new-chain InetForwardRx # Forward packets that are part of or related to an already established connection. iptables -A InetForwardRx -m state --state ESTABLISHED,RELATED -j ACCEPT # Reject packets that do not start a new connection. iptables -A InetForwardRx -m state --state ! NEW -j DropLog # Reject packets that come from the Internet but have IP addresses of our private net (=route verification) iptables -A InetForwardRx -s $private_net -j DropLog # Accept packets for port forwarding. for s in $forward_tcp_ports; do dport="${s%%/*}"; fwd="${s#*/}"; fwd_host="${fwd%:*}"; fwd_port="${fwd#*:}" iptables -A InetForwardRx -d $fwd_host -p tcp --dport $fwd_port -j ACCEPT done for s in $forward_udp_ports; do dport="${s%%/*}"; fwd="${s#*/}"; fwd_host="${fwd%:*}"; fwd_port="${fwd#*:}" iptables -A InetForwardRx -d $fwd_host -p udp --dport $fwd_port -j ACCEPT done # Drop all other packets. iptables -A InetForwardRx -j DropLog # FORWARD chain: # Pass all packets through ForwardStatistics chain. iptables -A FORWARD -j ForwardStatistics # If the packet comes from one of the Internet gateways, direct it to the InetForwardRx chain. for ((i=1; i<=public_nets; i++)); do iptables -A FORWARD -i eth0 -m mac --mac-source ${gateway_mac_addr[i]} -j InetForwardRx done # Forward packets that come from our local private net. iptables -A FORWARD -i eth0 -s $private_net -d ! $private_net -j ACCEPT # Drop all other packets. iptables -A FORWARD -j DropLog } function clear_nat_table { iptables -t nat --flush iptables -t nat --delete-chain } function set_nat_table { # Source NAT for all local machines. iptables -t nat -A POSTROUTING -o eth0 -s $private_net -d ! $private_net -j SNAT --to $primary_public_ip_addr # Port forwarding. for ((i=1; i<=public_nets; i++)); do for s in $forward_tcp_ports; do dport="${s%%/*}"; fwd="${s#*/}"; fwd_host="${fwd%:*}"; fwd_port="${fwd#*:}" iptables -t nat -A PREROUTING -i eth0 -d ${public_ip_addr[i]} -p tcp --dport $dport -j DNAT --to $fwd done for s in $forward_udp_ports; do dport="${s%%/*}"; fwd="${s#*/}"; fwd_host="${fwd%:*}"; fwd_port="${fwd#*:}" iptables -t nat -A PREROUTING -i eth0 -d ${public_ip_addr[i]} -p udp --dport $dport -j DNAT --to $fwd done done } function clear_iptables { clear_filter_table clear_nat_table } function dump_iptables { echo -e "\n--- Table filter ---\n" iptables -v --list echo -e "\n--- Table nat ---\n" iptables -t nat -v --list } function print_statistics { statistics_chains="InetInputStatistics InetOutputStatistics ForwardStatistics" counters="" for chain_name in $statistics_chains; do s=$(iptables -v -x -n -L $chain_name $1 | awk "/RETURN/ {printf \",%s\",\$2}") counters="$counters$s" done timestamp=$(date +"%Y-%m-%d %H:%M:%S") echo "$timestamp$counters" } function print_and_reset_statistics { print_statistics "--zero" iptables -t nat --zero } function print_statistics_labels { s="\"Timestamp\"" # InetInputStatistics chain: for p in $inet_io_statistics_tcp_ports; do s="$s,\"In TCP d=$p\"" s="$s,\"In TCP s=$p\"" done s="$s,\"In TCP other\"" for p in $inet_io_statistics_udp_ports; do s="$s,\"In UDP d=$p\"" s="$s,\"In UDP s=$p\"" done s="$s,\"In UDP other\"" s="$s,\"In ICMP\"" s="$s,\"In other protocols\"" # InetOutputStatistics chain: for ((i=1; i<=public_nets; i++)); do s="$s,\"Out local public net ${public_net_addr[i]}\"" done for p in $inet_io_statistics_tcp_ports; do s="$s,\"Out TCP s=$p\"" s="$s,\"Out TCP d=$p\"" done s="$s,\"Out TCP other\"" for p in $inet_io_statistics_udp_ports; do s="$s,\"Out UDP s=$p\"" s="$s,\"Out UDP d=$p\"" done s="$s,\"Out UDP other\"" s="$s,\"Out ICMP\"" s="$s,\"Out other protocols\"" # ForwardStatistics chain: for h in $private_net_statistics_hosts; do s="$s,\"Fwd from $h\"" s="$s,\"Fwd to $h\"" done s="$s,\"Fwd other\"" echo "$s" } function log_and_reset_statistics { if test ! -e $statistics_log_file_name; then print_statistics_labels >>$statistics_log_file_name fi print_and_reset_statistics >>$statistics_log_file_name } function reset_iptables_statistics { iptables --zero iptables -t nat --zero } function enable_ip_forwarding { echo "1" >/proc/sys/net/ipv4/ip_forward } function disable_ip_forwarding { echo "0" >/proc/sys/net/ipv4/ip_forward } function restart_internet_services { # The DNS server has to start a new listener on port 53 of the public Internet interface. rndc reload } function start_firewall { load_netfilter_modules clear_iptables set_filter_table set_nat_table connect_to_internet enable_ip_forwarding restart_internet_services } function stop_firewall { log_and_reset_statistics disable_ip_forwarding disconnect_from_internet clear_iptables } function main { . /etc/rc.status rc_reset case "$1" in start) echo -n "Starting Inventec Firewall" start_firewall logger "Inventec Firewall started" rc_status -v ;; stop) echo -n "Stopping Inventec Firewall" stop_firewall logger "Inventec Firewall stopped" rc_status -v ;; try-restart) $0 stop && $0 start rc_status ;; restart) $0 stop $0 start rc_status ;; force-reload) $0 stop && $0 start rc_status ;; reload) exit 3 ;; status) echo "Inventec Firewall: Status command not implemented." exit 3 ;; dump) dump_iptables exit 0 ;; print_stats) print_statistics exit 0 ;; log_and_reset_stats) log_and_reset_statistics exit 0 ;; reset_stats) reset_iptables_statistics logger "Inventec Firewall statistics reset" exit 0 ;; *) echo "Usage: $0 {start|stop|restart|dump|print_stats|reset_stats|log_and_reset_stats}" exit 1 ;; esac rc_exit } main $1