Linux Home
Automation IPv6

(Last updated: Sun., Feb. 27, 2011)
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. But in order to explain the complicated details I will usually skip mentioning IPv4.


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.

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:

Package Version Description
6scripts0.1-1IPv6 scripts to setup ipv6 connectivy using 6to4 tunnels
curl7.17.1-1.2A client-side URL transfer library
ip6tables1.4.0-1IPv6 firewall administration tool
ip6tables-utils1.4.0-1ip6tables save and restore utilities
iptables-utils1.4.0-1iptables save and restore utilities
iputils-ping620071127-1Program ping6 from iputils.
ipv6calc0.71.0ipv6calc is a small utility written in programming languate C to manipulate (not only) IPv6 addresses.
kmod-ip6tables2.6.25.20-brcm47xx-1Netfilter IPv6 firewalling support
kmod-iptunnel42.6.25.20-brcm47xx-1Kernel modules for IPv4 tunneling
kmod-ipv62.6.25.20-brcm47xx-1Kernel modules for IPv6 support
kmod-sit2.6.25.20-brcm47xx-1Kernel modules for IPv6-in-IPv4 tunnelling
libcurl7.17.1-1.2A client-side URL transfer utility
ndisc60.5.1-1An ICMPv6 neighbour discovery tools
radvd1.2-1.1IPv6 Routing Advertisement Daemon.

What I currently have working

I'll have to spend a lot more time cleaning up this page but for now I'll add what I've done here and clean up later (yes, this is typical of my notes).

