Now take that default route (i.e. fe80::201:5cff:fe50:c041%em3) and place it in your /etc/rc.conf like this:

ipv6_defaultrouter="fe80::201:5cff:fe50:c041%em3" # ugly hack

Others have run into this problem. It [hard-coding the route] wasn’t necessary when the firewall was strictly a DHCPv6 client, but once the firewall enabled IPv6 packet forwarding and ran the rtadvd daemon, it would periodically lose its default IPv6 route.

The downside of hard-coding the default route is that if/when your ISP re-configures the upstream router, your IPv6 configuration will break. [Within two months of publishing this post, Comcast re-configured their upstream router (at approx 01:40 2013-11-12). I’ve added a section “When Comcast changes its configuration” at the bottom to recover from cases like this.]

A quick note about IPv6 addresses: an IPv6 address that begins with “fe80″ is a link-local address—it can only be reached by machines on the local subnet, it cannot be reached by machines outside that subnet. Often it includes components of the ethernet MAC’s address (IPv6 uses Modified EUI-64, which is derived from the MAC address). There is nothing quite analogous to this in the IPv4 protocol.

IPv6 Gateway and rtadvd Daemon

We are now ready to turn our firewall into an IPv6 gateway and enable the rtadvd (router advertisement daemon). Modify /etc/rc.conf to include the following lines:

ipv6_gateway_enable="YES"
rtadvd_enable="YES" # Set to YES to enable an IPv6 router
rtadvd_interfaces="em0"

Note that you should enable rtadvd only on your inside interface (in this example, em0). You should not enable it on your outside interface. rtadvd is the daemon that manages IPv6’s router advertisement protocol. Router advertisement is similar to IPv4’s DHCP protocol in that it provides IP addresses to clients.

Reboot your firewall so that the changes take effect: sudo shutdown -r now

Testing

After your firewall has rebooted, your internal machines should automatically acquire IPv6 addresses—you shouldn’t need to do any additional configuration. But how to be sure? Let’s test.

The easiest way to test is to point a browser from one of your inside machines to http://test-ipv6.com/. You should score 10/10. Don’t worry if the page displays, “Your browser has real working IPv6 address – but is avoiding using it. We’re concerned about this.”

Observations

The client machines didn’t need any configuration—they were IPv6-ready out-of-the-box. Kudos to Apple and Microsoft. Even my printer worked (Go HP!). Sadly, my HTC One Google Edition Android Version 4.3 did not acquire an IPv6 address, but that appears to be a limitation of the HTC One and not the Android OS. Also, my Raspberry Pi (Linux running Raspbian) required slight re-configuration to enable IPv6, but almost every other Linux distro “just works”.

18 Quintillion Addresses

To clarify, I didn’t use all 18 quintillion addresses. In fact, I only used 11 of them. Comcast assigned me 2601:9:7980:1c2/64 (“/64″ is IPv6’s prefixlen, which is similar to IPv4’s CIDR notation, i.e. subnet-mask). That leaves 64 remaining bits (IPv6 addresses have 128 bits) for me to assign to my machines, which works out to 2^64 addresses, or 18 quintillion.

When Comcast changes its Configuration

Comcast can change its configuration; specifically, it might re-configure/swap-out its upstream router, which in turn may cause your IPv6 default route to change. Your first clue that something is wrong is that your IPv6 configuration will break. (e.g. ping6 ipv6.google.com will fail) Additionally, you may see messages similar to the following the following in /var/log/messages:

Notice that our default route’s MAC address is 00:01:5c:63:ec:46? The IPv6 counterpart is fe80::201:5cff:fe63:ec46%em3. That is what you need to set your default route to in /etc/rc.conf, i.e.

ipv6_defaultrouter="fe80::201:5cff:fe63:ec46%em3" # ugly hack

Reboot your router, and IPv6 should work again (note that it may take a couple of hours for things to shake out. For example, connectivity to my DHCPv6-acquired external IPv6 address was intermittent for ~8 hours after reconfiguration). Curiously, my internal machines who acquired their addresses via router solicitation worked right away.

Kyle Manna has written an excellent post on how to configure a Linux firewall as a native IPv6 Comcast client.

“My ISP is deploying IPv6, and I want to use it, but I don’t know what my firewall rulesets should look like.”

In this blog post, we discuss a basic set of IPv6 rules which will allow the firewall to route IPv6 traffic from internal machines while protecting those same machines from hostile probes. Although this blog post focuses on the *BSD pf (packet filter) firewall, the points can be generalized to other firewall rulesets (e.g. Linux’s iptables).

These rulesets are used by a firewall on the Comcast network, which has native IPv6 (i.e. not tunneling; these rules have not been tested on an IPv6 tunnel).

Here’s a barebones pf.conf (packet filter) ruleset for IPv6 (note: these rules are in addition to the IPv4 rules):

Notes

The firewall routes outbound IPv6 traffic (e.g. it does not convert the IPv6 address of my printer (2601:9:7980:1C2:121F:74FF:FE47:DAEE)). Each IPv6-capable machine on my network has a unique, routable IPv6 address.

The IPv6 firewall ruleset can not depend on the security that NAT offers to my IPv4 machines. Every one of my IPv6-capable machines (Mac Mini, MacBook Air, Windows 8, HP1536 printer) has a routable (public) IPv6 address. In other words, you cannot reach my printer’s IPv4 address (10.9.9.50) from the Internet, but you can reach its IPv6 address (2601:9:7980:1C2:121F:74FF:FE47:DAEE).

As a side note, none of the devices (except the firewall itself) needed special configuration in order to acquire an IPv6 address and to operate in an IPv6 environment.

The default rule is to deny inbound traffic. Inbound protocols/ports must be specifically enabled

The firewall does not filter outbound traffic, only inbound (i.e. the firewall will not drop any packet originating from a machine on the inside network, e.g. my mac mini).

Why These Rules?

Let’s discuss which services have been allowed through the firewall, the reasons for allowing them, and whether they’re reasonable to disable. We’ll break the services down by protocol (i.e. ICMP, TCP, and UDP), and whether a particular service has been enabled solely for the firewall or for the entire IPv6 home network.

Inbound ICMP6 for the Firewall

133, 134, 135, 136, 137 (router solicit, router advertisement, neighbor solicit, neighbor advertisement, route redirection). These should not be disabled. This is a good basic set of rules that allow the firewall to communicate with other IPv6 machines on its outside interface’s local subnet.

Note that I’ve allowed both unicast traffic and multicast (ff02::1/16, i.e. “All nodes on the local network segment”) to my external interface. ICMP6 Neighbor Solicitation sends packets to the local network segment multicast address. If you don’t accept those multicast packets, your neighbors (including your upstream router) won’t be able to discover you, and your external interface’s IPv6 address will be unreachable from other machines.

Inbound TCP Services for All Machines, including Firewall

port 22 (ssh). Safe to disable. I like to ssh in to my machines. All my machines. Security implications: I need to make sure that every account that can ssh-in has a hard-to-guess password.

Inbound TCP Services for the Firewall

Port 53 (DNS zone transfer). Unless your firewall is hosting a DNS zone (unlikely), then you can safely turn this off. Although the firewall allows this traffic, the nameserver has ACLs that only allow zone transfers from 2 IP addresses (my two external nameservers). Don’t depend on pf to be your only layer of security; restrict access when you can.

Inbound UDP Services for the Firewall

Port 53 (DNS). Unless your firewall is hosting a DNS zone (unlikely), then you can safely turn this off. I have used ACLs to further restrict access to my firewall’s nameserver daemon (not via packet filtering, but via named.conf): it only answers queries for domains for which it is authoritative; it won’t honor recursive queries originating from the Internet.

123 (NTP). Unless your firewall is part of the NTP Pool Project, you can safely turn this off. Note that if you decide to join the NTP Pool, you should lock down your ntp configuration. If you’re not sure how to do it, this is a good place to start. Pay special attention to the restrict directives.

Abstract

ISPs are now offering native IPv6 to their customers, which begs the question, “how do I configure my machine to use IPv6?” This blog post describes the steps to configure a FreeBSD 9.1 machine as an IPv6 DHCP client on the Comcast network.

Prerequisites

First, the machine you are configuring must have an interface on the Internet, it cannot be behind a firewall. This machine should be the firewall.

Second, disable any firewall rules. Really, I mean it. You can re-enable the rules once you have a working configuration, at which point any problems can be addressed by fixing the firewall rulesets. And for you firewall wizards out there who are not going to listen to this advice because you know better, I want to caution you that pf(4) IPv6 rulesets may not work as expected; you are better off disabling filters (or at least adopting a default-allow stance). It may save you several hours of pointless frustration.

Manual Procedure

In this example, the external interface (the one which will have the IPv6 address) is em3. First, let’s install the IPv6 DHCP client program:

sudo pkg_add -r dhcp6

Second, let’s create /usr/local/etc/dhcp6c.conf with the following contents:

Let’s run the client in the foreground to see if it can successfully acquire an IPv6 address (remember to substitute your interface name for em3):

sudo /usr/local/sbin/dhcp6c -fd em3

If you see a message client6_send: transmit failed: Network is unreachable, then hit ctrl-C to stop dhcp6, enable IPv6 and router advertisements on your interface, then start dhcp6 (again, substitute for em3):

Notice there are two IPv6 addresses. Ignore the one that begins with fe80::200— it’s a link-local address that only works on the local subnet; it doesn’t work on the Internet. The second IPv6 address, the one beginning with 2001:558, is your Internet-accessible IP address.

Abstract

FreeBSD 9.1, when a DHCP client, uses resolvconf to construct /etc/resolv.conf (which defines the DNS nameservers to query); however, this may be undesired behavior, especially when already running a local nameserver—The local nameserver will be ignored; the local domain won’t be searched; the reverse-lookups for RFC 1918 networks (e.g. 10.0.0.0/8) will fail or timeout.

This blog post describes a technique to override the DHCP-distributed DNS information with local information.

Problem Description

The original /etc/resolv.conf on the FreeBSD machine:

search nono.com
nameserver 127.0.0.1

This had the following advantages:

Hostnames were searched for within the nono.com domain. For example, when attempting to connect to the printer hp1536, one didn’t need an FQDN (i.e. hp1536.nono.com).

Comcast had configured a reasonable default domain to search, i.e. hsd1.ca.comcast.net., but that is unhelpful for the minority who have set up their own domains. Comcast also gave a reasonable set of nameservers to query, but similarly that is unhelpful for the minority who have set up RFC 1918 zones (e.g. 10.in-addr.arpa) (i.e. arp -a shows question marks, not hostnames).

The Fix

The fix is to configure resolvconf(8) to use the local search domain and nameservers before querying the DHCP-supplied search domains and nameservers. That is accomplished by creating /etc/resolvconf.conf:

search_domains="nono.com"
name_servers="127.0.0.1"

Now make sure that your configuration file is good by running resolvconf to update /etc/resolv.conf:

sudo resolvconf -u

Your new /etc/resolv.conf file should look something like the following: