#!/bin/bash ### BEGIN INIT INFO # Provides: firewall # Required-Start: $network # Required-Stop: $remote_fs # Default-Start: S # Default-Stop: 0 6 # Short-Description: Starts firewall # Description: Handle universal firewall script by Platon Group # http://platon.sk/cvs/cvs.php/scripts/shell/firewall/ # Author: Lubomir Host # Copyright: (c) 2003-2011 Platon Group ### END INIT INFO # # This will be universal firewalling script for Linux kernel (iptables) in near future # Can be started by init or by hand. # # Developed by Lubomir Host 'rajo' # Copyright (c) 2003-2011 Platon Group, http://platon.sk/ # Licensed under terms of GNU General Public License. # All rights reserved. # # $Platon: scripts/shell/firewall/fw-universal.sh,v 2.104 2015/10/12 22:41:24 rajo Exp $ # # Changelog: # 2003-10-24 - created # 2011-07-20 - implemented XEN_MODE # umask 077 # security DESC="firewall" PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DEFAULT_FIREWALL_CONFIG="${DEFAULT_FIREWALL_CONFIG:=/etc/default/firewall}" DEFAULT_FIREWALL_CONFIG_DIR="${DEFAULT_FIREWALL_CONFIG_DIR:=/etc/default/firewall.d}" DEFAULT_CACHE_DIR="${DEFAULT_CACHE_DIR:=/var/cache/firewall}" # quiet output? {{{ if [ "x$1" = "xblock" ] || [ "x$QUIET" = "xyes" ]; then print_info() { echo -n "" } else print_info() { echo "$@" } fi # }}} if [ -f "$DEFAULT_FIREWALL_CONFIG" ]; then print_info "Reading config file $DEFAULT_FIREWALL_CONFIG" . $DEFAULT_FIREWALL_CONFIG fi # # Default configuration values: # DEFAULT_POLICY="${DEFAULT_POLICY:=DROP}" # which modules to load MODULES="${MODULES:=}" MODULES_LOADING="${MODULES_LOADING:=yes}" MODULES_REMOVING="${MODULES_REMOVING:=no}" LOG_LIMIT="${LOG_LIMIT:=-m limit --limit 12/h --limit-burst 10 -j LOG --log-level notice --log-prefix}" # Paths: #IPTABLES=":" # for testing only - does nothing IPTABLES="${IPTABLES:=$DEBUG/sbin/iptables}" IPTABLES_SAVE="${IPTABLES_SAVE:=$DEBUG/sbin/iptables-save}" IPTABLES_RESTORE="${IPTABLES_RESTORE:=$DEBUG/sbin/iptables-restore}" IPTABLES_TABLES="${IPTABLES_TABLES:=filter nat mangle}" if [ "x$LOGGING" = "xoff" ]; then IPTABLES_LOG=": log turned off" else IPTABLES_LOG="${IPTABLES_LOG:=$DEBUG/sbin/iptables}" fi IFCONFIG="${IFCONFIG:=/sbin/ifconfig}" DEPMOD="${DEPMOD:=/sbin/depmod}" MODPROBE="${MODPROBE:=/sbin/modprobe}" RMMOD="${RMMOD:=/sbin/rmmod}" AWK="${AWK:=/usr/bin/gawk}" PERL="${PERL:=/usr/bin/perl}" # shaping TC="${TC:=/sbin/tc}" # update script UPDATE_SCRIPT="${UPDATE_SCRIPT:=update_from_cvs}" # loopback interface LO_IFACE="${LO_IFACE:=lo}" # Hide NAT clients behind firewall NAT_SET_TTL="${NAT_SET_TTL:=no}" # reject config ALL_REJECT_INPUT_TCP="${ALL_REJECT_INPUT_TCP:=113}" # by default reject connections to AUTH server REJECT_WITH="${REJECT_WITH:=tcp-reset}" # # CONSTANTS - Do not edit # ANYWHERE="0.0.0.0/0" # Match any IP address BROADCAST_SRC="0.0.0.0" # Broadcast Source Address BROADCAST_DEST="255.255.255.255" # Broadcast Destination Address CLASS_A="10.0.0.0/8" # Class-A Private (RFC-1918) Networks CLASS_B="172.16.0.0/12" # Class-B Private (RFC-1918) Networks CLASS_C="192.168.0.0/16" # Class-C Private (RFC-1918) Networks CLASS_D_MULTICAST="224.0.0.0/4" # Class-D Multicast Addresses CLASS_E_RESERVED_NET="240.0.0.0/5" # Class-E Reserved Addresses PRIVPORTS="0:1023" # Well-Known, Privileged Port Range UNPRIVPORTS="1024:65535" # Unprivileged Port Range TRACEROUTE_SRC_PORTS="32769:65535" # Traceroute Source Ports TRACEROUTE_DEST_PORTS="33434:33523" # Traceroute Destination Ports # allow some ICMP packets - needed for ping etc. ACCEPT_ICMP_PACKETS="${ACCEPT_ICMP_PACKETS:=echo-reply destination-unreachable echo-request time-exceeded}" # check if all required tools are installed check_tools() { # {{{ [ -x $AWK ] || (echo "AWK not found: please install gawk" && exit 1); [ -x $PERL ] || (echo "PERL not found: please install perl" && exit 1); [ -x $IPTABLES ] || (echo "IPTABLES not found: please install iptables" && exit 1); [ -x $IPTABLES_SAVE ] || (echo "IPTABLES_SAVE not found: please install iptables" && exit 1); [ -x $IPTABLES_RESTORE ] || (echo "IPTABLES_RESTORE not found: please install iptables" && exit 1); } # }}} print_first() { # {{{ echo $1 } # }}} get_first_ip_addr() { # {{{ varname="$1" print_first `echo ${!varname} | sort -g` } # }}} read_config_ips() { # {{{ PARSE_CONFIG=$1 $PERL -ne 'if (m/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/(\d+)$/g) { print; } elsif ($_ !~ m/^\s*#/ && $_ !~ m/^\s*$/ ) { print STDERR "ERROR: $ENV{PARSE_CONFIG}:$.: ignored string $_\n"; }' $1 } # }}} # load necessary modules from $MODULES variable load_modules() { # {{{ if [ "e$MODULES_LOADING" = "eyes" ]; then print_info "# Loading modules" for mod in $MODULES; do print_info " $MODPROBE $mod" $MODPROBE $mod done fi } # }}} load_cache() { # {{{ if [ ! -d "$DEFAULT_CACHE_DIR" ]; then mkdir -p "$DEFAULT_CACHE_DIR"; if [ "$?" -ne "0" ]; then print_info "ERROR: unable to create cache dir in load_cache()"; return; fi fi config=""; if [ -r "$DEFAULT_FIREWALL_CONFIG" ]; then config="$config ` cat \"$DEFAULT_FIREWALL_CONFIG\" `"; fi if [ -r "$0" ]; then config="$config ` cat \"$0\" `"; fi if [ -r "$DEFAULT_FIREWALL_CONFIG_DIR/deploy-servers.list" ]; then config="$config ` cat \"$DEFAULT_FIREWALL_CONFIG_DIR/deploy-servers.list\" `"; fi if [ -r "$DEFAULT_FIREWALL_CONFIG_DIR/BANNED_IP.conf" ]; then config="$config ` cat \"$DEFAULT_FIREWALL_CONFIG_DIR/BANNED_IP.conf\" `"; fi md5key=`echo "config='$config' parsed_interfaces='$parsed_interfaces' parsed_routes='$parsed_routes'" | md5sum | $AWK '{print $1;}'`; CACHE_FILE="$DEFAULT_CACHE_DIR/$md5key" #echo "CACHE_FILE=$CACHE_FILE" if [ -f "$CACHE_FILE" ]; then print_info "Loading rules from cache file $CACHE_FILE" # this has nothing to do with IPtables rules, we need to run them explicitly forward_on shaping_on # restore IPtables rules $IPTABLES_RESTORE -c < $CACHE_FILE; #echo "exit code $IPTABLES_RESTORE: $?" [ $? -eq 0 ] && exit 0; # exit if load succesfull fi } # }}} # unload necessary modules from $MODULES variable unload_modules() { # {{{ # reverse modules if [ "e$MODULES_REMOVING" = "eyes" ]; then print_info "# Removing modules" R_MODULES=`echo "$MODULES" | tr ' ' '\012' | tac | tr '\012' ' '` for mod in $R_MODULES; do print_info " $RMMOD $mod" $RMMOD $mod done fi } # }}} # print status of detected interfaces print_iface_status() { # {{{ # Print interfaces: print_info "$(pad7 "# iface") | $(pad15 "IP address") | $(pad15 "Gateway") | $(pad15 "Broadcast") | $(pad15 "Netmask") | HW address"; for iface in $interfaces; do IPS="IP_$iface"; for IP in ${!IPS}; do Gateway="Gateway_$iface"; Bcast="Bcast_$iface"; Mask="Mask_$iface"; HWaddr="HWaddr_$iface"; print_info "$(pad7 $iface) | $(pad15 ${IP}) | $(pad15 ${!Gateway}) | $(pad15 ${!Bcast}) | $(pad15 ${!Mask}) | ${!HWaddr}"; done done } # }}} # set default policy (variable $DEFAULT_POLICY) set_default_policy() { # {{{ # Set default policy for chain in INPUT OUTPUT FORWARD; do if [ "X$XEN_MODE" = "Xon" -a "$chain" = "FORWARD" ]; then print_info "XEN_MODE enabled: default policy for FORWARD forced to ACCEPT"; $IPTABLES -P $chain ACCEPT; continue; fi $IPTABLES -P $chain $DEFAULT_POLICY done } # }}} antispoof_on() { # {{{ for interface in /proc/sys/net/ipv4/conf/*/rp_filter; do echo "1" > ${interface} done } # }}} # Turn on IP packets forwarding forward_on() { # {{{ # NAT requires turn on IP forwarding if [ ! -z "$NAT_LAN_IFACE" ]; then print_info -en "NAT: Enabling packet forwarding..." echo 1 > /proc/sys/net/ipv4/ip_forward print_info " done." fi } # }}} forward_off() { # {{{ print_info -en "NAT: Disabling packet forwarding..." echo 0 > /proc/sys/net/ipv4/ip_forward print_info " done." } # }}} # clear status of iptable chains remove_chains() { # {{{ if [ "X$XEN_MODE" = "Xon" ]; then print_info "XEN_MODE enabled: not clearing FORWARD chain"; $IPTABLES --flush INPUT $IPTABLES --flush OUTPUT $IPTABLES --flush spoof # TODO!!! else for table in $IPTABLES_TABLES; do $IPTABLES -t $table -F # clear all chains $IPTABLES -t $table -X # remove all chains $IPTABLES -t $table -Z # zero counts done fi } # }}} # DROP packages from nmap(1) nmap_scan_filter() { # {{{ print_info -en "Turning on nmap scan filter " for chain in INPUT FORWARD; do if [ "X$XEN_MODE" = "Xon" -a "$chain" = "FORWARD" ]; then print_info -ne " XEN_MODE "; continue; fi # Nie je nastaveny ziaden bit $IPTABLES_LOG -A $chain -p TCP --tcp-flags ALL NONE $LOG_LIMIT "nmap scan $chain ALL NONE: " print_info -en "." $IPTABLES -A $chain -p TCP --tcp-flags ALL NONE -j DROP print_info -en "." # dva odporujuuce si flagy su nastavene: for flags in SYN,FIN SYN,RST FIN,RST ; do $IPTABLES_LOG -A $chain -p TCP --tcp-flags $flags $flags $LOG_LIMIT "nmap scan $chain $flags: " print_info -en "." $IPTABLES -A $chain -p TCP --tcp-flags $flags $flags -j DROP print_info -en "." done # je nastavene len $flags bez predpokladaneho ACK for flags in FIN PSH URG ; do $IPTABLES_LOG -A $chain -p TCP --tcp-flags ACK,$flags $flags $LOG_LIMIT "nmap scan $chain ACK,$flags: " print_info -en "." $IPTABLES -A $chain -p TCP --tcp-flags ACK,$flags $flags -j DROP print_info -en "." done done print_info " done." } # }}} # drop packets in state INVALID invalid_packet_filter() { # {{{ print_info -en "Turning on INVALID packet filter " for chain in INPUT OUTPUT FORWARD; do if [ "X$XEN_MODE" = "Xon" -a "$chain" = "FORWARD" ]; then print_info -ne " XEN_MODE "; continue; fi $IPTABLES_LOG -A $chain -m conntrack --ctstate INVALID $LOG_LIMIT "INVALID $chain: " print_info -en "." $IPTABLES -A $chain -m conntrack --ctstate INVALID -j DROP print_info -en "." done print_info " 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 for riface in $REAL_INTERFACES; do $IPTABLES -A INPUT -i $riface -p TCP --syn -j syn-flood # packet is marked az NEW, but doesn't have SYN flag - drop it $IPTABLES -A INPUT -i $riface -p TCP ! --syn -m conntrack --ctstate NEW -j DROP done } # }}} anti_spoof_filter() { # {{{ # http://www.iana.com/assignments/ipv4-address-space if [ ! -z "$ANTISPOOF_IFACE" ]; then print_info -en "Turning on antispoof filter for interfaces: " $IPTABLES -N spoof # Ochrana proti Spoogingu zo spatnej slucky $IPTABLES_LOG -A spoof -s 127.0.0.0/8 $LOG_LIMIT "RESERVED:127.0.0.0/8 src" $IPTABLES -A spoof -s 127.0.0.0/8 -j DROP $IPTABLES_LOG -A spoof -d 127.0.0.0/8 $LOG_LIMIT "RESERVED:127.0.0.0/8 dest" $IPTABLES -A spoof -d 127.0.0.0/8 -j DROP # Ochrana proti Spoofingu Internetu z adries urcenych pre lokalne siete $IPTABLES_LOG -A spoof -s 192.168.0.0/16 $LOG_LIMIT "RESERVED:192.168.0.0/16 src" $IPTABLES -A spoof -s 192.168.0.0/16 -j DROP # RFC1918 $IPTABLES_LOG -A spoof -s 172.16.0.0/12 $LOG_LIMIT "RESERVED:172.16.0.0/12 src" $IPTABLES -A spoof -s 172.16.0.0/12 -j DROP # RFC1918 $IPTABLES_LOG -A spoof -s 10.0.0.0/8 $LOG_LIMIT "RESERVED:10.0.0.0/8 src" $IPTABLES -A spoof -s 10.0.0.0/8 -j DROP # RFC1918 len pre sietovy interface do Internetu, kedze 10.0.0.0 je adresa LAN # 2009-02-11 - Not reserver anymore: http://www.iana.org/assignments/ipv4-address-space/ # - it is a Comcast network now #$IPTABLES_LOG -A spoof -s 96.0.0.0/4 $LOG_LIMIT "RESERVED:96.0.0.0/4 src" #$IPTABLES -A spoof -s 96.0.0.0/4 -j DROP # IANA for iface in $ANTISPOOF_IFACE; do print_info -en " $iface" if [ "X$XEN_MODE" = "Xon" ]; then print_info -ne " XEN_MODE "; else $IPTABLES -A FORWARD -i $iface -j spoof fi $IPTABLES -A INPUT -i $iface -j spoof done print_info " done." fi } # }}} mangle_prerouting() { # {{{ print_info -en "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 print_info -en "." $IPTABLES -t mangle -A PREROUTING -p TCP --dport ssh -j TOS --set-tos Minimize-Delay print_info -en "." $IPTABLES -t mangle -A PREROUTING -p TCP --sport ftp -j TOS --set-tos Minimize-Delay print_info -en "." $IPTABLES -t mangle -A PREROUTING -p TCP --dport ftp -j TOS --set-tos Minimize-Delay print_info -en "." $IPTABLES -t mangle -A PREROUTING -p TCP --dport telnet -j TOS --set-tos Minimize-Delay print_info -en "." $IPTABLES -t mangle -A PREROUTING -p TCP --sport ftp-data -j TOS --set-tos Maximize-Throughput print_info -en "." print_info " done." } # }}} mangle_output() { # {{{ print_info -en "Optimizing OUTPUT TOS:" # TOS flagy slouzi k optimalizaci datovych cest. Pro ssh, ftp a telnet # pozadujeme minimalni zpozdeni. Pro ftp-data zase maximalni propostnost for riface in $REAL_INTERFACES; do print_info -en " $riface"; $IPTABLES -t mangle -A OUTPUT -o $riface -p TCP --sport ssh -j TOS --set-tos Minimize-Delay $IPTABLES -t mangle -A OUTPUT -o $riface -p TCP --dport ssh -j TOS --set-tos Minimize-Delay $IPTABLES -t mangle -A OUTPUT -o $riface -p TCP --sport ftp -j TOS --set-tos Minimize-Delay $IPTABLES -t mangle -A OUTPUT -o $riface -p TCP --dport ftp -j TOS --set-tos Minimize-Delay $IPTABLES -t mangle -A OUTPUT -o $riface -p TCP --dport telnet -j TOS --set-tos Minimize-Delay $IPTABLES -t mangle -A OUTPUT -o $riface -p TCP --sport ftp-data -j TOS --set-tos Maximize-Throughput done print_info " done." } # }}} masquerade() { # {{{ if [ -z "$NAT_LAN_IFACE" ]; then return; fi print_info -en "NAT: Masquerading local subnet: $NAT_SUBNET_IFACE --> $NAT_LAN_IFACE" if [ "X$XEN_MODE" = "Xon" ]; then if [ -n "$NAT_SUBNET_SRC" ]; then NAT_SUBNET_SRC="-s $NAT_SUBNET_SRC"; fi $IPTABLES -t nat -A POSTROUTING -o $NAT_LAN_IFACE -j MASQUERADE $NAT_SUBNET_SRC print_info " done." print_info "XEN_MODE enabled: masquerade is limited to basic functionality only"; return; fi ip="`get_first_ip_addr IP_$NAT_SUBNET_IFACE`" netmask="Mask_$NAT_SUBNET_IFACE" localnet="$ip/${!netmask}" lan_ip="`get_first_ip_addr IP_$NAT_LAN_IFACE`" # alow packets from private subnet $IPTABLES -A FORWARD -s ! $localnet -i $NAT_SUBNET_IFACE -j DROP for client_ip in $NAT_CLIENT_DROP; do print_info -en " !$client_ip"; $IPTABLES -A FORWARD -s $client_ip -i $NAT_SUBNET_IFACE -j DROP done for redirect in $NAT_TCP_PORT_REDIRECT; do #eval `echo $redirect | $AWK -v FS=: '{ printf "remote_port=%s; local_port=%s;", $1, $2; }'` eval `echo $redirect | \ $AWK -v FS=: ' (NF == 2) { remote_ip = "$lan_ip"; remote_port = $1; local_port = $2; } \ (NF == 3) { remote_ip = $2; remote_port = $1; local_port = $3; } \ END { printf "remote_ip=%s; remote_port=%s; local_port=%s;", remote_ip, remote_port, local_port; }'` print_info -en " $remote_port>>$remote_ip:$local_port(tcp)" $IPTABLES -t nat -A PREROUTING -p TCP \ -i $NAT_SUBNET_IFACE \ --dport $remote_port -j REDIRECT --to-port $local_port done for redirect in $NAT_UDP_PORT_REDIRECT; do #eval `echo $redirect | $AWK -v FS=: '{ printf "remote_port=%s; local_port=%s;", $1, $2; }'` eval `echo $redirect | \ $AWK -v FS=: ' (NF == 2) { dnat = "no" ; remote_ip = "X"; remote_port = $1; local_port = $2; } \ (NF == 3) { dnat = "yes" ; remote_ip = $2; remote_port = $1; local_port = $3; } \ END { printf "dnat=%s; remote_ip=%s; remote_port=%s; local_port=%s;", dnat, remote_ip, remote_port, local_port; }'` print_info -en " $remote_port>>$remote_ip:$local_port(udp)" if [ "x$dnat" = "xyes" ]; then $IPTABLES -t nat -A PREROUTING -p UDP -i $NAT_SUBNET_IFACE -d ! $ip \ --dport $local_port -j DNAT --to $remote_ip:$remote_port $IPTABLES -A FORWARD -p UDP -i $NAT_SUBNET_IFACE -d ! $ip --dport $local_port -j ACCEPT else $IPTABLES -t nat -A PREROUTING -p UDP \ -i ! $NAT_LAN_IFACE -d ! $lan_ip \ --dport $remote_port -j REDIRECT --to-port $local_port fi done if [ -n "$NAT_SUBNET_SRC" ]; then NAT_SUBNET_SRC="-s $NAT_SUBNET_SRC"; fi $IPTABLES -t nat -A POSTROUTING -o $NAT_LAN_IFACE -j MASQUERADE $NAT_SUBNET_SRC print_info " done." # don't forward Miscrosoft protocols - NOT RFC compliant packets if [ ! -z "$NAT_FORWARD_MICROSOFT" ]; then if [ "x$NAT_FORWARD_MICROSOFT" = "xno" ]; then $IPTABLES -A FORWARD -p TCP ! --syn -m conntrack --ctstate NEW -j DROP for port in 67 68 69 135 445 1434 6667; do $IPTABLES -A FORWARD -p TCP --dport $port -j DROP $IPTABLES -A FORWARD -p UDP --dport $port -j DROP done fi fi if [ ! -z "$NAT_FORWARD_TCP_PORTS" ]; then print_info -en "\tAccepting FORWARD TCP ports:" for port in $NAT_FORWARD_TCP_PORTS; do print_info -en " $port" $IPTABLES -A FORWARD -p TCP --dport $port -m conntrack --ctstate NEW -j ACCEPT done print_info " done." fi if [ ! -z "$NAT_FORWARD_UDP_PORTS" ]; then print_info -en "\tAccepting FORWARD UDP ports:" for port in $NAT_FORWARD_UDP_PORTS; do print_info -en " $port" $IPTABLES -A FORWARD -p UDP --dport $port -m conntrack --ctstate NEW -j ACCEPT done print_info " done." fi # NAT_FORWARD_TCP_HOSTS {{{ if [ ! -z "$NAT_FORWARD_TCP_HOSTS" ]; then print_info -en "\tAccepting FORWARD TCP hosts:" for host in $NAT_FORWARD_TCP_HOSTS; do print_info -en " $host" $IPTABLES -A FORWARD -p TCP -d $host -m conntrack --ctstate NEW -j ACCEPT done print_info " done." fi # }}} # NAT_FORWARD_UDP_HOSTS {{{ if [ ! -z "$NAT_FORWARD_UDP_HOSTS" ]; then print_info -en "\tAccepting FORWARD UDP hosts:" for host in $NAT_FORWARD_UDP_HOSTS; do print_info -en " $host" $IPTABLES -A FORWARD -p UDP -d $host -m conntrack --ctstate NEW -j ACCEPT done print_info " done." fi # }}} # NAT_FORWARD_TCP_CLIENTS {{{ if [ ! -z "$NAT_FORWARD_TCP_CLIENTS" ]; then print_info -en "\tAccepting FORWARD TCP clients:" for client in $NAT_FORWARD_TCP_CLIENTS; do print_info -en " $client" $IPTABLES -A FORWARD -p TCP -s $client -m conntrack --ctstate NEW -j ACCEPT done print_info " done." fi # }}} # NAT_FORWARD_UDP_CLIENTS {{{ if [ ! -z "$NAT_FORWARD_UDP_CLIENTS" ]; then print_info -en "\tAccepting FORWARD UDP clients:" for client in $NAT_FORWARD_UDP_CLIENTS; do print_info -en " $client" $IPTABLES -A FORWARD -p UDP -s $client -m conntrack --ctstate NEW -j ACCEPT done print_info " done." fi # }}} print_info -en "\tAccepting ICMP packets:" for type in $ACCEPT_ICMP_PACKETS; do print_info -en " $type" $IPTABLES -A FORWARD -p ICMP --icmp-type $type -j ACCEPT done #$IPTABLES_LOG -A FORWARD -p ICMP -j LOG --log-prefix "FWD ICMP: " print_info " done." # Port forwarding to local machines if [ ! -z "$NAT_TCP_PORT_FORWARD" ]; then print_info -en "\tForwarding TCP ports to local machines:" for redirect in $NAT_TCP_PORT_FORWARD; do #eval `echo $redirect | $AWK -v FS=: '{ printf "src_port=%s; local_machine=%s; dest_port=%s;", $1, $2, $3; }'` eval `echo $redirect | \ $AWK -v FS=: ' (NF == 3) { src_ip = "$lan_ip" ; src_port = $1; local_machine = $2; dest_port = $3; } \ (NF == 4) { src_ip = $1 ; src_port = $2; local_machine = $3; dest_port = $4; } \ END { printf "src_ip=%s; src_port=%s; local_machine=%s; dest_port=%s;", src_ip, src_port, local_machine, dest_port; }'` print_info -en " $src_ip:$src_port -> $local_machine:$dest_port" $IPTABLES -t nat -A PREROUTING -p TCP -i $NAT_LAN_IFACE -d $src_ip \ --dport $src_port -j DNAT --to $local_machine:$dest_port $IPTABLES -A FORWARD -p TCP -i $NAT_LAN_IFACE -d $local_machine --dport $dest_port -j ACCEPT done print_info " done." fi if [ ! -z "$NAT_UDP_PORT_FORWARD" ]; then print_info -en "\tForwarding UDP ports to local machines:" for redirect in $NAT_UDP_PORT_FORWARD; do #eval `echo $redirect | $AWK -v FS=: '{ printf "src_port=%s; local_machine=%s; dest_port=%s;", $1, $2, $3; }'` eval `echo $redirect | \ $AWK -v FS=: ' (NF == 3) { src_ip = "$lan_ip" ; src_port = $1; local_machine = $2; dest_port = $3; } \ (NF == 4) { src_ip = $1 ; src_port = $2; local_machine = $3; dest_port = $4; } \ END { printf "src_ip=%s; src_port=%s; local_machine=%s; dest_port=%s;", src_ip, src_port, local_machine, dest_port; }'` print_info -en " $src_port -> $local_machine:$dest_port" $IPTABLES -t nat -A PREROUTING -p UDP -i $NAT_LAN_IFACE -d $lan_ip \ --dport $src_port -j DNAT --to $local_machine:$dest_port $IPTABLES -A FORWARD -p UDP -i $NAT_LAN_IFACE -d $local_machine --dport $dest_port -j ACCEPT done print_info " done." fi # Keep state of connections from private subnets $IPTABLES -A OUTPUT -m conntrack --ctstate NEW -o $NAT_LAN_IFACE -j ACCEPT #$IPTABLES -A FORWARD -m conntrack --ctstate NEW -o $NAT_LAN_IFACE -j ACCEPT $IPTABLES -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # hide NAT clients behind firewall: - set TTL # XXX: warning: this breaks traceroute !!! if [ ! "a$NAT_SET_TTL" = "ano" ]; then print_info "NAT: clients hidden behind firewall - setting TTL to $NAT_SET_TTL" $IPTABLES -t mangle -A POSTROUTING -o $NAT_LAN_IFACE -j TTL --ttl-set $NAT_SET_TTL fi } # }}} log_new_connections() { # {{{ if [ ! -z "$NAT_LOG_NEW_CONNECTIONS" ]; then if [ "x$NAT_LOG_NEW_CONNECTIONS" = "xyes" ]; then if [ "x$NAT_LOG_NEW_CONNECTIONS" = "xyes" ]; then NAT_LOG_NEW_CONNECTIONS="TCP UDP" fi print_info -en "Logging new connections $NAT_LOG_NEW_CONNECTIONS:" for proto in $NAT_LOG_NEW_CONNECTIONS; do $IPTABLES_LOG -A INPUT -m conntrack --ctstate NEW -p $proto -j LOG --log-prefix "IN connection: " $IPTABLES_LOG -A OUTPUT -m conntrack --ctstate NEW -p $proto -j LOG --log-prefix "OUT connection: " $IPTABLES_LOG -A FORWARD -m conntrack --ctstate NEW -p $proto -j LOG --log-prefix "FWD connection: " done print_info " done." fi fi } # }}} drop_output() { # {{{ for riface in $REAL_INTERFACES; do drop_output_tcp="${riface}_DROP_OUTPUT_TCP" DROP_OUTPUT_TCP="${!drop_output_tcp}" drop_output_udp="${riface}_DROP_OUTPUT_UDP" DROP_OUTPUT_UDP="${!drop_output_udp}" if [ ! -z "$DROP_OUTPUT_TCP" ]; then print_info -en "$riface: Dropping outgoing packets from ports:" for port in $DROP_OUTPUT_TCP; do print_info -en " $port" if [ "X$XEN_MODE" = "Xon" ]; then print_info -ne " XEN_MODE "; else $IPTABLES -A FORWARD -p TCP --sport $port -o $riface -j DROP fi $IPTABLES -A OUTPUT -p TCP --sport $port -o $riface -j DROP done print_info " done." fi if [ ! -z "$DROP_OUTPUT_UDP" ]; then print_info -en "$riface: Dropping outgoing packets from ports:" for port in $DROP_OUTPUT_UDP; do print_info -en " $port" if [ "X$XEN_MODE" = "Xon" ]; then print_info -ne " XEN_MODE "; else $IPTABLES -A FORWARD -p UDP --sport $port -o $riface -j DROP fi $IPTABLES -A OUTPUT -p UDP --sport $port -o $riface -j DROP done print_info " done." fi done } # }}} bann_ip_adresses() { # {{{ # # This feature has been developed for following reason: # UbiCrawler spam our website with many requests (they are duplicit requests of the same page!) # And this web robot doesn't accept HTTP META tags (http://www.robotstxt.org/wc/faq.html#extension) # # Bann them too! # #IP address is: 146.48.97.11 146.48.97.13 # User Agent: "UbiCrawler/v0.4beta (http://ubi.iit.cnr.it/projects/ubicrawler/)" # cf="$DEFAULT_FIREWALL_CONFIG_DIR/BANNED_IP.conf" if [ -f $cf ]; then BANNED_IP="$BANNED_IP `read_config_ips $cf`" fi if [ ! -z "$BANNED_IP" ]; then print_info -en "Dropping ALL packets from IP:" for banned_ip in $BANNED_IP; do print_info -en " $banned_ip" $IPTABLES -A INPUT -s $banned_ip -j DROP if [ "X$XEN_MODE" = "Xon" ]; then print_info -ne " XEN_MODE "; else $IPTABLES -A FORWARD -s $banned_ip -j DROP fi done print_info " done." fi } # }}} allow_accept_all() { # {{{ if [ ! -z "$IFACE_ACCEPT_ALL" ]; then print_info -en "Accepting ALL packets on interfaces:" for iface in $IFACE_ACCEPT_ALL; do print_info -en " $iface" $IPTABLES -A INPUT -i $iface -j ACCEPT $IPTABLES -A OUTPUT -o $iface -j ACCEPT if [ "X$XEN_MODE" = "Xon" ]; then print_info -ne " XEN_MODE "; else $IPTABLES -A FORWARD -i $iface -j ACCEPT fi done print_info " done." fi } # }}} drop_input() { # {{{ if [ ! -z "$NAT_LAN_IFACE" ]; then for client_ip in $NAT_CLIENT_DROP; do print_info -en " !$client_ip"; $IPTABLES -A INPUT -s $client_ip -i $NAT_SUBNET_IFACE -j DROP done fi if [ ! -z "$ALL_DROP_INPUT_TCP" ]; then print_info -en "Drop ALL INPUT TCP connections on ports:" for port in $ALL_DROP_INPUT_TCP; do echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi for riface in $REAL_INTERFACES; do print_info -en " $port($riface)" $IPTABLES -A INPUT -i $riface -p TCP $port_rule -j DROP done done print_info " done." fi if [ ! -z "$ALL_DROP_INPUT_UDP" ]; then print_info -en "Drop ALL INPUT UDP connections on ports:" for port in $ALL_DROP_INPUT_UDP; do echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi for riface in $REAL_INTERFACES; do print_info -en " $port($riface)" $IPTABLES -A INPUT -i $riface -p UDP $port_rule -j DROP done done print_info " done." fi if [ ! -z "$REAL_DROP_INPUT_TCP" ]; then print_info -en "Drop REAL all INPUT TCP connections for ALL interfaces on ports:" for port in $REAL_DROP_INPUT_TCP; do echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi print_info -en " $port(ALL)" $IPTABLES -A INPUT -p TCP $port_rule -j DROP done print_info " done." fi if [ ! -z "$REAL_DROP_INPUT_UDP" ]; then print_info -en "Drop REAL all INPUT UDP connections for ALL interfaces on ports:" for port in $REAL_DROP_INPUT_UDP; do echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi print_info -en " $port(ALL)" $IPTABLES -A INPUT -p UDP $port_rule -j DROP done print_info " done." fi } # }}} reject_input() { # {{{ if [ ! -z "$ALL_REJECT_INPUT_TCP" ]; then print_info -en "Reject ALL INPUT TCP connections on ports:" for port in $ALL_REJECT_INPUT_TCP; do echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi for riface in $REAL_INTERFACES; do print_info -en " $port($riface)" $IPTABLES -A INPUT -i $riface -p TCP $port_rule -j REJECT --reject-with $REJECT_WITH done done print_info " done." fi if [ ! -z "$ALL_REJECT_INPUT_UDP" ]; then print_info -en "Reject ALL INPUT UDP connections on ports:" for port in $ALL_REJECT_INPUT_UDP; do echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi for riface in $REAL_INTERFACES; do print_info -en " $port($riface)" $IPTABLES -A INPUT -i $riface -p UDP $port_rule -j REJECT --reject-with $REJECT_WITH done done print_info " done." fi if [ ! -z "$REAL_REJECT_INPUT_TCP" ]; then print_info -en "Reject REAL all INPUT TCP connections for ALL interfaces on ports:" for port in $REAL_REJECT_INPUT_TCP; do echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi print_info -en " $port(ALL)" $IPTABLES -A INPUT -p TCP $port_rule -j REJECT --reject-with $REJECT_WITH done print_info " done." fi if [ ! -z "$REAL_REJECT_INPUT_UDP" ]; then print_info -en "Reject REAL all INPUT UDP connections for ALL interfaces on ports:" for port in $REAL_REJECT_INPUT_UDP; do echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi for riface in $REAL_INTERFACES; do print_info -en " $port(ALL)" $IPTABLES -A INPUT -p UDP $port_rule -j REJECT --reject-with $REJECT_WITH done done print_info " done." fi } # }}} allow_input() { # {{{ if [ ! -z "$ALL_ACCEPT_INPUT_TCP" ]; then print_info -en "Accepting ALL INPUT TCP connections on ports:" for port in $ALL_ACCEPT_INPUT_TCP; do src_ip="" eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'` echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi for iface in $INTERFACES; do riface="IFname_$iface"; print_info -en " $port($iface)"`[ ! -z "$src_ip" ] && echo "[$src_ip]"` IPS="IP_$iface"; for ip in ${!IPS}; do if [ -z "$src_ip" ]; then $IPTABLES -A INPUT -i ${!riface} -d $ip -p TCP $port_rule -j ACCEPT else $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p TCP $port_rule -j ACCEPT fi done done done print_info " done." fi if [ ! -z "$ALL_ACCEPT_INPUT_UDP" ]; then print_info -en "Accepting ALL INPUT UDP connections on ports:" for port in $ALL_ACCEPT_INPUT_UDP; do src_ip="" eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'` echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi for iface in $INTERFACES; do riface="IFname_$iface"; print_info -en " $port($iface)"`[ ! -z "$src_ip" ] && echo "[$src_ip]"` IPS="IP_$iface"; if [ "x$port" = "x67" ]; then # DHCP requests doesn't have destination IP specified $IPTABLES -A INPUT -i ${!riface} -p UDP --dport $port -j ACCEPT else for ip in ${!IPS}; do if [ -z "$src_ip" ]; then $IPTABLES -A INPUT -i ${!riface} -d $ip -p UDP $port_rule -j ACCEPT else $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p UDP $port_rule -j ACCEPT fi done fi done done print_info " done." fi if [ ! -z "$REAL_ACCEPT_INPUT_TCP" ]; then print_info -en "Accepting REAL all INPUT TCP connections for ALL interfaces on ports:" for port in $REAL_ACCEPT_INPUT_TCP; do src_ip="" eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'` print_info -en " $port(ALL)"`[ ! -z "$src_ip" ] && echo "[$src_ip]"` echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi if [ -z "$src_ip" ]; then $IPTABLES -A INPUT -p TCP $port_rule -j ACCEPT else $IPTABLES -A INPUT -s $src_ip -p TCP $port_rule -j ACCEPT fi done print_info " done." fi if [ ! -z "$REAL_ACCEPT_INPUT_UDP" ]; then print_info -en "Accepting REAL all INPUT UDP connections for ALL interfaces on ports:" for port in $REAL_ACCEPT_INPUT_UDP; do src_ip="" eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'` print_info -en " $port(ALL)"`[ ! -z "$src_ip" ] && echo "[$src_ip]"` echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi if [ -z "$src_ip" ]; then $IPTABLES -A INPUT -p UDP $port_rule -j ACCEPT else $IPTABLES -A INPUT -s $src_ip -p UDP $port_rule -j ACCEPT fi done print_info " done." fi # We are using REAL_INTERFACES instead of INTERFACES here, because we want # to do redirects for "lo" interface as well. However for "lo" it is done # quite differently. See http://ix.sk/0WY2j for more information on this. # -- Nepto [2015-10-19] for iface in $REAL_INTERFACES; do riface="IFname_$iface"; IPS="IP_$iface"; redirect_tcp="${iface}_REDIRECT_TCP" REDIRECT_TCP="${!redirect_tcp}" redirect_udp="${iface}_REDIRECT_UDP" REDIRECT_UDP="${!redirect_udp}" reject_input_tcp="${iface}_REJECT_INPUT_TCP" REJECT_INPUT_TCP="${!reject_input_tcp}" reject_input_udp="${iface}_REJECT_INPUT_UDP" REJECT_INPUT_UDP="${!reject_input_udp}" accept_input_tcp="${iface}_ACCEPT_INPUT_TCP" ACCEPT_INPUT_TCP="${!accept_input_tcp}" accept_input_udp="${iface}_ACCEPT_INPUT_UDP" ACCEPT_INPUT_UDP="${!accept_input_udp}" if [ ! -z "$REDIRECT_TCP" ]; then print_info -en "$iface: redirecting TCP connections:" ip="`get_first_ip_addr IP_$iface`"; for redirect in $REDIRECT_TCP; do eval `echo $redirect | \ $AWK -v FS=: ' (NF == 2) { remote_ip = "0.0.0.0/0"; from_port = $1; to_port = $2; } \ (NF == 3) { remote_ip = $1; from_port = $2; to_port = $3; } \ END { printf "remote_ip=%s; from_port=%s; to_port=%s;", remote_ip, from_port, to_port; }'` print_info -en " $remote_ip:$from_port->$to_port" if [ "X$iface" = "Xlo" ]; then $IPTABLES -t nat -A OUTPUT -p TCP -s $remote_ip -d $ip --dport $from_port -j REDIRECT --to-port $to_port else $IPTABLES -t nat -A PREROUTING -p TCP -i ${!riface} -s $remote_ip -d $ip --dport $from_port -j REDIRECT --to-port $to_port fi done print_info " done." fi if [ ! -z "$REDIRECT_UDP" ]; then print_info -en "$iface: redirecting UDP connections:" ip="`get_first_ip_addr IP_$iface`"; for redirect in $REDIRECT_UDP; do eval `echo $redirect | \ $AWK -v FS=: ' (NF == 2) { remote_ip = "0.0.0.0/0"; from_port = $1; to_port = $2; } \ (NF == 3) { remote_ip = $1; from_port = $2; to_port = $3; } \ END { printf "remote_ip=%s; from_port=%s; to_port=%s;", remote_ip, from_port, to_port; }'` print_info -en " $remote_ip:$from_port->$to_port" if [ "X$iface" = "Xlo" ]; then $IPTABLES -t nat -A OUTPUT -p UDP -s $remote_ip -d $ip --dport $from_port -j REDIRECT --to-port $to_port else $IPTABLES -t nat -A PREROUTING -p UDP -i ${!riface} -s $remote_ip -d $ip --dport $from_port -j REDIRECT --to-port $to_port fi done print_info " done." fi # REJECT {{{ if [ ! -z "$REJECT_INPUT_TCP" ]; then print_info -en "$iface: Rejecting INPUT TCP connections on ports:" for port in $REJECT_INPUT_TCP; do src_ip="" eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'` print_info -en " $port"`[ ! -z "$src_ip" ] && echo "[$src_ip]"` echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi for ip in ${!IPS}; do if [ -z "$src_ip" ]; then $IPTABLES -A INPUT -i ${!riface} -d $ip -p TCP $port_rule -j REJECT --reject-with $REJECT_WITH else $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p TCP $port_rule -j REJECT --reject-with $REJECT_WITH fi done done print_info " done." fi if [ ! -z "$REJECT_INPUT_UDP" ]; then print_info -en "$iface: Rejecting INPUT UDP connections on ports:" for port in $REJECT_INPUT_UDP; do src_ip="" eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'` print_info -en " $port"`[ ! -z "$src_ip" ] && echo "[$src_ip]"` echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi for ip in ${!IPS}; do if [ -z "$src_ip" ]; then $IPTABLES -A INPUT -i ${!riface} -d $ip -p UDP $port_rule -j REJECT --reject-with $REJECT_WITH else $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p UDP $port_rule -j REJECT --reject-with $REJECT_WITH fi done done print_info " done." fi # }}} # ACCEPT {{{ if [ ! -z "$ACCEPT_INPUT_TCP" ]; then print_info -en "$iface: Accepting INPUT TCP connections on ports:" counter=0; for port in $ACCEPT_INPUT_TCP; do src_ip="" eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'` if [ -n "$src_ip" -a "$port" = "0" ]; then port="ALL"; fi print_info -en " $port"`[ ! -z "$src_ip" ] && echo "[$src_ip]"` if [ $(( ++counter )) -ge 5 -o "x$port" = "x10050" ]; then counter=0; print_info ""; fi; echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi for ip in ${!IPS}; do if [ -z "$src_ip" ]; then $IPTABLES -A INPUT -i ${!riface} -d $ip -p TCP $port_rule -j ACCEPT else if [ "$port" = "ALL" ]; then $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p TCP -j ACCEPT else $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p TCP $port_rule -j ACCEPT fi fi done done print_info " done." fi if [ ! -z "$ACCEPT_INPUT_UDP" ]; then print_info -en "$iface: Accepting INPUT UDP connections on ports:" for port in $ACCEPT_INPUT_UDP; do src_ip="" eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'` if [ -n "$src_ip" -a "$port" = "0" ]; then port="ALL"; fi echo $port | grep -q , multiport="$?"; if [ "$multiport" -eq 0 ]; then port_rule="--match multiport --dports $port" else port_rule="--dport $port" fi print_info -en " $port"`[ ! -z "$src_ip" ] && echo "[$src_ip]"` #$IPTABLES -A INPUT -i $iface -d ${!INET_IP} -p UDP --dport $port -j ACCEPT #$IPTABLES -A INPUT -i $iface --source 192.168.1.0/16 -p UDP --dport $port -j ACCEPT if [ "x$port" = "x67" ]; then # DHCP requests doesn't have destination IP specified $IPTABLES -A INPUT -i ${!riface} -p UDP --dport $port -j ACCEPT else for ip in ${!IPS}; do if [ -z "$src_ip" ]; then $IPTABLES -A INPUT -i ${!riface} -d $ip -p UDP $port_rule -j ACCEPT else if [ "$port" = "ALL" ]; then $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p UDP -j ACCEPT else $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p UDP $port_rule -j ACCEPT fi fi done fi done print_info " done." fi # }}} done # Enable outgoing TRACEROUTE requests (required e.g. by Skype, http://www.skype.com) if [ ! -z "$TRACEROUTE_IFACE" ]; then ip="`get_first_ip_addr IP_$ANTISPOOF_IFACE`"; print_info -en "Accepting traceroute:" if [ "X$XEN_MODE" = "Xon" ]; then print_info -ne " XEN_MODE "; else $IPTABLES -A OUTPUT -o $ANTISPOOF_IFACE -p UDP \ --sport $TRACEROUTE_SRC_PORTS --dport $TRACEROUTE_DEST_PORTS \ -s $ip -d $ANYWHERE -j ACCEPT for iface in $TRACEROUTE_IFACE; do $IPTABLES -A FORWARD -p UDP -i $iface --sport $TRACEROUTE_SRC_PORTS \ --dport $TRACEROUTE_DEST_PORTS -j ACCEPT done fi print_info " done." fi } # }}} # ACCEPT selected IPs/ports if defined for interface # if not defined ACCEPT all packets from our IP addresses allow_output() { # {{{ output_tcp_str=""; output_udp_str=""; output_icmp_str=""; for iface in $INTERFACES; do gateway="Gateway_$iface"; riface="IFname_$iface"; IPS="IP_$iface"; accept_output_tcp="${iface}_ACCEPT_OUTPUT_TCP" ACCEPT_OUTPUT_TCP="${!accept_output_tcp}" accept_output_udp="${iface}_ACCEPT_OUTPUT_UDP" ACCEPT_OUTPUT_UDP="${!accept_output_udp}" # TCP if [ -z "$ACCEPT_OUTPUT_TCP" ]; then if [ -n "${!gateway}" ]; then for ip in ${!IPS}; do output_tcp_str="$output_tcp_str $ip:${!riface}:${!gateway}"; $IPTABLES -A OUTPUT -p TCP -o ${!riface} -s $ip -j ACCEPT done fi else print_info -en "$iface: Accepting OUTPUT TCP connections to ports:" for port in $ACCEPT_OUTPUT_TCP; do dest_ip="" eval `echo $port | awk -v FS=: '/:/ { printf "dest_ip=\"%s\"; port=\"%s\";", $1, $2; }'` if [ -n "$dest_ip" -a "$port" = "0" ]; then port="ALL"; fi print_info -en " $port"`[ ! -z "$dest_ip" ] && echo "[$dest_ip]"` if [ -z "$dest_ip" ]; then $IPTABLES -A OUTPUT -o ${!riface} -p TCP --dport $port -j ACCEPT else if [ "$port" = "ALL" ]; then $IPTABLES -A OUTPUT -o ${!riface} -d $dest_ip -p TCP -j ACCEPT else $IPTABLES -A OUTPUT -o ${!riface} -d $dest_ip -p TCP --dport $port -j ACCEPT fi fi done print_info " done." fi # UDP if [ -z "$ACCEPT_OUTPUT_UDP" ]; then if [ -n "${!gateway}" ]; then for ip in ${!IPS}; do output_udp_str="$output_udp_str $ip:${!riface}:${!gateway}"; $IPTABLES -A OUTPUT -p UDP -o ${!riface} -s $ip -j ACCEPT done fi else print_info -en "$iface: Accepting OUTPUT UDP connections to ports:" for port in $ACCEPT_OUTPUT_UDP; do dest_ip="" eval `echo $port | awk -v FS=: '/:/ { printf "dest_ip=\"%s\"; port=\"%s\";", $1, $2; }'` if [ -n "$dest_ip" -a "$port" = "0" ]; then port="ALL"; fi print_info -en " $port"`[ ! -z "$dest_ip" ] && echo "[$dest_ip]"` if [ -z "$dest_ip" ]; then $IPTABLES -A OUTPUT -o ${!riface} -p UDP --dport $port -j ACCEPT else if [ "$port" = "ALL" ]; then $IPTABLES -A OUTPUT -o ${!riface} -d $dest_ip -p UDP -j ACCEPT else $IPTABLES -A OUTPUT -o ${!riface} -d $dest_ip -p UDP --dport $port -j ACCEPT fi fi done print_info " done." fi # ICMP if [ -n "${!gateway}" ]; then for ip in ${!IPS}; do output_icmp_str="$output_icmp_str $ip:${!riface}:${!gateway}"; $IPTABLES -A OUTPUT -p ICMP -o ${!riface} -s $ip -j ACCEPT done fi done if [ -n "$output_tcp_str" ]; then print_info "Accepting OUTPUT TCP packets through $output_tcp_str done." fi if [ -n "$output_udp_str" ]; then print_info "Accepting OUTPUT UDP packets through $output_udp_str done." fi if [ -n "$output_icmp_str" ]; then print_info "Accepting OUTPUT ICMP packets through $output_icmp_str done." fi } # }}} allow_icmp() { # {{{ print_info -en "Accepting ICMP packets:" # accept only allowed ICMP packets for type in $ACCEPT_ICMP_PACKETS; do print_info -en " $type" for iface in $INTERFACES; do riface="IFname_$iface"; IPS="IP_$iface"; for ip in ${!IPS}; do $IPTABLES -A INPUT -i ${!riface} -d $ip -p ICMP --icmp-type $type -j ACCEPT done done done #$IPTABLES_LOG -A INPUT -p ICMP -j LOG --log-prefix "IN ICMP: " #$IPTABLES_LOG -A OUTPUT -p ICMP -j LOG --log-prefix "OUT ICMP: " print_info " done." } # }}} log_input_drop() { # {{{ if [ ! "x$LOGGING" = "xoff" ]; then prefix="input drop: " print_info "Input drop is logged with prefix '$prefix'" $IPTABLES_LOG -A INPUT $LOG_LIMIT "$prefix" fi } # }}} log_output_drop() { # {{{ if [ ! "x$LOGGING" = "xoff" ]; then prefix="output drop: " print_info "Output drop is logged with prefix '$prefix'" $IPTABLES_LOG -A OUTPUT $LOG_LIMIT "$prefix" fi } # }}} log_forward_drop() { # {{{ if [ ! "x$LOGGING" = "xoff" ]; then prefix="forward drop: " print_info "Forward drop is logged with prefix '$prefix'" $IPTABLES_LOG -A FORWARD $LOG_LIMIT "$prefix" fi } # }}} configure_special_rules() { # {{{ print_info -en "Loading special rules: " ## ## for DSL from Slovanet (Slovak DSL provider) and DSL modem DLINK DSL-360T you must add following rule for proper ssh connect to your machine ## # print_info -en "slovanet " # $IPTABLES -t mangle -A OUTPUT -s 0/0 -j DSCP --set-dscp 0 print_info " done."; } # }}} custom_rules() { # {{{ print_info -en "Executing custom rules: " for max_rule_num in 9 99 999; do initialized="no"; for i in `seq -w 0 "$max_rule_num"`; do varname="CUSTOM_RULE_$i"; if [ -z "${!varname}" ]; then break; fi print_info -n "#$i"; $IPTABLES ${!varname}; rc="$?"; if [ "$rc" -eq 0 ]; then print_info -n "[OK] "; else print_info -n "[rc:$?] "; fi; initialized="yes"; done if [ "X$initialized" = "Xyes" ]; then break; fi done print_info " done."; } # }}} do_ip_accounting() { # {{{ if [ ! "x$DO_LOCAL_IP_ACCOUNTING" = "xno" ]; then if [ ! -z "$NAT_LAN_IFACE" ]; then IPACCT_NAME="ZORBCOUNT" IPACCT_IN_NAME="ZORBCOUNTIN" IPACCT_OUT_NAME="ZORBCOUNTOUT" $IPTABLES -N $IPACCT_NAME # whole network $IPTABLES -N $IPACCT_IN_NAME # download: from server to client $IPTABLES -A $IPACCT_IN_NAME $IPTABLES -N $IPACCT_OUT_NAME # upload: from client to server $IPTABLES -A $IPACCT_OUT_NAME ip="`get_first_ip_addr IP_$NAT_SUBNET_IFACE`"; netmask="Mask_$NAT_SUBNET_IFACE" localnet="$ip/${!netmask}" $IPTABLES -I INPUT -i $NAT_LAN_IFACE -j $IPACCT_IN_NAME $IPTABLES -I OUTPUT -o $NAT_LAN_IFACE -j $IPACCT_OUT_NAME if [ "X$XEN_MODE" = "Xon" ]; then print_info -ne " XEN_MODE "; else $IPTABLES -I FORWARD -s $localnet -o $NAT_LAN_IFACE -j $IPACCT_NAME $IPTABLES -I FORWARD -d $localnet -i $NAT_LAN_IFACE -j $IPACCT_NAME fi for client_ip in $IP_ACCT_CLIENTS; do $IPTABLES -A $IPACCT_NAME -s $client_ip $IPTABLES -A $IPACCT_NAME -d $client_ip done if [ ! "x$DO_LOCAL_IP_ACCOUNTING" = "xno" ]; then accountig_ports=`echo "$NAT_TCP_PORT_REDIRECT " | $AWK -v RS=' ' -v FS=: '{ print $2; }' | sort -u -r -g ` for port in $accountig_ports; do $IPTABLES -I INPUT -i $NAT_SUBNET_IFACE -p TCP --dport $port -j $IPACCT_NAME $IPTABLES -I INPUT -i $NAT_SUBNET_IFACE -p UDP --dport $port -j $IPACCT_NAME $IPTABLES -I OUTPUT -o $NAT_SUBNET_IFACE -p TCP --sport $port -j $IPACCT_NAME $IPTABLES -I OUTPUT -o $NAT_SUBNET_IFACE -p UDP --sport $port -j $IPACCT_NAME done fi $IPTABLES -A $IPACCT_NAME -s $localnet $IPTABLES -A $IPACCT_NAME -d $localnet fi fi } # }}} accept_related() { # {{{ print_info -en "Accepting ESTABLISHED, RELATED packets ..." $IPTABLES -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT print_info " done." } # }}} accept_loopback() { # {{{ # Loopback není radno omezovat print_info -en "Accepting loopback:" $IPTABLES -A INPUT -i $LO_IFACE -j ACCEPT $IPTABLES -A OUTPUT -o $LO_IFACE -j ACCEPT print_info " done." } # }}} # # Shaping support {{{ # # http://koti.welho.com/ntoivol2/shaping/ # shaping_on() { # {{{ mark_idx=1 if [ ! -z "$SHAPING_IFACE" ]; then for iface in $SHAPING_IFACE; do echo "Shaping for interface $iface" shaping_classes="${iface}_SHAPING_CLASSES" # root qdisc: 2-band prio with everything defaulting to band 0 $TC qdisc add dev $iface root handle 1: prio bands 2 priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 for class in ${!shaping_classes}; do rate="${iface}_SHAPING_RATE_${class}" latency="${iface}_SHAPING_LATENCY_${class}" burst="${iface}_SHAPING_BURST_${class}" netmask="${iface}_SHAPING_NETMASK_${class}" echo -e "\tshaping \"$class\" traffic: rate=${!rate} burst=${!burst} netmask=${!netmask}" if [ -z "${!netmask}" ]; then $IPTABLES -t mangle -A OUTPUT -j MARK --set-mark 0x$mark_idx else $IPTABLES -t mangle -A OUTPUT -d ${!netmask} -j MARK --set-mark 0x$mark_idx fi if [ -z "${!rate}" ]; then # SFQ for local traffic $TC qdisc add dev $iface parent 1:$mark_idx handle $((10 + $mark_idx)): sfq perturb 10 else # TBF shaping and SFQ for internet traffic $TC qdisc add dev $iface parent 1:$mark_idx handle $((10 + $mark_idx)): tbf rate ${!rate} burst ${!burst} latency ${!latency} $TC qdisc add dev $iface parent $((10 + $mark_idx)): handle $((10 * $mark_idx)): sfq perturb 10 fi mark_idx=$(($mark_idx + 1)) done done fi } # }}} shaping_off() { # {{{ if [ ! -z "$SHAPING_IFACE" ]; then echo -en "Shaping turned off for interface" for iface in $SHAPING_IFACE; do echo -en " $iface" $TC qdisc del dev $iface root 2>/dev/null done echo ". done" fi } # }}} shaping_status() { # {{{ if [ ! -z "$SHAPING_IFACE" ]; then echo "# Shaping status: " $TC qdisc list else echo "# Shaping turned off" fi } # }}} # }}} add_banned_ip() { # {{{ echo "# `date '+%Y-%m-%d %X' `" >> $DEFAULT_FIREWALL_CONFIG_DIR/BANNED_IP.conf TMPFILE=`mktemp -t fw-universal.sh-XXXXXX` || exit 1 trap 'rm -f $TMPFILE' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 if [ -z "$*" ]; then #print_info "Reading banned IP's from STDIN:" cat >> $TMPFILE else for IP in $*; do echo $IP >> $TMPFILE; done fi read_config_ips $TMPFILE >> $DEFAULT_FIREWALL_CONFIG_DIR/BANNED_IP.conf rm -f $TMPFILE # start with new firewalling rules $0 start } # }}} deploy_block() { # {{{ if [ -z "$*" ]; then echo "Usage: $0 deploy-block IP1/netmask1 IP2/netmask2 ..." exit 1; fi print_info "Deploying to local rules ..." add_banned_ip $* # start the same script twice to refresh rules (new blocked IP's) QUIET=yes $0 start TMPFILE=`mktemp -t fw-universal.sh-XXXXXX` || exit 1 trap 'rm -f $TMPFILE' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 for i in $*; do echo "block $i" >> $TMPFILE; done while read conn keyfile do case "$conn" in ""|\#*) continue ;; esac print_info "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" print_info "Deploying to $conn ..."; cat $TMPFILE | ssh -i $keyfile $conn $0 remote done < $DEFAULT_FIREWALL_CONFIG_DIR/deploy-servers.list rm -f $TMPFILE } # }}} update_from_cvs() { # {{{ cd /etc/firewall && cvs up -d } # }}} update() { # {{{ $UPDATE_SCRIPT } # }}} deploy_update() { # {{{ print_info "Updating local firewall ..." $0 update # start the same script twice to refresh rules (updated scripts and configs) QUIET=yes $0 start while read conn keyfile do case "$conn" in ""|\#*) continue ;; esac print_info "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" print_info "Updating $conn ..."; echo "update" | ssh -i $keyfile $conn $0 remote done < $DEFAULT_FIREWALL_CONFIG_DIR/deploy-servers.list } # }}} remote() { # {{{ while read comnd par do case "$comnd" in block) echo "Blocking '$par'..." add_banned_ip $par ;; update) echo "Updating firewall scripts..." update ;; ""|\#*) echo "Line '$comnd $par' ignored" continue ;; esac done } # }}} # Parse output from ifconfig: - tested on Linux and FreeBSD # http://platon.sk/cvs/cvs.php/scripts/shell/firewall/ifconfig-parse.sh parse_ifconfig() { # {{{ # Parse output from ifconfig: parsed_interfaces=`$IFCONFIG | \ $PERL -e ' my $iface_count = 0; my $iface; my (%ip, %ifname, %ip6, %scope6, %bcast, %mask, %hwaddr, %ipcount); while (my $line = ) { chomp $line; if ($line =~ m/^([a-z0-9:]+)\s+.*?([a-z0-9:]+)\s*$/i) { # Linux interface $iface = $1; my $iface_hwaddr = $2; my $x_iface = $iface; $iface =~ s/:$//g; $iface =~ s/:/_/g; # convert "eth0:0" --> "eth0_0" $x_iface = [ $x_iface =~ m/^([a-z0-9]+)/i ]->[0]; # convert "eth0:0" --> "eth0" $ifname{$iface} = $x_iface; $ipcount{$iface}++; $hwaddr{$iface} = $iface_hwaddr; $iface_count++; } elsif ($line =~ m/^[ \t]+inet addr:/) { # Linux IP address die unless defined $iface; my @fields = split(/[\s:]+/, $line); push @{$ip{$iface}}, $fields[3]; $bcast{$iface} = $fields[5] || ""; # invalid for loopback interface lo, but we don t need this $mask{$iface} = $fields[7] || $fields[5]; # for loopback interface lo } elsif($line =~ m/^[ \t]+inet6 addr:/) { # Linux IPv6 address die unless defined $iface; my @fields = split(/\s+/, $line); push @{$ip6{$iface}}, $fields[3]; $scope6{$iface} = [ $fields[4] =~ m/Scope:(.*)$/i ]->[0]; } elsif ($line =~ m/^[ \t]+inet\s/) { # Linux IP address die unless defined $iface; my @fields = split(/[\s:]+/, $line); push @{$ip{$iface}}, $fields[2]; $bcast{$iface} = (defined($fields[5]) and $fields[5] eq "broadcast") ? $fields[6] : ""; $mask{$iface} = $fields[4]; } } map { printf "IP_%s=\"%s\"; export IP_%s;\n", $_, join(" ", @{$ip{$_}}), $_; } keys %ip; map { printf "IFACE_6_%s=\"%s\"; export IFACE_6_%s;\n", $_, join(" ", @{$ip6{$_}}), $_; } keys %ip6; map { printf "SCOPE_6_%s=\"%s\"; export SCOPE_6_%s;\n", $_, $scope6{$_}, $_; } keys %scope6; map { printf "Bcast_%s=\"%s\"; export Bcast_%s;\n", $_, $bcast{$_}, $_; } keys %bcast; map { printf "Mask_%s=\"%s\"; export Mask_%s;\n", $_, $mask{$_}, $_; } keys %mask; map { printf "HWaddr_%s=\"%s\"; export HWaddr_%s;\n", $_, $hwaddr{$_}, $_; } keys %hwaddr; map { printf "IPcount_%s=\"%s\"; export IPcount_%s;\n", $_, $ipcount{$_}, $_; } keys %ipcount; map { printf "IFname_%s=\"%s\"; export IFname_%s;\n", $_, $ifname{$_}, $_; } keys %ifname; printf "interfaces=\"%s\"; export interfaces;\n", join(" ", sort keys %ip); '` #echo "$parsed_interfaces"; eval "$parsed_interfaces"; parsed_routes=`$PERL -e ' $\ = "\n"; open(FILE, "/proc/net/route") or die "Can not open /proc/net/route: $!"; my @columns = split(/\s+/, ); while (my $line = ) { my $iface; my @vals = split(/\s+/, $line); foreach my $key (@columns) { $iface->{$key} = shift @vals; } foreach my $key (qw( Gateway Destination )) { print "${key}_$iface->{Iface}=", qw("), hex2ip($iface->{$key}), qw("), "; export ${key}_$iface->{Iface};"; } foreach my $key (qw( Flags MTU Metric Window IRTT )) { print "${key}_$iface->{Iface}=", qw("), $iface->{$key}, qw("), "; export ${key}_$iface->{Iface};"; } } close(FILE); sub hex2ip { # {{{ my ($str) = @_; my @block; my $hex = uc($str); while (length($hex)) { my $x = ord(substr($hex, 0, 1)); my $y = ord(substr($hex, 1, 1)); $x = $x > 64 ? $x - 55 : $x - 48; $y = $y > 64 ? $y - 55 : $y - 48; push @block, 16 * $x + $y; $hex = substr($hex, 2); } return join(".", reverse @block); } # }}} '` #echo $parsed_routes eval "$parsed_routes"; # 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 } # }}} # helper function for string padding str_pad_right() { # {{{ num="$1"; string="$2"; count=$(echo -n "$string" | wc -c); count=$((count + 0)) while [ $count -lt $num ]; do string="$string "; count=$((count + 1)); done echo -n "$string" return; } # }}} pad7() { str_pad_right 7 "$1"; } pad15() { str_pad_right 15 "$1"; } check_tools parse_ifconfig print_iface_status # # Split interfaces into 2 groups: # # $INTERFACES_ACCEPT_ALL - interfaces withouth restrictions # # $INTERFACES - all interfaces withouth loopback # and devices without restrictions (e.g. tun0 tun1 tap0 eth0_0 eth0_1 ...) # # $REAL_INTERFACES - aliases like eth0:0, eth1:0 are transformed to eth0, eth1, ... # # list of all interfaces is in $interfaces variable # INTERFACES="" INTERFACES_ACCEPT_ALL="" x_REAL_INTERFACES="" regexp='^\('`echo $IFACE_ACCEPT_ALL | sed 's/ /\\\|/g; s/+/.*/g;'`'\)$' for iface in $interfaces; do riface="IFname_$iface"; x_REAL_INTERFACES="$x_REAL_INTERFACES ${!riface}" #if [ "o$iface" = "olo" ]; then continue; fi echo $iface | grep -q -e "$regexp" if [ $? = 0 ] || [ "o$iface" = "olo" ]; then # lo interface is always here INTERFACES_ACCEPT_ALL="$INTERFACES_ACCEPT_ALL $iface"; else INTERFACES="$INTERFACES $iface"; fi done REAL_INTERFACES="`echo $x_REAL_INTERFACES | awk -v RS=' ' '{ print; }' | sort -u`" INTERFACES_ACCEPT_ALL="$IFACE_ACCEPT_ALL" case "$1" in start) print_info -n "Starting $DESC: " # Inicialize modules #$DEPMOD -a load_modules load_cache set_default_policy remove_chains # # (un)commnet next lines as needed # bann_ip_adresses allow_accept_all nmap_scan_filter invalid_packet_filter anti_spoof_filter #syn_flood mangle_prerouting mangle_output accept_related log_new_connections drop_output drop_input reject_input allow_input allow_output allow_icmp accept_loopback masquerade forward_on log_input_drop log_output_drop log_forward_drop do_ip_accounting shaping_off shaping_on configure_special_rules custom_rules $IPTABLES_SAVE -c > $CACHE_FILE ;; stop) print_info -n "Stopping $DESC: " shaping_off set_default_policy remove_chains unload_modules forward_off accept_related ;; really-off) print_info -n "Stopping $DESC: removing ALL rules, all packets are dropped !!" set_default_policy remove_chains unload_modules forward_off ;; status) print_iface_status; echo $IPTABLES -L -nv shaping_status ;; purge) find $DEFAULT_CACHE_DIR -type f -ls -exec rm -f {} \; ;; block) shift; add_banned_ip $*; # start the some script twice to refresh rules (new blocked IP's) QUIET=yes $0 start; ;; update) update; ;; deploy-block) shift; deploy_block $*; ;; deploy-update) deploy_update; ;; remote) remote; ;; *) echo "Usage: $0 {start|stop|really-off|status|purge|block|deploy-block|deploy-update|update}" >&2 exit 1 ;; esac exit 0 # vim600: fdm=marker fdl=0 fdc=3