Skip to content

Instantly share code, notes, and snippets.

@marcopaganini
Created January 19, 2024 21:29
Show Gist options
  • Save marcopaganini/ab632c3eff23d05dd73c9e1e2a8cbcb6 to your computer and use it in GitHub Desktop.
Save marcopaganini/ab632c3eff23d05dd73c9e1e2a8cbcb6 to your computer and use it in GitHub Desktop.
Quick debian guide for IPv6 on Comcast

IPv6 on Comcast

WAN (eth0) configuration using wide-dhcpv6

This component does a few important things:

  • Retrieves an IPv6 address (from comcast) for our external interfaces (Using IA).

  • Retrieves a prefix from comcast using Prefix Discovery (PD). By default, comcast will send a /64 prefix, which is only good for one host (we need more networks, as routing anything less than a /64 tends to break a lot of stuff in ipv6). In this case, we use wide-dhcpv6-client to request a /60 from comcast. Note that the network is not related to the IP address given to the interface.

  • Assign ipv6 addresses to each of the other interfaces, based on the prefix received from comcast and our configuration (see below).

  • Note that routes (including default routes) in ipv6 are assigned via RA. Make sure net.ipv6.conf.all.accept_ra and net.ipv6.conf.<interface>.accept_ra are both set to 2 in /etc/sysctl.conf (normally interface here is the WAN interface, eth0.)

    Sample /etc/sysctl.conf entries:

    net.ipv6.conf.all.accept_ra=2
    net.ipv6.conf.eth0.accept_ra=2
    
    • Note: Setting it to 1 will work partially, but the WAN interface (eth0) won't receive the default route to the Internet, breaking things.

Sample wide-dhcpv6 config (eth0 = external interface, lan0.X = internal VLANs:)

profile default
{
  information-only;
  script "/etc/wide-dhcpv6/dhcp6c-script";
};

interface eth0 {
  send ia-na 1;
  send ia-pd 1;
};

id-assoc na 1 {
};

id-assoc pd 1 {
  # Request a /60 from Comcast.
  prefix ::/60 infinity;

  # `sla-id` is the Site Level Aggregator (SLA) used to form the ipv6 of each
  # of the interfaces. The format is normally `<prefix><sla-id>::<if-id>`. We
  # Match the VLAN number for easy identification of IPv6 addresses.
  #
  # `sla-len` is how long the SLA ID should be (in bits). In our case, we have
  # a /60 given to us by Comcast and we want each interface to have a /64,
  # so this should be 4.
  #
  # `if-id` identifies the interface number (in practive, the last octet)
  # inside each interface. We use 1 so that each interface in the server
  # will end up in `:1`.
  #
  # To reset the DUID (including the PD ip range), remove `/var/lib/dhcpv6/dhcp6c_duid`
  # and restart wide-dhcpv6.

  # Guest network
  prefix-interface lan0.3 {
    sla-id 3;
    sla-len 4;
    ifid 1;
  };

  # Internal network
  prefix-interface lan0.4 {
    sla-id 4;
    sla-len 4;
    ifid 1;
  };

  # DMZ
  prefix-interface lan0.5 {
    sla-id 5;
    sla-len 4;
    ifid 1;
  };
};

wide-dhcpv6 is started by systemd. Extra configuration is present in /etc/default/wide-dhcpv6-client. Sample:

# Interfaces on which the client should send DHCPv6 requests and listen to
# answers. If empty, the client is deactivated.
INTERFACES="eth0"

# Verbose level for syslog. Default is 0 (0: minimal; 1: info; 2: debug)
VERBOSE=1

DNSMASQ configuration

DNSMASQ is used to:

  • Assign internal IPv6 addresses, based on the client's ipv4 addresses and their network.

  • Send Route Advertisements (RA) to the internal networks.

To enable RA, set enable-ra in /etc/dnsmasq.conf.

IPv6 can also use RAs for IPs, setting the AAAA record from ipv6 dhcp_names. Sample excerpt from /etc/dnsmasq.conf:

# ipv6: Use RA for IPs, set AAAA records from ipv4 dhcp names.
dhcp-range=set:guest_v6,::100,constructor:lan0.3, ra-names, 24h
dhcp-range=set:internal_v6,::100,constructor:lan0.4, ra-names, 24h
dhcp-range=set:dmz_v6,::100,constructor:lan0.5, ra-names, 24h

