The Gig of Ham

One geek's contributions to the series of tubes

May 31, 2011 - 29 minute read - Comments - ipv6 linux sysadmin

Building an IPv6 Firewall

As As will gladly tell you, we are rapidly running out of unique IP addresses on the Internet.  The good news is we solved this problem in 1998.  The bad news is that, after more than ten years, we still haven’t widely implemented the new standard: IPv6. All of the big carriers support it, but getting access to the IPv6 Internet is still very tough. If you are a Comcast customer it is possible to get IPv6 access, and there are a few others who allow access as well. For everyone else, you either have to wait or you can get a tunnel (again from HE through their awesome Tunnel Broker service).

Let me take a moment here and state that I really applaud HE’s leadership in the transition to IPv6. They run an excellent tunnel broker service for end users, they run a very large transit network, they share a lot of information, and they were not afraid to jump in the pool. Without their efforts I don’t think we would be as far along today as we are now, and I thank them deeply for their efforts to date.

Now, some may know the differences between IPv4 (the current Internet addressing scheme) and IPv6 (the new scheme), but some may not. There are a lot of excellent resources that go into much deeper detail than I will but here are the basics:

  • The space for IP addresses has changed from 32bits to 128bits – an immensely huge number of addresses.
  • There are NO private address spaces in IPv6 (unlike IPv4 which has several: 10.0.0.0/8 192.168.0.0/16 and 172.16.0.0/12).
  • While there is Network Address Translation (NAT) in IPv6, it is 1-to-1 – as opposed to the typical 1-to-many used by almost every consumer/business router product on the market.
  • Unlike current IPv4 addressing where end users typically get a single IP address with a consumer connection, you get an entire 64bit subnet on a consumer connection with IPv6.
  • Unlike the current IPv4 Internet where many people are on the same “private” subnets, everyone on the IPv6 Internet is uniquely addressable. This has the benefit of P2P and gaming systems not having to use so much “magic” in order for connectivity.

There are downsides to this: because everything is Internet addressable, the need of security in depth firewall solutions is much greater than it has been in the past. You can no longer depend on a big NAT firewall at the border of your network to protect you. The old, lazy M&M security model (hard outer shell, soft and chewy on the inside) is dead. This also brings up some interesting concerns for “consumer devices” (such as game consoles, and other black-box network appliances) on your network as they could now be more of an attack vector into your network than they were before.

With all this in mind I got a HE tunnel and wanted to build a firewall for my stuff at home.  Previously, I used a pfSense firewall on a Soekris NET4801 hardware platform. This was great, but pfSense does not support IPv6 on their General Availability release. Also the old NET4801 doesn’t have enough horsepower to handle my forthcoming FiOS high speed connection (the combination of the NICs and the processor can only handle about 9mbps, where as the FiOS package I want is 25mbps). I also have a game console (PS3) which needs UPnP IGD service on my router in order for on-line gaming to work. There are other firewall solutions which do support IPv6, but none supported IPv6 and UPnP. So, I started to build one myself.

I decided to build the firewall on a Jetway VIA C7 platform using FreeBSD. Why FreeBSD? The miniupnpd server is ported to it, and it includes the pf firewall. Also, FreeBSD is the basis for pfSense so I could re-use my old IPv4 pf rules. I could have used Linux, but I woud have to compile miniupnpd myself and I haven’t tested it on Linux.

Before making the firewall, I sat down and figured out what traffic I wanted my firewall to pass and what I wanted it to block for IPv6. Here are the goals I cam up with:

  • Anyone can ping anyone on either side of the firewall
  • Anyone inside the firewall can connect to anyone on the outside of the firewall
  • No TCP/UDP connections be made from outside the firewall to hosts inside the firewall by default (specific ports can be opened later)
  • Router Advertisements from outside the firewall will NOT be passed inside the firewall
  • Router Solicitations from inside the firewall will NOT be passed to outside the firewall
  • Neighbor Solicitations will not pass through the firewall

Obviously, more complicated that a traditional IPv4 firewall ruleset. So I started to build the rules in pf, and then ran into some problems because I forgot the rules of pf:

  1. LAST match wins
  2. The “quick” keyword means stop processing rules and use that one

With rules like that, there are two solutions for building your rulesets:

  1. First rules drop everything, then the subsequent rules allow traffic (with some short cuts using quick)
  2. Last rules drop everything, all previous rules have the quick short cut

The pf firewall rules, use method 2. I would have preferred method 1, but oh well. So, here is the ruleset I built:

`

System Aliases

loopback = “{ lo0 }”
lan = “{ re1 }”
wan = “{ re0 }”
enc0 = “{ enc0 }”
hurrelec=”[HE tunnel IPv4 endpoint]“`

# Allow IPv6<br /> pass out quick on gif0 inet6 label "gif0 tunnel out allowed"<br /> pass in quick inet proto 41 from $hurrelec to $wan keep state label "tunnel traffic from HE"<br /> pass out quick inet proto 41 from $wan to $hurrelec keep state label "tunnel traffic to HE"<br /> pass in quick on $lan inet6 proto tcp from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any keep state label "IPv6 TCP from the LAN"<br /> pass in quick on $lan inet6 proto udp from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any keep state label "IPv6 UDP from the LAN"<br /> pass in quick on $lan inet6 proto icmp6 to any keep state label "ICMPv6 from the LAN"

# Allow some ICMPv6 through<br /> pass in quick log on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type echoreq label "ICMPv6 echo request in lan"<br /> pass in quick log on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type echorep label "ICMPv6 echo reply in lan"<br /> pass out quick on $lan inet6 proto icmp6 from any to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type echoreq label "ICMPv6 echo request out lan"<br /> pass out quick on $lan inet6 proto icmp6 from any to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type echorep label "ICMPv6 echo reply out lan"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type timex label "ICMPv6 time exceeded"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type unreach label "ICMPv6 destination unreachable"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type paramprob label "ICMPv6 invalid header (parameter problem)"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type toobig label "ICMPv6 too big"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type groupqry label "ICMPv6 group membership query"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type listqry label "ICMPv6 multicast listener query"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type grouprep label "ICMPv6 group membership report"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type groupterm label "ICMPv6 group membership termination"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type listendone label "ICMPv6 multicast listener done"<br /> pass in quick on $lan inet6 proto icmp6 icmp6-type routersol label "ICMPv6 lan router solicitations"<br /> pass in quick on $lan inet6 proto icmp6 icmp6-type neighbrsol label "ICMPv6 lan neighbor solicitations"<br /> pass out quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 router]</span> to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type routeradv label "ICMPv6 lan router advertisements"<br /> pass out quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 router]</span> to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type neighbradv label "ICMPv6 lan neighbor advertisements"

``

# loopback<br /> anchor "loopback"<br /> pass in quick on $loopback inet6 all label "pass in loopback IPv6"<br /> pass out quick on $loopback inet6 all label "pass out loobkack IPv6"

``

 

 

 

```As As will gladly tell you, we are rapidly running out of unique IP addresses on the Internet.  The good news is we solved this problem in 1998.  The bad news is that, after more than ten years, we still haven’t widely implemented the new standard: IPv6. All of the big carriers support it, but getting access to the IPv6 Internet is still very tough. If you are a Comcast customer it is possible to get IPv6 access, and there are a few others who allow access as well. For everyone else, you either have to wait or you can get a tunnel (again from HE through their awesome Tunnel Broker service).

Let me take a moment here and state that I really applaud HE’s leadership in the transition to IPv6. They run an excellent tunnel broker service for end users, they run a very large transit network, they share a lot of information, and they were not afraid to jump in the pool. Without their efforts I don’t think we would be as far along today as we are now, and I thank them deeply for their efforts to date.

Now, some may know the differences between IPv4 (the current Internet addressing scheme) and IPv6 (the new scheme), but some may not. There are a lot of excellent resources that go into much deeper detail than I will but here are the basics:

  • The space for IP addresses has changed from 32bits to 128bits – an immensely huge number of addresses.
  • There are NO private address spaces in IPv6 (unlike IPv4 which has several: 10.0.0.0/8 192.168.0.0/16 and 172.16.0.0/12).
  • While there is Network Address Translation (NAT) in IPv6, it is 1-to-1 – as opposed to the typical 1-to-many used by almost every consumer/business router product on the market.
  • Unlike current IPv4 addressing where end users typically get a single IP address with a consumer connection, you get an entire 64bit subnet on a consumer connection with IPv6.
  • Unlike the current IPv4 Internet where many people are on the same “private” subnets, everyone on the IPv6 Internet is uniquely addressable. This has the benefit of P2P and gaming systems not having to use so much “magic” in order for connectivity.

There are downsides to this: because everything is Internet addressable, the need of security in depth firewall solutions is much greater than it has been in the past. You can no longer depend on a big NAT firewall at the border of your network to protect you. The old, lazy M&M security model (hard outer shell, soft and chewy on the inside) is dead. This also brings up some interesting concerns for “consumer devices” (such as game consoles, and other black-box network appliances) on your network as they could now be more of an attack vector into your network than they were before.

With all this in mind I got a HE tunnel and wanted to build a firewall for my stuff at home.  Previously, I used a pfSense firewall on a Soekris NET4801 hardware platform. This was great, but pfSense does not support IPv6 on their General Availability release. Also the old NET4801 doesn’t have enough horsepower to handle my forthcoming FiOS high speed connection (the combination of the NICs and the processor can only handle about 9mbps, where as the FiOS package I want is 25mbps). I also have a game console (PS3) which needs UPnP IGD service on my router in order for on-line gaming to work. There are other firewall solutions which do support IPv6, but none supported IPv6 and UPnP. So, I started to build one myself.

I decided to build the firewall on a Jetway VIA C7 platform using FreeBSD. Why FreeBSD? The miniupnpd server is ported to it, and it includes the pf firewall. Also, FreeBSD is the basis for pfSense so I could re-use my old IPv4 pf rules. I could have used Linux, but I woud have to compile miniupnpd myself and I haven’t tested it on Linux.

Before making the firewall, I sat down and figured out what traffic I wanted my firewall to pass and what I wanted it to block for IPv6. Here are the goals I cam up with:

  • Anyone can ping anyone on either side of the firewall
  • Anyone inside the firewall can connect to anyone on the outside of the firewall
  • No TCP/UDP connections be made from outside the firewall to hosts inside the firewall by default (specific ports can be opened later)
  • Router Advertisements from outside the firewall will NOT be passed inside the firewall
  • Router Solicitations from inside the firewall will NOT be passed to outside the firewall
  • Neighbor Solicitations will not pass through the firewall

Obviously, more complicated that a traditional IPv4 firewall ruleset. So I started to build the rules in pf, and then ran into some problems because I forgot the rules of pf:

  1. LAST match wins
  2. The “quick” keyword means stop processing rules and use that one

With rules like that, there are two solutions for building your rulesets:

  1. First rules drop everything, then the subsequent rules allow traffic (with some short cuts using quick)
  2. Last rules drop everything, all previous rules have the quick short cut

The pf firewall rules, use method 2. I would have preferred method 1, but oh well. So, here is the ruleset I built:

`

System Aliases

loopback = “{ lo0 }”
lan = “{ re1 }”
wan = “{ re0 }”
enc0 = “{ enc0 }”
hurrelec=”[HE tunnel IPv4 endpoint]“`

# Allow IPv6<br /> pass out quick on gif0 inet6 label "gif0 tunnel out allowed"<br /> pass in quick inet proto 41 from $hurrelec to $wan keep state label "tunnel traffic from HE"<br /> pass out quick inet proto 41 from $wan to $hurrelec keep state label "tunnel traffic to HE"<br /> pass in quick on $lan inet6 proto tcp from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any keep state label "IPv6 TCP from the LAN"<br /> pass in quick on $lan inet6 proto udp from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any keep state label "IPv6 UDP from the LAN"<br /> pass in quick on $lan inet6 proto icmp6 to any keep state label "ICMPv6 from the LAN"

# Allow some ICMPv6 through<br /> pass in quick log on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type echoreq label "ICMPv6 echo request in lan"<br /> pass in quick log on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type echorep label "ICMPv6 echo reply in lan"<br /> pass out quick on $lan inet6 proto icmp6 from any to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type echoreq label "ICMPv6 echo request out lan"<br /> pass out quick on $lan inet6 proto icmp6 from any to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type echorep label "ICMPv6 echo reply out lan"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type timex label "ICMPv6 time exceeded"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type unreach label "ICMPv6 destination unreachable"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type paramprob label "ICMPv6 invalid header (parameter problem)"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type toobig label "ICMPv6 too big"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type groupqry label "ICMPv6 group membership query"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type listqry label "ICMPv6 multicast listener query"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type grouprep label "ICMPv6 group membership report"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type groupterm label "ICMPv6 group membership termination"<br /> pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type listendone label "ICMPv6 multicast listener done"<br /> pass in quick on $lan inet6 proto icmp6 icmp6-type routersol label "ICMPv6 lan router solicitations"<br /> pass in quick on $lan inet6 proto icmp6 icmp6-type neighbrsol label "ICMPv6 lan neighbor solicitations"<br /> pass out quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 router]</span> to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type routeradv label "ICMPv6 lan router advertisements"<br /> pass out quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 router]</span> to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type neighbradv label "ICMPv6 lan neighbor advertisements"

``

# loopback<br /> anchor "loopback"<br /> pass in quick on $loopback inet6 all label "pass in loopback IPv6"<br /> pass out quick on $loopback inet6 all label "pass out loobkack IPv6"

``

 

 

 


You also need a few lines in your /etc/rc.conf:
  
````As [As](http://ipv6.he.net) will gladly tell you, we are rapidly running out of unique IP addresses on the Internet.  The good news is we solved this problem in 1998.  The bad news is that, after more than ten years, we still haven't widely implemented the new standard: IPv6. All of the big carriers support it, but getting access to the IPv6 Internet is still very tough. If you are a Comcast customer it is possible to get IPv6 access, and there are a few others who allow access as well. For everyone else, you either have to wait or you can get a tunnel (again from HE through their awesome [Tunnel Broker](http://tunnelbroker.net) service).

Let me take a moment here and state that I really applaud HE's leadership in the transition to IPv6. They run an excellent tunnel broker service for end users, they run a very large transit network, they share a lot of information, and they were not afraid to jump in the pool. Without their efforts I don't think we would be as far along today as we are now, and I thank them deeply for their efforts to date.

Now, some may know the differences between IPv4 (the current Internet addressing scheme) and IPv6 (the new scheme), but some may not. There are a lot of excellent resources that go into much deeper detail than I will but here are the basics:

  * The space for IP addresses has changed from 32bits to 128bits &#8211; an immensely huge number of addresses.
  * There are NO private address spaces in IPv6 (unlike IPv4 which has several: 10.0.0.0/8 192.168.0.0/16 and 172.16.0.0/12).
  * While there is Network Address Translation (NAT) in IPv6, it is 1-to-1 &#8211; as opposed to the typical 1-to-many used by almost every consumer/business router product on the market.
  * Unlike current IPv4 addressing where end users typically get a single IP address with a consumer connection, you get an entire 64bit subnet on a consumer connection with IPv6.
  * Unlike the current IPv4 Internet where many people are on the same "private" subnets, everyone on the IPv6 Internet is uniquely addressable. This has the benefit of P2P and gaming systems not having to use so much "magic" in order for connectivity.

There are downsides to this: because everything is Internet addressable, the need of security in depth firewall solutions is much greater than it has been in the past. You can no longer depend on a big NAT firewall at the border of your network to protect you. The old, lazy M&M security model (hard outer shell, soft and chewy on the inside) is dead. This also brings up some interesting concerns for "consumer devices" (such as game consoles, and other black-box network appliances) on your network as they could now be more of an attack vector into your network than they were before.

With all this in mind I got a HE tunnel and wanted to build a firewall for my stuff at home.  Previously, I used a [pfSense](http://pfsense.org) firewall on a [Soekris NET4801](http://soekris.com) hardware platform. This was great, but pfSense does not support IPv6 on their General Availability release. Also the old NET4801 doesn't have enough horsepower to handle my forthcoming FiOS high speed connection (the combination of the NICs and the processor can only handle about 9mbps, where as the FiOS package I want is 25mbps). I also have a game console (PS3) which needs UPnP IGD service on my router in order for on-line gaming to work. There are other firewall solutions which do support IPv6, but none supported IPv6 and UPnP. So, I started to build one myself.

I decided to build the firewall on a Jetway VIA C7 platform using FreeBSD. Why FreeBSD? The miniupnpd server is ported to it, and it includes the pf firewall. Also, FreeBSD is the basis for pfSense so I could re-use my old IPv4 pf rules. I could have used Linux, but I woud have to compile miniupnpd myself and I haven't tested it on Linux.

Before making the firewall, I sat down and figured out what traffic I wanted my firewall to pass and what I wanted it to block for IPv6. Here are the goals I cam up with:

  * Anyone can ping anyone on either side of the firewall
  * Anyone inside the firewall can connect to anyone on the outside of the firewall
  * No TCP/UDP connections be made from outside the firewall to hosts inside the firewall by default (specific ports can be opened later)
  * Router Advertisements from outside the firewall will NOT be passed inside the firewall
  * Router Solicitations from inside the firewall will NOT be passed to outside the firewall
  * Neighbor Solicitations will not pass through the firewall

Obviously, more complicated that a traditional IPv4 firewall ruleset. So I started to build the rules in pf, and then ran into some problems because I forgot the rules of pf:

  1. LAST match wins
  2. The "quick" keyword means stop processing rules and use that one

With rules like that, there are two solutions for building your rulesets:

  1. First rules drop everything, then the subsequent rules allow traffic (with some short cuts using quick)
  2. Last rules drop everything, all previous rules have the quick short cut

The pf firewall rules, use method 2. I would have preferred method 1, but oh well. So, here is the ruleset I built:
  
`<br />
# System Aliases<br />
loopback = "{ lo0 }"<br />
lan = "{ re1 }"<br />
wan = "{ re0 }"<br />
enc0 = "{ enc0 }"<br />
hurrelec="<span style="color: #ff0000;">[HE tunnel IPv4 endpoint]</span>"`

`# Allow IPv6<br />
pass out quick on gif0 inet6 label "gif0 tunnel out allowed"<br />
pass in quick inet proto 41 from $hurrelec to $wan keep state label "tunnel traffic from HE"<br />
pass out quick inet proto 41 from $wan to $hurrelec keep state label "tunnel traffic to HE"<br />
pass in quick on $lan inet6 proto tcp from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any keep state label "IPv6 TCP from the LAN"<br />
pass in quick on $lan inet6 proto udp from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any keep state label "IPv6 UDP from the LAN"<br />
pass in quick on $lan inet6 proto icmp6 to any keep state label "ICMPv6 from the LAN"`

`# Allow some ICMPv6 through<br />
pass in quick log on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type echoreq label "ICMPv6 echo request in lan"<br />
pass in quick log on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type echorep label "ICMPv6 echo reply in lan"<br />
pass out quick on $lan inet6 proto icmp6 from any to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type echoreq label "ICMPv6 echo request out lan"<br />
pass out quick on $lan inet6 proto icmp6 from any to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type echorep label "ICMPv6 echo reply out lan"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type timex label "ICMPv6 time exceeded"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type unreach label "ICMPv6 destination unreachable"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type paramprob label "ICMPv6 invalid header (parameter problem)"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type toobig label "ICMPv6 too big"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type groupqry label "ICMPv6 group membership query"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type listqry label "ICMPv6 multicast listener query"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type grouprep label "ICMPv6 group membership report"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type groupterm label "ICMPv6 group membership termination"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type listendone label "ICMPv6 multicast listener done"<br />
pass in quick on $lan inet6 proto icmp6 icmp6-type routersol label "ICMPv6 lan router solicitations"<br />
pass in quick on $lan inet6 proto icmp6 icmp6-type neighbrsol label "ICMPv6 lan neighbor solicitations"<br />
pass out quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 router]</span> to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type routeradv label "ICMPv6 lan router advertisements"<br />
pass out quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 router]</span> to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type neighbradv label "ICMPv6 lan neighbor advertisements"`

 ``

`# loopback<br />
anchor "loopback"<br />
pass in quick on $loopback inet6 all label "pass in  loopback IPv6"<br />
pass out quick on $loopback inet6 all label "pass out loobkack IPv6"`

 ``

&nbsp;

&nbsp;

&nbsp;

```As [As](http://ipv6.he.net) will gladly tell you, we are rapidly running out of unique IP addresses on the Internet.  The good news is we solved this problem in 1998.  The bad news is that, after more than ten years, we still haven't widely implemented the new standard: IPv6. All of the big carriers support it, but getting access to the IPv6 Internet is still very tough. If you are a Comcast customer it is possible to get IPv6 access, and there are a few others who allow access as well. For everyone else, you either have to wait or you can get a tunnel (again from HE through their awesome [Tunnel Broker](http://tunnelbroker.net) service).

Let me take a moment here and state that I really applaud HE's leadership in the transition to IPv6. They run an excellent tunnel broker service for end users, they run a very large transit network, they share a lot of information, and they were not afraid to jump in the pool. Without their efforts I don't think we would be as far along today as we are now, and I thank them deeply for their efforts to date.

Now, some may know the differences between IPv4 (the current Internet addressing scheme) and IPv6 (the new scheme), but some may not. There are a lot of excellent resources that go into much deeper detail than I will but here are the basics:

  * The space for IP addresses has changed from 32bits to 128bits &#8211; an immensely huge number of addresses.
  * There are NO private address spaces in IPv6 (unlike IPv4 which has several: 10.0.0.0/8 192.168.0.0/16 and 172.16.0.0/12).
  * While there is Network Address Translation (NAT) in IPv6, it is 1-to-1 &#8211; as opposed to the typical 1-to-many used by almost every consumer/business router product on the market.
  * Unlike current IPv4 addressing where end users typically get a single IP address with a consumer connection, you get an entire 64bit subnet on a consumer connection with IPv6.
  * Unlike the current IPv4 Internet where many people are on the same "private" subnets, everyone on the IPv6 Internet is uniquely addressable. This has the benefit of P2P and gaming systems not having to use so much "magic" in order for connectivity.

There are downsides to this: because everything is Internet addressable, the need of security in depth firewall solutions is much greater than it has been in the past. You can no longer depend on a big NAT firewall at the border of your network to protect you. The old, lazy M&M security model (hard outer shell, soft and chewy on the inside) is dead. This also brings up some interesting concerns for "consumer devices" (such as game consoles, and other black-box network appliances) on your network as they could now be more of an attack vector into your network than they were before.

With all this in mind I got a HE tunnel and wanted to build a firewall for my stuff at home.  Previously, I used a [pfSense](http://pfsense.org) firewall on a [Soekris NET4801](http://soekris.com) hardware platform. This was great, but pfSense does not support IPv6 on their General Availability release. Also the old NET4801 doesn't have enough horsepower to handle my forthcoming FiOS high speed connection (the combination of the NICs and the processor can only handle about 9mbps, where as the FiOS package I want is 25mbps). I also have a game console (PS3) which needs UPnP IGD service on my router in order for on-line gaming to work. There are other firewall solutions which do support IPv6, but none supported IPv6 and UPnP. So, I started to build one myself.

I decided to build the firewall on a Jetway VIA C7 platform using FreeBSD. Why FreeBSD? The miniupnpd server is ported to it, and it includes the pf firewall. Also, FreeBSD is the basis for pfSense so I could re-use my old IPv4 pf rules. I could have used Linux, but I woud have to compile miniupnpd myself and I haven't tested it on Linux.

Before making the firewall, I sat down and figured out what traffic I wanted my firewall to pass and what I wanted it to block for IPv6. Here are the goals I cam up with:

  * Anyone can ping anyone on either side of the firewall
  * Anyone inside the firewall can connect to anyone on the outside of the firewall
  * No TCP/UDP connections be made from outside the firewall to hosts inside the firewall by default (specific ports can be opened later)
  * Router Advertisements from outside the firewall will NOT be passed inside the firewall
  * Router Solicitations from inside the firewall will NOT be passed to outside the firewall
  * Neighbor Solicitations will not pass through the firewall

Obviously, more complicated that a traditional IPv4 firewall ruleset. So I started to build the rules in pf, and then ran into some problems because I forgot the rules of pf:

  1. LAST match wins
  2. The "quick" keyword means stop processing rules and use that one

With rules like that, there are two solutions for building your rulesets:

  1. First rules drop everything, then the subsequent rules allow traffic (with some short cuts using quick)
  2. Last rules drop everything, all previous rules have the quick short cut

The pf firewall rules, use method 2. I would have preferred method 1, but oh well. So, here is the ruleset I built:
  
`<br />
# System Aliases<br />
loopback = "{ lo0 }"<br />
lan = "{ re1 }"<br />
wan = "{ re0 }"<br />
enc0 = "{ enc0 }"<br />
hurrelec="<span style="color: #ff0000;">[HE tunnel IPv4 endpoint]</span>"`

`# Allow IPv6<br />
pass out quick on gif0 inet6 label "gif0 tunnel out allowed"<br />
pass in quick inet proto 41 from $hurrelec to $wan keep state label "tunnel traffic from HE"<br />
pass out quick inet proto 41 from $wan to $hurrelec keep state label "tunnel traffic to HE"<br />
pass in quick on $lan inet6 proto tcp from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any keep state label "IPv6 TCP from the LAN"<br />
pass in quick on $lan inet6 proto udp from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any keep state label "IPv6 UDP from the LAN"<br />
pass in quick on $lan inet6 proto icmp6 to any keep state label "ICMPv6 from the LAN"`

`# Allow some ICMPv6 through<br />
pass in quick log on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type echoreq label "ICMPv6 echo request in lan"<br />
pass in quick log on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type echorep label "ICMPv6 echo reply in lan"<br />
pass out quick on $lan inet6 proto icmp6 from any to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type echoreq label "ICMPv6 echo request out lan"<br />
pass out quick on $lan inet6 proto icmp6 from any to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type echorep label "ICMPv6 echo reply out lan"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type timex label "ICMPv6 time exceeded"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type unreach label "ICMPv6 destination unreachable"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type paramprob label "ICMPv6 invalid header (parameter problem)"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type toobig label "ICMPv6 too big"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type groupqry label "ICMPv6 group membership query"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type listqry label "ICMPv6 multicast listener query"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type grouprep label "ICMPv6 group membership report"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type groupterm label "ICMPv6 group membership termination"<br />
pass in quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 prefix]</span>/64 to any icmp6-type listendone label "ICMPv6 multicast listener done"<br />
pass in quick on $lan inet6 proto icmp6 icmp6-type routersol label "ICMPv6 lan router solicitations"<br />
pass in quick on $lan inet6 proto icmp6 icmp6-type neighbrsol label "ICMPv6 lan neighbor solicitations"<br />
pass out quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 router]</span> to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type routeradv label "ICMPv6 lan router advertisements"<br />
pass out quick on $lan inet6 proto icmp6 from <span style="color: #ff0000;">[IPv6 router]</span> to <span style="color: #ff0000;">[IPv6 prefix]</span>/64 icmp6-type neighbradv label "ICMPv6 lan neighbor advertisements"`

 ``

`# loopback<br />
anchor "loopback"<br />
pass in quick on $loopback inet6 all label "pass in  loopback IPv6"<br />
pass out quick on $loopback inet6 all label "pass out loobkack IPv6"`

 ``

&nbsp;

&nbsp;

&nbsp;

You also need a few lines in your /etc/rc.conf:

````

You also need the secret decoder ring:

  • [IPv6 prefix] – Your delegated netblock, typically ends in “::/64”
  • [IPv6 router] – This is the address of your router in your netblock
  • [HE tunnel IPv4 endpoint] – This information provided by HE for your tunnel
  • [provided by HE] – This information is also provided by HE for your tunnel

The rules work as I expected, after some debugging. They also complete all the goals above, I’m sure I’ll be adding specific rules for specific applications as time goes on. If I were going to start from scratch, I would reverse the rules in order and then remove all the quick keywords. But I’m not..for now.  Hope this helps others, please don’t hesitate to contact me if you have questions.

comments powered by Disqus