As I've noted (and blogged about) I was having some trouble understanding how the new IPv6 protocol suite was going to fit into my existing home IPv4 network. Over the last 4 years (yes I started these notes in 2007!) I've wondered and poke about trying to understand IPv6 and how it works. There were all sorts of wonderous things that were said (instantly change providers and you won't have to renumber your network - well not quite) and a real lack of experience. I've had a whole lot of fun reading RFCs only to find that they were deprecated (Oh Joy!). Well I think I finally have my head around a simple configuration for the home.

My current setup consists of Comcast as my ISP, A Netgear WGT634U running OpenWRT Kamikaze 8.09.1 (with the WiFi card pulled), several Linux and Windows XP computers with IPv6 enabled and Hurricane Electric as my tunnel provider.

The Netgear firewall is currently handling just the NAT (for IPv4), routing and firewall duties (though I intend to configure dnsmasq as a backup local DNS server too). The Wireless Access Point duties are being taken care of by a WRT54GL in bridge mode.

A diagram of my Dual Stack network

A simplified picture of my IPv6/IPv4 (Dual Stack) home network.

Above you see a simplified picture of my home network. This will make it easier to describe how I've setup the network for IPv6. One thing to keep in the back of your mind is that the existing IPv4 network is also working and that none of these changes have affected the IPv4 traffic. I've not shown any IPv4 on the diagram as it adds nothing to the explaination and only clusters the diagram.

Details

I found the appropriate configuration for building IPv6-inIPv4 tunnels to Hurricane Electric but I was having trouble with the Firewall and getting RADVD properly configured. As is the norm for any search of the internet I found loads of partial information but nothing really concrete. Many times I found information that pertained to a special distribution of Linux (such as Tomato, DD-WRT and OpenWRT). This only made things worse I tried to translate the commands into what I was running in OpenWRT.

Getting IPv6 to the real world

Running IPv6 is fine within the confines of your network but it's not really adding much. For now, you can pretty much do everything you need with IPv4. To really start to take advantage of IPv6 you need to get to the IPv6 resources out on the Internet. To connect to those resources you need to have IPv6 between you and those resources. There are a number of ways to do this, one is to have an ISP that already supports IPv6 (as of 2010/07/21 I know of none). Comcast is trialing various IPv6 methods but none are available to the general public. Another method is to tunnel the IPv6 across the existing IPv4 network.

So what I did was the last choice. I tunneled IPv6 in IPv4. I checked out various tunneling services (they each have their own pluses and minuses) and selected Hurricane Electric. I found a number of solutions on their forums for getting the tunnel up and running. It wasn't hard once I figured out which one was right for me. I then went about attempting to build the firewall rules. I've come up with a simple version that mostly works I'm having trouble with ICMPv6. I will resolve this and update the rules at a later date. Remember you don't want to block all IPv6 ICMPs. There are many types and some are extrememly important. Visit this link: IPv6 ICMPs to find out why are so important. So, then I went to work on RADVD, the Linux Route ADVertisement Daemon. This seemed to be easier to setup than using DHCPv6, only time will tell. One thing that did give me fits was getting the IPv6 default route to propagate. Most How-To's explained the simpliest of radvd.cfg files but lacked the addition of the route statement. Once I grasped the concept I configured RADVD and everything began to work. I've determined that I don't need RADVD running on every Linux computer but only on the firewall. I let the Neighbor Discovery Protocol (NDP) do all the work on the rest of the computers. This is acceptable for now but I'll probably need to migrate the DHCPv6 at a later date and tie that in with my local DNS (yes, I need a local DNS - I'm not about to memorize these IPV6 addresses). I am still a little puzzled by my browser's behavior as it will peacefully go to http://[2001:200:dff:fff1:216:3eff:feb1:44d7]/ (Kame.net's IPv6 address - note the use of the square brackets around the IPv6 address) using IPv6 but not http://www.kame.net/ which instead uses IPv4 (note the lack of the dancing kame). I'll have to check to see if I turned off the browsers IPv6 usage.

My current and working configs for my OpenWRT router

I have my IPv6 tunnel to Hurricane Electric up and running. Here's what I did:

Sign up with a tunnel provider

For those of us not fortunate enough to get IPv6 directly from our ISPs there are Tunnel Brokers (IPv6-in-IPv4 tunneling). I chose Hurrican Electric because they fit my needs and so far I've found them to work very well. To signup just go to TunnelBroker.net (yes, their Hurricane Electric), register, follow the directions and remember to save the information from a page that looks like this (it's the link under Tunnels, at the bottom center. on the main page after you've logged on):

Tunnel Details
Account: UserName
BLAH Global Tunnel ID: 12345 Local Tunnel ID: 9876
Description:
Registration Date: Mon, Jan 5, 1970
Tunnel Endpoints
Server IPv4 address: 198.51.100.6
Server IPv6 address: 2001:db8:1001::1/64
Client IPv4 address: 192.0.2.67
Client IPv6 address: 2001:db8:1001::2/64
Available DNS Resolvers
Anycasted IPv6 Caching Nameserver:2001:db8:20::2
Anycasted IPv4 Caching Nameserver:203.0.113.42
Routed IPv6 Prefixes and rDNS Delegations
Routed /48: 2001:db8:1002::/48
Routed /64: 2001:db8:4321:567::/64
RDNS Delegation NS1: none
RDNS Delegation NS2: none
RDNS Delegation NS3: none
Example OS Configurations (Windows, Linux, etc.):


Copy and Paste the following into a command window:
modprobe ipv6
ip tunnel add he-ipv6 mode sit remote 172.32.101.34 local 10.21.43.65 ttl 255
ip link set he-ipv6 up
ip addr add 2001:db8:1001::2/64 dev he-ipv6
ip route add ::/0 dev he-ipv6
ip -f inet6 addr

*NOTE* When behind a firewall appliance that passes protocol41, instead of using the IPv4 endpoint you provided to our broker, use the IPv4 address you get from your appliance's DHCP service.

The configurations provided are only example configurations and may be different depending on the version OS or tools you are using. If you have any issues getting your tunnel to work please contact us at ipv6@he.net and we will be happy to assist you.

Note: the addresses used above are not mine and are just for reference (they're the documentation reserved addresses). You need to change the addresses used above and below to match your addressing. (As of July 2010, the information above and below is very inconsistent. I'll work on and correct that so it's much easier to follow and understand).

Also note the 2001:db8:1001:: (IPv6 Tunnel Endpoints) and 2001:db8:1002:: (Routed /64) addresses from the tunnel details page. The Routed/64 address goes on you LAN and is different from the tunnel address. This seems to cause problems for more than a few users. Probably because you're new to IPv6 addresses and the address format is quite long.

Allowing Type 41 Packets

Before we can do anything with IPv6 tunnels (IPv6-in-IPv4) we need to tell iptables to allow those packets.

Add a new rule to your firewall to ACCEPT protocol 41 from wan to the device. Use luci or do it on the cli like this:

Code:

uci add firewall rule
uci set firewall.@rule[-1].src=wan
uci set firewall.@rule[-1].target=ACCEPT
uci set firewall.@rule[-1]._name=HE-IP6
uci set firewall.@rule[-1].proto=41
uci commit firewall

I cut and paste these 6 commands into the shell and I was done. The results of these commands are stored in /etc/config/firewall

 # ...
config 'rule'
        option 'src' 'wan'
        option 'target' 'ACCEPT'
        option '_name' 'HE-IP6'
        option 'proto' '41'
# ...

This code is just a portion of the entire file. Other rules and firewall configuration information can be found in this file. So if you must edit this file do so carefully. Examing the firewall config file further shows a reference to /etc/firewall.user. It should be possible to add the HE-IP6 rule to that file along with the rest of my IPv6 related firewall rules. I'll look into that in the future.

Building the Tunnel

Building the tunnel to Hurricane Electric

Here's the manual start script:

Code:
. /etc/functions.sh

IPT6=/usr/sbin/ip6tables
PUBIF=he-ipv6
DEVICE=eth0.1 # WAN

# setup tunnel
logger "HE-IPv6: starting tunnel..." 

# get your ISP provided IP address
IPADDR=$(ip -4 addr show dev $DEVICE | awk '/inet / {print $2}' | cut -d/ -f1)
username="1234abcd1234abcd1234abcd1234abcd" # userid (not your login name) from main page after tunnelborker.net logon
# Remember that the echo -n is important, echo without -n will give you the wrong value
password="5678efgh5678efgh5678efgh5678efgh" # MD5 of your password $(echo -n password | md5sum | cut -f 1 -d \ )
tunnelid="12345" # global tunnel-ID, not your local tunnel-ID

wget -q -O /dev/tty "http://ipv4.tunnelbroker.net/ipv4_end.php?ipv4b=$IPADDR&pass=$password&user_id=$username&tunnel_id=$tunnelid"

SERVER_IPv4_ENDPOINT=192.51.100.6  # change this IP, this is the Frankfurt POP
CLIENT_IPv6_ENDPOINT=2001:db8:1001::2/64 # change this, too

# setup tunnel
ip tunnel add he-ipv6 mode sit remote $SERVER_IPv4_ENDPOINT local $IPADDR ttl 255
ip link set he-ipv6 up
ip addr add $CLIENT_IPv6_ENDPOINT dev he-ipv6
ip route add ::/0 dev he-ipv6

Now that you've brought up the tunnel you should see something similar to the following when you do a ip -6 addr:

root@OpenWGT:~# ip -6 addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 fe80::209:5bff:fed1:1f01/64 scope link 
       valid_lft forever preferred_lft forever
3: eth0.0@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 
    inet6 fe80::209:5bff:fed1:1f01/64 scope link 
       valid_lft forever preferred_lft forever
5: br-lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 
    inet6 fe80::e49b:fdff:fe29:b807/64 scope link 
       valid_lft forever preferred_lft forever
7: he-ipv6@NONE: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1480 
    inet6 2001:db8:1001::2/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::4454:2057/128 scope link 
       valid_lft forever preferred_lft forever

And when you do a ip -6 route you should see something like this:

root@OpenWGT:~# ip -6 route
2001:db8:1001::/64 via :: dev he-ipv6  metric 256  expires 20305606sec mtu 1480 advmss 1420 hoplimit 4294967295
fe80::/64 dev eth0  metric 256  expires 20305586sec mtu 1500 advmss 1440 hoplimit 4294967295
fe80::/64 dev eth0.0  metric 256  expires 20305588sec mtu 1500 advmss 1440 hoplimit 4294967295
fe80::/64 dev br-lan  metric 256  expires 20305588sec mtu 1500 advmss 1440 hoplimit 4294967295
fe80::/64 dev eth0.1  metric 256  expires 20305590sec mtu 1500 advmss 1440 hoplimit 4294967295
fe80::/64 via :: dev he-ipv6  metric 256  expires 20305606sec mtu 1480 advmss 1420 hoplimit 4294967295
default dev he-ipv6  metric 1024  expires 20305606sec mtu 1480 advmss 1420 hoplimit 4294967295

You should now be able to ping the remote end of your tunnel, like this:

root@OpenWGT:~# ping6 -c 3 2001:db8:1001::1 
PING 2001:db8:1001::1 (2001:db8:1001::1): 56 data bytes
64 bytes from 2001:db8:1001::1: seq=0 ttl=64 time=18.491 ms
64 bytes from 2001:db8:1001::1: seq=1 ttl=64 time=17.315 ms
64 bytes from 2001:db8:1001::1: seq=2 ttl=64 time=17.063 ms

--- 2001:db8:1001::1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 17.063/17.623/18.491 ms
root@OpenWGT:~# ip -6 addr  del fe80::209:5bff:fed1:1f01/64 dev eth0.1

Here's the manual stop script:

Code:
#!/bin/bash

IPV4Client=$(ip -4 addr show dev $DEVICE | awk '/inet / {print $2}' | cut -d/ -f1) # ISP provided IPv4
IPV4Server="192.51.100.6"  # Hurricane Electric end of the tunnel
IPV6Client="2001:db8:1001::2/64" # Your end of the tunnel


# To take this down:
ip route del ::/0 dev he-ipv6
ip addr del ${IPV6Client} dev he-ipv6
ip link set he-ipv6 down
ip tunnel del he-ipv6 mode sit remote ${IPV4Server} local ${IPV4Client} ttl 255

IPv6 LAN address

Now add the the LAN IPv6 address to you LAN. If you have a routed /64 prefix then just use that prefix. If you have a routed /48 then selecton one of the networks from there. If you don't know how to do that then don't get a routed /48 prefix at this time. (I'll add a proper explaination for selecting your hard coded addresses at some later date. Using the first host may not be a good idea and there are some rules).

uci set network.lan.ip6addr=2001:db8:1002::1/64
uci commit
root@OpenWGT:~# ip -6 addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 fe80::209:5bff:fed1:1f01/64 scope link 
       valid_lft forever preferred_lft forever
3: eth0.0@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 
    inet6 fe80::209:5bff:fed1:1f01/64 scope link 
       valid_lft forever preferred_lft forever
5: br-lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 
    inet6 2001:db8:1002:::1/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::e49b:fdff:fe29:b807/64 scope link 
       valid_lft forever preferred_lft forever
7: he-ipv6@NONE: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1480 
    inet6 2001:db8:1001::2/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::4454:2057/128 scope link 
       valid_lft forever preferred_lft forever

And when you do a ip -6 route you should see something like this:

root@OpenWGT:~# ip -6 route
2001:db8:1001::/64 via :: dev he-ipv6  metric 256  expires 20305606sec mtu 1480 advmss 1420 hoplimit 4294967295
2001:db8:1002::/64 dev br-lan  metric 256  expires 20305594sec mtu 1500 advmss 1440 hoplimit 4294967295
fe80::/64 dev eth0  metric 256  expires 20305586sec mtu 1500 advmss 1440 hoplimit 4294967295
fe80::/64 dev eth0.0  metric 256  expires 20305588sec mtu 1500 advmss 1440 hoplimit 4294967295
fe80::/64 dev br-lan  metric 256  expires 20305588sec mtu 1500 advmss 1440 hoplimit 4294967295
fe80::/64 dev eth0.1  metric 256  expires 20305590sec mtu 1500 advmss 1440 hoplimit 4294967295
fe80::/64 via :: dev he-ipv6  metric 256  expires 20305606sec mtu 1480 advmss 1420 hoplimit 4294967295
default dev he-ipv6  metric 1024  expires 20305606sec mtu 1480 advmss 1420 hoplimit 4294967295

IPv6 addressing/Routing - RADVD

After building the tunnel and making sure it was pingable I statically added the appropriate IPv6 address to the firewall's LAN interface. This address (a /64 prefix) is from the pool Hurricane Electric provided (see the simulated page above). I gave it an easy to remember address so I would remember it and so I could add static routes to equipment that had trouble with RA or anything else. The rest of my devices on my network learn their prefix from the RA. This makes it easy to configure your home network. It really isn't that different from IPv4 and DHCP.

RADVD config with default route:

interface br-lan
{
        AdvSendAdvert on;
        AdvManagedFlag off;
        AdvOtherConfigFlag off;

        prefix 2001:db8:1002::/64
        {
                AdvOnLink on;
                AdvAutonomous on;
                AdvRouterAddr off;
        };

	route ::/0
	{
	};
};

Firewall

Ip6tables

The IPv6 firewall rule: (not quite working, no icmpv6 support):

# Generated by ip6tables-save v1.4.0 on Mon Jul 12 13:24:13 2010
*raw
:PREROUTING ACCEPT [4385:2986826]
:OUTPUT ACCEPT [299:40480]
COMMIT
# Completed on Mon Jul 12 13:24:13 2010
# Generated by ip6tables-save v1.4.0 on Mon Jul 12 13:24:13 2010
*mangle
:PREROUTING ACCEPT [4385:2986826]
:INPUT ACCEPT [296:39536]
:FORWARD ACCEPT [4021:2942142]
:OUTPUT ACCEPT [299:40480]
:POSTROUTING ACCEPT [4550:3017390]
COMMIT
# Completed on Mon Jul 12 13:24:13 2010
# Generated by ip6tables-save v1.4.0 on Mon Jul 12 13:24:13 2010
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [1615:1046166]
:OUTPUT DROP [0:0]
-A INPUT -i lo -j ACCEPT 
-A INPUT -p ipv6-icmp -j ACCEPT 
-A INPUT -i he-ipv6 -m state --state RELATED,ESTABLISHED -j ACCEPT 
-A FORWARD -p ipv6-icmp -j ACCEPT 
-A OUTPUT -o lo -j ACCEPT 
-A OUTPUT -p ipv6-icmp -j ACCEPT 
-A OUTPUT -o he-ipv6 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT 
COMMIT
# Completed on Mon Jul 12 13:24:13 2010

My manual start script:

Code:
IPT6=/usr/sbin/ip6tables # njc
PUBIF=he-ipv6 # njc
#exit 0

# Default behaviour DROP all traffic
$IPT6 -P INPUT   ACCEPT
$IPT6 -P OUTPUT  ACCEPT
$IPT6 -P FORWARD ACCEPT

$IPT6 -F
$IPT6 -X
$IPT6 -t mangle -F
$IPT6 -t mangle -X

#unlimited access to loopback                                   
$IPT6 -A INPUT -i lo -j ACCEPT
$IPT6 -A OUTPUT -o lo -j ACCEPT

# Allow pings
#$IPT6 -A INPUT -i $PUBIF -p icmpv6 -m limit --limit 10/s -j ACCEPT
#$IPT6 -A OUTPUT -o $PUBIF -p icmpv6 -m limit --limit 10/s -j ACCEPT
#$IPT6 -A FORWARD -p icmpv6 -m limit --limit 10/s -j ACCEPT

# Allow pings
$IPT6 -A INPUT   -p icmpv6 -j ACCEPT
$IPT6 -A OUTPUT  -p icmpv6 -j ACCEPT
$IPT6 -A FORWARD -p icmpv6 -j ACCEPT

# Allow full outgoing connection but no incomming stuff
$IPT6 -A INPUT  -i $PUBIF -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT6 -A OUTPUT -o $PUBIF -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
                                                                                            
# Default behaviour DROP all traffic
$IPT6 -P INPUT DROP
$IPT6 -P OUTPUT DROP
#$IPT6 -P FORWARD DROP
                                                                                            
$IPT6 -v -L
                                                                                            
# more needs to be done here
# done

My manual stop script:

Code:
#!/bin/bash
IPT6="/usr/sbin/ip6tables"

$IPT6 -F
$IPT6 -X
$IPT6 -t mangle -F
$IPT6 -t mangle -X
 
# DROP all incomming traffic
$IPT6 -P INPUT ACCEPT
$IPT6 -P OUTPUT ACCEPT
$IPT6 -P FORWARD ACCEPT

IPv6 Forwarding

After all this lovely work you're ready to test everything and find something is not quite right. Well you need to have forwarindg turned on. From the command line you can do this:

Code:
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding

The following is included in the RADVD script:

Code:
sysctl -w net.ipv6.conf.all.forwarding=1 > /dev/null 2> /dev/null

It pretty much takes care of enabling the IPv6 forwarding so you won't need to use the manual commands.


The rest of my notes

Everything after this point is just reference material. I may incorporate itto the information above but I may also delete it. Some of it seems relavent some not. For now I need to clean up everything above so it is correct.

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

This 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 Unix and Windows systems 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 (hmmm, 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-homed

This host has multiple network interfaces connected to different networks, but is not acting as a router (packets coming in one interface and exiting another). 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. Often these hosts are servers. 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 are some simple rules of thumb:

  1. PREROUTING: Packets will enter this chain before a routing decision is made, used if the packet needs to go to a different address (used with NAT).
  2. INPUT: Packet is going to be locally delivered, if the packet is coming directly to the machine running the firewall.
  3. FORWARD: All packets that have been routed and were not for local delivery, used if the packet is simply passing through from one machine onto another.
  4. OUTPUT: Packets sent from the machine itself, used if the packet is being generated by the machine running the firewall.
  5. POSTROUTING: Routing decision has been made, used if the packet needs to been seen as a coming from a different IP 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. It may be necessary for some users of IPv6 to IPv4 traffic to communicate. The main arguement for NAT originally was the lack of avaialble IPv4 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.

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

My working rules

Here are the IPv6 rules that I'm currently running on my OpenWRT router (a Netgear WGT634U) with Kamazi 8.09.2.


# Generated by ip6tables-save v1.4.0 on Sat Jul 10 22:41:51 2010
*raw
:PREROUTING ACCEPT [2362:347780]
:OUTPUT ACCEPT [30:3432]
COMMIT
# Completed on Sat Jul 10 22:41:51 2010
# Generated by ip6tables-save v1.4.0 on Sat Jul 10 22:41:51 2010
*mangle
:PREROUTING ACCEPT [2362:347780]
:INPUT ACCEPT [27:2336]
:FORWARD ACCEPT [2333:345300]
:OUTPUT ACCEPT [30:3432]
:POSTROUTING ACCEPT [366:188972]
COMMIT
# Completed on Sat Jul 10 22:41:51 2010
# Generated by ip6tables-save v1.4.0 on Sat Jul 10 22:41:51 2010
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [30:3432]
:IPV6-INPUT - [0:0]
-A INPUT -j IPV6-INPUT 
-A FORWARD -j IPV6-INPUT 
-A IPV6-INPUT -i lo -j ACCEPT 
-A IPV6-INPUT -p ipv6-icmp -j ACCEPT 
-A IPV6-INPUT -p esp -j ACCEPT 
-A IPV6-INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT 
-A IPV6-INPUT -i br-lan -m state --state NEW -j ACCEPT 
-A IPV6-INPUT -j REJECT --reject-with icmp6-adm-prohibited 
COMMIT
# Completed on Sat Jul 10 22:41:51 2010

I'll work on getting the correct ip6tables syntax so that those who don't have save/restore utilities will be able to take advantage of the last configuration.

Links