#!/bin/bash # # IPv6 firewall script for Linux 2.6 with IPv6 connection tracking enabled. # Based on Best Current Practice for Filtering ICMPv6 Messages in Firewalls # (draft-ietf-v6ops-icmpv6-filtering-bcp-01.txt) # # set -x # Set of prefixes on the trusted ("inner") side of the firewall export INNER_PREFIXES="2001:DB8:85::/60" # Set of prefixes on the untrusted ("outer") side of the firewall export OUTER_PREFIXES="2001:DB8:86::/60" # Services provided from the inner side: # Service name must be either PING, DOMAIN # or a TCP-based service name from /etc/services. export SERVICES="PING SSH HTTP DOMAIN" # Set of hosts providing the given services export SERVICE_PING="2001:DB8:85::/64" export SERVICE_SSH="2001:DB8:85::1/64" export SERVICE_HTTP="2001:DB8:85::1/64" export SERVICE_DOMAIN="2001:DB8:85::1/64" # Services provided from the firewall itself # Service name must be either PING # or a TCP-based service name from /etc/services. export LOCAL_SERVICES="PING SSH" # Set of hosts for which the services are allowed from the firewall itself export LOCAL_SERVICE_PING="2001:DB8:85::1/64" export LOCAL_SERVICE_SSH="2001:DB8:85::1/64" # Configuration option: Change this to 1 if the site support # Mobile IPv6 Home Agents export HOME_AGENTS_PRESENT=1 # Configuration option: Change this to 1 if the site support # Mobile IPv6 mobile nodes being present on the site export MOBILE_NODES_PRESENT=1 # The ip6tables command ip6tables=ip6tables # Create logging chains in order to record every # accepted session and denied packet for type in accept drop do target=`echo $type | tr [a-z] [A-Z]` $ip6tables -N $type $ip6tables -A $type -j LOG --log-prefix "${target}: " $ip6tables -A $type -j $target done # Create a chain to accept the selected list of ICMPv6 reply # packets only (established or related) $ip6tables -N icmpv6-state # List all accepted ICMPv6 error type/code export ACCEPT_ICMPV6_TYPE="" # Allow destination unreachable messages ACCEPT_ICMPV6_TYPE="$ACCEPT_ICMPV6_TYPE destination-unreachable" # Allow Packet Too Big messages ACCEPT_ICMPV6_TYPE="$ACCEPT_ICMPV6_TYPE packet-too-big" # Allow time exceeded code 0 and 1 messages ACCEPT_ICMPV6_TYPE="$ACCEPT_ICMPV6_TYPE ttl-zero-during-transit" ACCEPT_ICMPV6_TYPE="$ACCEPT_ICMPV6_TYPE ttl-zero-during-reassembly" # Allow parameter problem code 1 and 2 messages ACCEPT_ICMPV6_TYPE="$ACCEPT_ICMPV6_TYPE unknown-header-type" ACCEPT_ICMPV6_TYPE="$ACCEPT_ICMPV6_TYPE unknown-option" # Established: allow ICMPv6 echo reply packets $ip6tables -A icmpv6-state -p icmpv6 --icmpv6-type echo-reply -j ACCEPT # Related: allow the selected list of ICMPv6 packets related to # existing traffic for icmpv6_type in $ACCEPT_ICMPV6_TYPE do $ip6tables -A icmpv6-state -p icmpv6 --icmpv6-type $icmpv6_type -j ACCEPT done # Deny anything else as established,related ICMPv6 packet $ip6tables -A icmpv6-state -j drop # # Forwarded traffic between the Internet and the inner side # # Allow reply packets and packets related to existing connections $ip6tables -A FORWARD -p icmpv6 -m state --state ESTABLISHED,RELATED \ -j icmpv6-state $ip6tables -A FORWARD -p ! icmpv6 -m state --state ESTABLISHED,RELATED \ -j ACCEPT # Drop INVALID packets, so NEW packets remain only $ip6tables -A FORWARD -m state --state INVALID -j drop # Allow outbound requests from prefixes which belong to the site for inner_prefix in $INNER_PREFIXES do $ip6tables -A FORWARD -s $inner_prefix -j accept done # Split incoming requests into protocol-dependent sub-chains # Allow inbound protocol requests towards only the predetermined hosts for service in $SERVICES do proto=`echo $service | tr [A-Z] [a-z]` $ip6tables -N $proto case $proto in domain) $ip6tables -A FORWARD -p tcp --dport domain -j domain $ip6tables -A FORWARD -p udp --dport domain -j domain ;; ping) $ip6tables -A FORWARD -p icmpv6 --icmpv6-type echo-request -j $proto ;; *) $ip6tables -A FORWARD -p tcp --dport $proto -j $proto ;; esac eval hosts="\$SERVICE_$service" for host in $hosts do $ip6tables -A $proto -d $host -j accept done done # If there are mobile ipv6 home agents present on the # trusted side allow if [ "$HOME_AGENTS_PRESENT" -eq "1" ] then for inner_prefix in $INNER_PREFIXES do # 144: incoming Home Agent address discovery request # 145: outgoing Home Agent address discovery reply # 146: incoming Mobile prefix solicitation # 147: outgoing Mobile prefix advertisement for type in 144 146 do $ip6tables -A FORWARD -p icmpv6 --icmpv6-type $type \ -d $inner_prefix -j ACCEPT done for type in 145 147 do $ip6tables -A FORWARD -p icmpv6 --icmpv6-type $type \ -s $inner_prefix -j ACCEPT done done fi # If there are roaming mobile nodes present on the # trusted side allow if [ "$MOBILE_NODES_PRESENT" -eq "1" ] then for inner_prefix in $INNER_PREFIXES do # 144: incoming Home Agent address discovery request # 145: outgoing Home Agent address discovery reply # 146: incoming Mobile prefix solicitation # 147: outgoing Mobile prefix advertisement for type in 144 146 do $ip6tables -A FORWARD -p icmpv6 --icmpv6-type $type \ -s $inner_prefix -j ACCEPT done for type in 145 147 do $ip6tables -A FORWARD -p icmpv6 --icmpv6-type $type \ -d $inner_prefix -j ACCEPT done done fi # DROP EVERYTHING ELSE $ip6tables -A FORWARD -j drop # # Traffic to and from the firewall itself # # Allow outbound traffic $ip6tables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT $ip6tables -A OUTPUT -m state --state NEW -j accept $ip6tables -A OUTPUT -j drop # Basic loopback and localhost communication $ip6tables -A INPUT -i lo -j ACCEPT $ip6tables -A INPUT -s ::1 -j ACCEPT $ip6tables -A INPUT -d ::1 -j ACCEPT # Neighbour discovery: # DAD $ip6tables -A INPUT -p icmpv6 -d ff02::/16 -j ACCEPT # RS, RA, NS, NA, redirect... $ip6tables -A INPUT -p icmpv6 -s fe80::/10 -d fe80::/10 -j ACCEPT # Allow any link-local multicast traffic $ip6tables -A INPUT -s fe80::/10 -d ff02::/16 -j ACCEPT for prefix in $INNER_PREFIXES $OUTER_PREFIXES do $ip6tables -A INPUT -s $prefix -d ff02::/16 -j ACCEPT done # Allow reply packets and packets related to existing connections $ip6tables -A INPUT -p icmpv6 -m state --state ESTABLISHED,RELATED \ -j icmpv6-state $ip6tables -A INPUT -p ! icmpv6 -m state --state ESTABLISHED,RELATED \ -j ACCEPT # Drop INVALID packets, so NEW packets remain only $ip6tables -A INPUT -m state --state INVALID -j drop # Allow inbound protocol requests from the predetermined hosts only for service in $LOCAL_SERVICES do proto=`echo $service | tr [A-Z] [a-z]` case $proto in ping) eval hosts="\$SERVICE_$service" for host in $hosts do $ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request \ -s $host -j accept done ;; *) eval hosts="\$SERVICE_$service" for host in $hosts do $ip6tables -A INPUT -p tcp --dport $proto \ -s $host -j accept done ;; esac done # DROP EVERYTHING ELSE $ip6tables -A INPUT -j drop