Linux Home
Automation IPv6

(Last updated: Sun., Feb. 07, 2010)
Google
 

IPv6 Firewall/Router

As part of my Home networking with IPv6 I knew I would need a Firewall for my WGT634u router running OpenWRT Kamikaze. That protection would be provided by iptables (ip6tables to be exact). While I am posting notes of various information on IPv6 here it's really about IPv6 and IPv4. You can't have a good firewall if you don't consider both protocols at the same time.


Notes:

As always, these are my notes and you'll find them in various states of disarray. That's because as I update them I don't always go back and fix other sections. Sometimes I leave contradictions in place until I figure them out. If you come across anything that doesn't make sense just send an email and I'll try to clear it up or remove it.

Firewalls

There are 3 basic types of firewall setup. Some of the fancier setups combine the some form of the three to make it look like a much more complex setup.

Host

The host has a single network interface, and the firewall's purpose is to protect that host from the outside world. The principle distinction here is "this host" versus "everything else." One example is a home computer connected to a cable modem.

This is a common type of firewall. Many Windows system now enable this to help protect then from incoming and outgoing connections. For Unix systems this started out as tcp-wrappers which allowed for a form of access control list for daemons. Today's firewalls provide for all sorts of control of the packets (hmm an awkward statement). An example of this a host directly connected to a cable modem (no router/firewall device). It is still a good idea to have the hosts protected by their own individual firewall.

Multi-host

The host has multiple network interfaces connected to different networks, but is not acting as a router. In other words, it has an address on each of its connected networks, but it does not forward traffic across itself, nor interconnect those networks for other hosts. Such a host is called multi-homed and may be directly connected to various networks. In this case, firewall rules must distinguish among the different interfaces, addresses, and networks to which the host/router is attached, perhaps implementing different security policies on different networks. For example, the host might be connected to the Internet on one side, and a trusted private network on the other.

Router

The host has multiple network interfaces and is configured as a router. That is, the kernel's " IP forwarding" flag is on, and the host will forward packets between its connected networks as directed by its routing table. In this case, firewall rules not only must control what traffic may reach the host, but also might restrict what traffic can cross the host (as router), bound for other hosts.

Using the Right Chain

See the packet, be the packet. ;-) Often the difficulty with iptables is knowing when to use which chain when filtering. Here’s some simple rules of thumb:

  1. INPUT, if the packet is coming directly to the machine running the firewall.
  2. OUTPUT, if the packet is being generated by the machine running the firewall, OUTPUT.
  3. FORWARD, If the packet is simply passing through from one machine onto another , FORWARD.
  4. POSTROUTING, if the packet needs to been seen as a coming from a different IP address (used with NAT)
  5. PREROUTING, if the packet needs to go to a different address (used with NAT).

Currently (02/2010) there is no NAT for IPv6. There is work on having NAT with IPv6 but I'm not sure I really want it. The main arguement for NAT originally was the lack of avaialble IP addressing. I understand that NAT allows a form of blocking but with modern viruses/trojans now working from the inside (private address space) out, the availability of IPv6 addresses and the fact that a properly setup firewall will do the same thing, I really don't see a huge need for IPv6 NAT.

Prerequisites

I'll start listing the prerequisites needed for IPv6 to be added to the Netgear WGT634u. A normal Linux install on a x86 machine should have similar requirements but may not be exact:

  • 6scripts - 0.1-1 -
  • curl - 7.17.1-1.2 -
  • ip6tables - 1.4.0-1 -
  • ip6tables-utils - 1.4.0-1 -
  • iptables-utils - 1.4.0-1 -
  • iputils-ping6 - 20071127-1 -
  • ipv6calc - 0.71.0 -
  • kmod-ip6tables - 2.6.25.20-brcm47xx-1 -
  • kmod-iptunnel4 - 2.6.25.20-brcm47xx-1 -
  • kmod-ipv6 - 2.6.25.20-brcm47xx-1 -
  • kmod-sit - 2.6.25.20-brcm47xx-1 -
  • libcurl - 7.17.1-1.2 -
  • ndisc6 - 0.5.1-1 -
  • radvd - 1.2-1.1 -

IPv4 Table Names


root@OpenWrt:/# cat /proc/net/ip_tables_names 
nat
mangle
filter

root@OpenWrt:/# cat /proc/net/ip_tables_targets  
MASQUERADE
DNAT
SNAT
REJECT
TCPMSS
LOG
ERROR

IPv6 Table Names


root@OpenWrt:/# cat /proc/net/ip6_tables_names 
raw
mangle
filter
root@OpenWrt:/# cat /proc/net/ip6_tables_targets 
REJECT
LOG
IMQ
ERROR
TCPMSS

Firewall scripts

Below are some scripts I've found, I haven't tested them yet so don't trust them as they are. I need to investigate them further and make sure they are what I need and want. For now they just stand as an example of what is available. Some may be for individual hosts, some for hosts that terminate tunnels, I'm looking for a router which terminates a tunnel and then route the IPv6 (and IPv4) traffic accordingly. Eventually I want to setup DHCP or RADVD to properly dish out the correct IPv6 address suffix for the host with the learned IPv6 prefix. This should also work in conjustion with the local DNS which will allow local users access to the local resources without learning the awkward IPv6 addresses. Let's face it www6.example.org is a lot easier to remember than 2001:db8::192.168.1.1 (yes that's a mix IPv6 and IPv4 address).

Ip6tables script


#!/bin/sh

# Before we start, we'll set some variables to make the rules more
# clear later.

# Comma seperated list of blocked tcp ports. These can be anything,
# but we're using the ports VNC and X Windows use since these services 
# can be tunneled over SSH.
blocked_tcp_ports=5900:5910,6000:6063

# A UDP port to block.
blocked_udp_ports=5353

# Flush chains

ip6tables -F INPUT
ip6tables -F FORWARD
ip6tables -F OUTPUT
ip6tables -F

# Set up default policies

ip6tables -P INPUT   DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT  DROP

# Allow localhost traffic. This rule is for all protocols.

ip6tables -A INPUT -s ::1 -d ::1 -j ACCEPT

# Allow some ICMPv6 types in the INPUT chain
# Using ICMPv6 type names to be clear.

ip6tables -A INPUT -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type parameter-problem -j ACCEPT

# Allow some other types in the INPUT chain, but rate limit.
ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -m limit --limit 600/min -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-reply -m limit --limit 600/min -j ACCEPT

# Allow others ICMPv6 types but only if the hop limit field is 255.

ip6tables -A INPUT -p icmpv6 --icmpv6-type router-advertisement   -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-solicitation  -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type redirect               -m hl --hl-eq 255 -j ACCEPT

# When there isn't a match, the default policy (DROP) will be applied.
# To be sure, drop all other ICMPv6 types.
# We're dropping enough icmpv6 types to break RFC compliance.

ip6tables -A INPUT -p icmpv6 -j LOG --log-prefix "dropped ICMPv6"
ip6tables -A INPUT -p icmpv6 -j DROP


# Allow ICMPv6 types that should be sent through the Internet.

ip6tables -A OUTPUT -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type packet-too-big          -j ACCEPT
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type time-exceeded           -j ACCEPT
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type parameter-problem       -j ACCEPT


# Limit most NDP messages to the local network.

ip6tables -A OUTPUT -p icmpv6 --icmpv6-type neighbour-solicitation  -m hl --hl-eq 255 -j ACCEPT
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type neighbour-advertisement -m hl --hl-eq 255 -j ACCEPT
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type router-solicitation     -m hl --hl-eq 255 -j ACCEPT


# If we're acting like a router, this could be a sign of problems.

ip6tables -A OUTPUT -p icmpv6 --icmpv6-type router-advertisement -j LOG --log-prefix "ra ICMPv6 type"
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type redirect             -j LOG --log-prefix "redirect ICMPv6 type"
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type router-advertisement -j REJECT
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type redirect             -j REJECT


# Accept all other ICMPv6 types in the OUTPUT chain.

ip6tables -A OUTPUT -p icmpv6 -j ACCEPT


# Reject in the FORWARD chain. This rule is probably not needed 
# due to the FORWARD policy.

ip6tables -A FORWARD -p icmpv6 -j REJECT

# Enough ICMPv6!   :-D 
# Some sample TCP rules. <These are for example purposes only.>
# The REJECT is for politeness on the local network.

ip6tables -A INPUT  -m multiport -p tcp --dport $blocked_tcp_ports -m hl --hl-eq 255 -j REJECT
ip6tables -A OUTPUT -m multiport -p tcp --dport $blocked_tcp_ports -m hl --hl-eq 255 -j REJECT
ip6tables -A INPUT  -m multiport -p tcp --dport $blocked_tcp_ports -m hl --hl-lt 255 -j DROP
ip6tables -A OUTPUT -m multiport -p tcp --dport $blocked_tcp_ports -m hl --hl-lt 255 -j DROP


# This rule will block the port mdns uses. Its commented out.
# For mobile systems, the rule can
# be added to a script in
# /etc/Networkmanager/dispatcher/
# to gain location-aware rules 
# by querying iwconfig, ifconfig, ip route2, date, etc. An example
# script is below. It would need to be placed in
# /etc/Networkmanager/dispatcher/ to function.

#!/bin/bash
#network=$(iwconfig wlan0 | grep SSID)
#
#if [ "$network" = "wlan0 IEEE 802.11abg ESSID:"SSID"" ]; then
#iptables -A INPUT -p udp $blocked_udp_ports -j ACCEPT
#
#else
#ip6tables -A OUTPUT -p udp --dport $blocked_udp_ports -j REJECT
#
#fi


# Stateful matching to allow requested traffic in.

ip6tables -A OUTPUT -p tcp -j ACCEPT
ip6tables -A OUTPUT -p udp -j ACCEPT
ip6tables -A INPUT  -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A INPUT  -p udp -m state --state ESTABLISHED,RELATED -j ACCEPT


# Drop NEW,INVALID probably not needed due to the default drop policy.

ip6tables -A INPUT -m state --state NEW,INVALID -j DROP


# REJECT everything in the FORWARD chain.

ip6tables -A FORWARD -p tcp -j REJECT
ip6tables -A FORWARD -p udp -j REJECT

Other

Another script


#!/bin/bash

# A bash shell script for ip6tables to protect single hosting / 
# dedicated / vps / colo server running CentOS / Debian / RHEL / or any
# other Linux distribution.

# -------------------------------------------------------------------------
# Copyright (c) 2007 nixCraft project <http://www.cyberciti.biz/fb/>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# ----------------------------------------------------------------------
# Last updated on Jan-23, 2008 : Added support for tcp packets
# ---------------------------------------------------------------------------
IPT6="/sbin/ip6tables"
 
# Interfaces
PUB_IF="eth1"
PUB_LO="lo0"
PUB_VPN="eth0"
 
# Custom chain names
CHAINS="chk_tcp6_packets_chain chk_tcp_inbound chk_udp_inbound chk_icmp_packets"
HTTP_SERVER_6="2001:470:1f04:55a::2 2001:470:1f04:55a::3 2001:470:1f04:55a::4 2001:470:1f04:55a::5"
 
echo "Starting IPv6 firewall..."
# first clean old mess
$IPT6 -F
$IPT6 -X
$IPT6 -Z
for table in $(</proc/net/ip6_tables_names)
do
	$IPT6 -t $table -F
	$IPT6 -t $table -X
	$IPT6 -t $table -Z
done
$IPT6 -P INPUT ACCEPT
$IPT6 -P OUTPUT ACCEPT
$IPT6 -P FORWARD ACCEPT
 
# Set default DROP all
$IPT6 -P INPUT DROP
$IPT6 -P OUTPUT DROP
$IPT6 -P FORWARD DROP
 
# Create the chain
for c in $CHAINS
  do $IPT6 --new-chain $c
done
 
# Input policy
$IPT6 -A INPUT -i $PUB_LO  -j ACCEPT
$IPT6 -A INPUT -i $PUB_VPN -j ACCEPT
$IPT6 -A INPUT -i $PUB_IF  -j chk_tcp6_packets_chain
$IPT6 -A INPUT -i $PUB_IF  -m state --state RELATED,ESTABLISHED -j ACCEPT
$IPT6 -A INPUT -i $PUB_IF  -p tcp -j chk_tcp_inbound
$IPT6 -A INPUT -i $PUB_IF  -p udp -j chk_udp_inbound
$IPT6 -A INPUT -i $PUB_IF  -p icmp -j chk_icmp_packets
$IPT6 -A INPUT -i $PUB_IF  -p ipv6-icmp -j chk_icmp_packets
$IPT6 -A INPUT -i $PUB_IF  -m limit --limit 3/min --limit-burst 3 -j LOG --log-prefix "INPUT OUTPUT "
$IPT6 -A INPUT -i $PUB_IF  -j DROP
 
# Output policy
$IPT6 -A OUTPUT -o $PUB_LO  -j ACCEPT
$IPT6 -A OUTPUT -o $PUB_VPN -j ACCEPT
$IPT6 -A OUTPUT -o $PUB_IF  -j ACCEPT
$IPT6 -A OUTPUT -o $PUB_IF  -m limit --limit 3/min --limit-burst 3 -j LOG --log-prefix "DROP OUTPUT "
 
### Custom chains ###
# Bad packets chk
$IPT6 -A chk_tcp6_packets_chain -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -m limit --limit 3/min --limit-burst 3 -j LOG --log-prefix "Bad tcp packets"

$IPT6 -A chk_tcp6_packets_chain -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP

$IPT6 -A chk_tcp6_packets_chain -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -m limit --limit 3/min --limit-burst 3 -j LOG --log-prefix "Bad tcp packets"

$IPT6 -A chk_tcp6_packets_chain -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP

$IPT6 -A chk_tcp6_packets_chain -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,PSH,URG -m limit --limit 3/min --limit-burst 3 -j LOG --log-prefix "BAD tcp"

$IPT6 -A chk_tcp6_packets_chain -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,PSH,URG -j DROP

$IPT6 -A chk_tcp6_packets_chain -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,ACK,URG -m limit --limit 3/min --limit-burst 3 -j LOG --log-prefix "Bad tcp"

$IPT6 -A chk_tcp6_packets_chain -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,ACK,URG -j DROP

$IPT6 -A chk_tcp6_packets_chain -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -m limit --limit 3/min --limit-burst 3 -j LOG --log-prefix "Bad tcp "

$IPT6 -A chk_tcp6_packets_chain -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP

$IPT6 -A chk_tcp6_packets_chain -p tcp -m tcp --tcp-flags FIN,SYN FIN,SYN -m limit --limit 3/min --limit-burst 3 -j LOG --log-prefix "Bad tcp "

$IPT6 -A chk_tcp6_packets_chain -p tcp -m tcp --tcp-flags FIN,SYN FIN,SYN -j DROP

$IPT6 -A chk_tcp6_packets_chain -p tcp -j RETURN 
 
# Open TCP Ports
# Open http port
for h in $HTTP_SERVER_6
do
   $IPT6 -A chk_tcp_inbound -p tcp -m tcp --dport 80 -d $h -j ACCEPT
done
 
# Open 53 port
$IPT6 -A chk_tcp_inbound -p tcp -m tcp --dport 53 -j ACCEPT
###############################
# Add your rules below to open other TCP ports
# Open smtp
# $IPT6 -A chk_tcp_inbound -p tcp -m tcp --dport 25 -j ACCEPT
# Open pop3
# $IPT6 -A chk_tcp_inbound -p tcp -m tcp --dport 113 -j ACCEPT
# Open ssh
# $IPT6 -A chk_tcp_inbound -p tcp -m tcp --dport 22 -j ACCEPT
###############################
# do not modify following rule
$IPT6 -A chk_tcp_inbound -p tcp -j RETURN 
 
# Open UDP Ports
# Open dns 53 udp
$IPT6 -A chk_udp_inbound -p udp -m udp --dport 53 -j ACCEPT
###############################
# Add your rules below to open other UDP ports
#
###############################
# do not modify following rule
$IPT6 -A chk_udp_inbound -p udp -j RETURN 
 
# ICMP - allow ping pong
$IPT6 -A chk_icmp_packets -p ipv6-icmp -j ACCEPT
$IPT6 -A chk_icmp_packets -p icmp -j RETURN