If you have a Linux router and AT&T Gigabit fiber, you may want to have all your VLANs addressed with IPv6. This is assuming you set up the AT&T modem to do IP passthrough, so you have an actual IPv4 address in your router.
WAN Setup
First and foremost, your router needs to speak IPv6 to the world. You need to accept AT&Ts router advertisement, so you can set up your IPv6 address using SLAAC.
echo 2 > /proc/sys/net/ipv6/conf/att0/accept_ra
As you want to be a router, you need to enable forwarding for both v4 and v6:
echo 1 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
I named the WAN interface att0
and the LAN interface home0
.
You should see something like this:
$ ip addr show att0
2: att0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:11:22:33:44:55 brd ff:ff:ff:ff:ff:ff
inet 99.1.2.3/22 brd 99.1.3.255 scope global dynamic att0
valid_lft 2755sec preferred_lft 2755sec
inet6 2600:1:2:3::45/128 scope global
valid_lft forever preferred_lft forever
inet6 2600:4:5:6:7:8:9:10/64 scope global dynamic mngtmpaddr
valid_lft 3350sec preferred_lft 3350sec
inet6 fe80::1:2:3:4/64 scope link
valid_lft forever preferred_lft forever
With everything working, a ping6 to Google should work:
$ ping6 -n -c 1 google.com
PING google.com(2607:f8b0:4005:802::200e) 56 data bytes
64 bytes from 2607:f8b0:4005:802::200e: icmp_seq=1 ttl=117 time=6.04 ms
--- google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 6.041/6.041/6.041/0.000 ms
LAN Setup
To request prefixes for your internal VLANs, you will ask a prefix delegation (PD) via DHCPv6. Some ISPs, like Comcast, allow you to request a /60 block, so you can chop it yourself. AT&T doesn’t allow that, but they do allow requesting multiple /64s, which has the same effect at the end.
On Debian/Ubuntu, install the package wide-dhcpv6-client
.
Your /etc/wide-dhcpv6/dhcp6c.conf
will look like this:
interface att0 {
send ia-pd 0;
send ia-pd 1;
send ia-pd 2;
send ia-pd 3;
send ia-na 0;
send rapid-commit;
};
id-assoc pd 0 {
prefix ::/64 infinity;
prefix-interface home0.2 {
sla-len 0;
sla-id 0;
};
};
id-assoc pd 1 {
prefix ::/64 infinity;
prefix-interface home0.3 {
sla-len 0;
sla-id 0;
};
};
id-assoc pd 2 {
prefix ::/64 infinity;
prefix-interface home0.4 {
sla-len 0;
sla-id 0;
};
};
id-assoc pd 3 {
prefix ::/64 infinity;
prefix-interface home0 {
sla-len 0;
sla-id 0;
};
};
id-assoc na {
};
As you can see, I use send ia-pd
multiple times with a different ID. Then later I associate each PD to a different interface. The order doesn’t matter.
If everything worked, ip -6 addr
should show all interfaces addressed correctly.
Addressing your clients
So far, your internal clients have no idea your network can speak IPv6. You need to advertise your prefixes to them. That’s a job for the package radvd
.
Your /etc/radvd.conf
will look like this:
interface home0.2
{
AdvSendAdvert on;
prefix ::/64
{
AdvValidLifetime 900;
AdvPreferredLifetime 900;
};
RDNSS 2001:4860:4860::8888 2001:4860:4860::8844 {};
};
interface home0.3
{
AdvSendAdvert on;
prefix ::/64
{
AdvValidLifetime 900;
AdvPreferredLifetime 900;
};
RDNSS 2001:4860:4860::8888 2001:4860:4860::8844 {};
};
interface home0.4
{
AdvSendAdvert on;
prefix ::/64
{
AdvValidLifetime 900;
AdvPreferredLifetime 900;
};
RDNSS 2001:4860:4860::8888 2001:4860:4860::8844 {};
};
interface home0
{
AdvSendAdvert on;
prefix ::/64
{
AdvValidLifetime 900;
AdvPreferredLifetime 900;
};
RDNSS 2001:4860:4860::8888 2001:4860:4860::8844 {};
};
You pretty much repeat the same thing over and over for each interface. RDNSS in my example is announcing the Google’s DNS servers, which are the IPv6 version of 8.8.8.8 and 8.8.4.4.
Firewall
Do not filter ICMPv6 on your input and forward chains, unless you know what you are doing. ICMP is a crucial part of IPv6.
For DHCPv6 work, you need to accept UDP datagrams on ports 546 and 547.
Security
Once you address all your internal clients, they will all have a valid IPv6 address and are able to receive traffic directly from the Internet. You probably don’t want that, so you need to set up some firewall to prevent undesired incoming traffic.
This is a simple example with NFTables, only showing the forward chain:
table inet filter {
chain forward {
type filter hook forward priority 0; policy drop;
ct state related,established accept
iifname {home0.2, home0.3} oifname att0 accept
ip6 nexthdr ipv6-icmp iifname att0 icmpv6 type {1,2,3,4,128,129} accept
}
}
That’s all!