(See dnsmasq documentation for more details.)

Debugging RA messages

Use radvdump to see the stream of RA messages.

Sample routing table on client inside internal network:

$ ip -6 route show

::1 dev lo proto kernel metric 256 pref medium
2601:646:9680:5924::/64 dev eth0 proto ra metric 100 pref medium
fe80::/64 dev eth0 proto kernel metric 100 pref medium
fe80::/64 dev veth7092176 proto kernel metric 256 pref medium
fe80::/64 dev docker0 proto kernel metric 256 pref medium
fe80::/64 dev veth8546e3b proto kernel metric 256 pref medium
fe80::/64 dev veth4f0c5a1 proto kernel metric 256 pref medium
default via fe80::6ca2:99ff:fe50:d55d dev eth0 proto ra metric 100 pref medium

Note how the fe80 (link local) addresses are used for routing. The default gateway points to the link local address of the router.

Case study: No default route

For some reason, there's no default route pointing to Comcast (on the server):

$ ip -6 r s | grep '^default'
<nothing>

Using radvdump we see messages coming from eth0 (fe80::201:5cff:fea9:3446), but no default routes. The following routes are present (but still don't generate entries in the routing tables):

prefix 2001:558:4000:62::/64
prefix 2001:558:5027:c6::/64
prefix 2001:558:6045:74::/64
prefix 2001:558:8046:b6::/64

Adding a default route by hand works:

ip -6 route add default via fe80::201:5cff:fea9:3446 dev eth0

Cause: missing accept_ra = 2 in /etc/sysctl.conf.

Other differences

'arp' command is now 'ip neigh'

Instead of arp use ip -6 neigh show to see ipv6 and mac addresses.

Links

Dynamic addresses on clients

IPV6 can use DHCP6 or SLAAC (stateless) to give addresses to clients. SLAAC is simpler, but can't be used to set fixed addresses on certain hosts, for example.

Clients typically end up with two types of addresses on clients: "temporary dynamic" and "mngtmpaddr noprefixroute". The first is, as the name implies, dynamic and used by clients (for privacy purposes). The second is the "fixed" address of the machine, used for inbound connections. Once dynamic addresses expire, they become "temporary deprecated dynamic" until they eventually disappear from the address table.

Example:

$ ip a s eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether c8:60:00:5f:9f:d8 brd ff:ff:ff:ff:ff:ff
    inet 172.30.1.250/24 brd 172.30.1.255 scope global dynamic noprefixroute eth0
       valid_lft 49902sec preferred_lft 49902sec
    inet 192.168.1.2/24 brd 192.168.1.255 scope global eth0:0
       valid_lft forever preferred_lft forever
    inet6 2601:646:9600:3f74:a833:98c4:93d:a967/64 scope global temporary dynamic
       valid_lft 86078sec preferred_lft 84489sec
    inet6 2601:646:9600:3f74:ca60:ff:fe5f:9fd8/64 scope global dynamic mngtmpaddr noprefixroute
       valid_lft 86078sec preferred_lft 86078sec
    inet6 2601:646:9681:22e4:db94:864b:3402:c113/64 scope global temporary deprecated dynamic
       valid_lft 5220sec preferred_lft 0sec
    inet6 2601:646:9681:22e4:ca60:ff:fe5f:9fd8/64 scope global deprecated dynamic mngtmpaddr noprefixroute
       valid_lft 5220sec preferred_lft 0sec
    inet6 2601:646:9680:5924:fa0d:1d58:9008:3626/64 scope global temporary deprecated dynamic
       valid_lft 5092sec preferred_lft 0sec
    inet6 2601:646:9680:5924:6ec7:e5b6:d30b:188/64 scope global temporary deprecated dynamic
       valid_lft 5092sec preferred_lft 0sec
    inet6 2601:646:9680:5924:ca60:ff:fe5f:9fd8/64 scope global deprecated dynamic mngtmpaddr noprefixroute
       valid_lft 5092sec preferred_lft 0sec
    inet6 fe80::ca60:ff:fe5f:9fd8/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment