lqs/sixup

🌐 IPv6 router daemon for Linux, fully automatic. DHCPv6-PD, RA, DHCPv6 server, NDP proxy, DS-Lite/MAP-E tunnels. One static binary.

Go

0

22 commits

updated Sep 24, 2026

See the code

See what people are saying

README

sixup: IPv6 routing, fully automatic

English | 简体中文 | ę—„ęœ¬čŖž

CI License: MIT

In the past, setting up IPv6 routing on Linux took a number of programs. odhcp6c obtained the prefix, radvd sent the Router Advertisements, odhcpd served DHCPv6, ndppd proxied Neighbor Discovery, and a few scripts passed parameters between them and restarted whatever had to be restarted.

sixup does all of it in one program, the state and the parameters of each stage passing inside it rather than through scripts. When the line hands out a different prefix, the interface addresses, the Router Advertisements, the DHCPv6 leases, the proxy entries and the tunnel endpoints all follow from that one event. No manual step, no restart.

Features

  • Handles the whole job of an IPv6 router, with no other daemon to configure
  • Detects how the prefix arrives, DHCPv6-PD or an RA, and hands clients their addresses and configuration through its own RA and DHCPv6 services
  • When the ISP hands out a new prefix, addresses, RAs, leases, proxy entries and tunnel endpoints follow
  • Shares a single upstream /64 with the LAN as RFC 7278 prescribes, Neighbor Discovery proxy included, splits a shorter prefix across the segments
  • Builds a DS-Lite, MAP-E or IPIP6 tunnel as needed, and keeps MAP-E source ports inside the assigned port set
  • One static binary under 5 MiB, dependent on no external command and no system service

Quick start

[!WARNING] sixup is under development and has not been released yet. Parts of it have never run on a real line, so it may not work at all, and options change from one commit to the next.

Pick the package for your distribution (.deb, .rpm, .apk or Arch Linux .pkg.tar.zst) or a static binary from the releases page. There is no formal release yet, only the dev pre-release.

Check what the line provides, without changing anything:

sudo sixup -wan eth0 -dry-run

Obtain the prefix from the WAN interface and configure one LAN interface from it:

sudo sixup -wan eth0 -lan eth1

The prefix is obtained by whichever method the line supports. No further options are needed.

To divide a delegated prefix across several LAN segments, give each interface a subnet id:

sudo sixup -wan eth0 -lan eth1:0 -lan eth2:1

Note: a single /64 covers one LAN segment. On a line that delegates nothing, subnet id 0 gets the prefix and the other segments get none; give them a ULA with -lan-ula auto if they need to reach each other.

Note: on a MAP-E line the source port has to stay inside the port set the line was given, or return traffic never arrives. sixup maintains those nftables rules in a table of its own, inet sixup, removed when it exits. Pass -tunnel-nat off to write them yourself.

Options

[!WARNING] sixup has not been released yet, so options may be renamed or removed without notice.

sixup -h lists every option in the groups below.

  • A boolean option is turned off with =false, for example -wan-ra=false.
  • A duration takes Go syntax: 30s, 10m, 1h30m.
  • A repeatable option is given once per value: -lan eth1 -lan eth2.

Interfaces and prefixes

OptionDefaultDescription
-wanWAN interface. Required.
-lanLAN interface, repeatable, as name[:subnet-id]. The subnet id, in decimal, picks which /64 of the delegated prefix goes to this interface; without one, the interfaces take 0, 1, 2 in the order given. Several LAN interfaces need a delegated prefix.
-lan-ulaULA prefix advertised next to the global prefix. auto generates a random /48 and keeps it in the state directory; a prefix such as fd12:3456:789a::/48 is used as given. Comma separated for several.
-lan-iidInterface identifiers of the router's own addresses on each LAN prefix, comma separated, one address each, same syntax as -wan-iid. Empty means one RFC 7217 stable address.
-lan-deprecate-hold10mHow long a withdrawn prefix keeps being advertised with a preferred lifetime of 0, so clients stop using it.

WAN side: DHCPv6 client

OptionDefaultDescription
-dhcp6c-modeautoauto follows the M and O flags of the upstream RA, on always runs the client, off never does.
-dhcp6c-pd-len56Prefix length hinted when requesting a delegated prefix (IA_PD). 0 requests none.
-dhcp6c-ia-natrueAlso request an address for the WAN interface itself (IA_NA).
-dhcp6c-pd-grace10sHow long to wait for a delegated prefix after startup. Until then an RA prefix only serves the WAN side and is not handed to the LAN, so it never has to be withdrawn again.
-dhcp6c-releasefalseSend RELEASE on exit to give back the prefix and addresses. Off by default: the DUID is kept, so a restart renews the same prefix. A dry run always releases.

WAN side: upstream RA and addresses

OptionDefaultDescription
-wan-ratrueListen to upstream RAs as a second prefix source, and maintain the default route from them.
-wan-slaactrueConfigure SLAAC addresses on the WAN interface for RA prefixes with the A flag set.
-wan-iidInterface identifiers of the static SLAAC addresses on the WAN interface, comma separated, one address each. Each is stable or empty for an RFC 7217 stable address, eui64 to derive it from the MAC address, or a fixed suffix such as ::1 or ::1111:2222:3333:4444. The first one is reported as the WAN address.
-wan-tempaddrfalseAlso rotate temporary addresses on the WAN interface, following the -tempaddr-* options.
-wan-preferpdWhich prefix wins when both a delegated prefix and an RA prefix are available: pd or ra.
-wan-shared64lanLayout when the upstream gives only one /64. lan: the /64 goes to the LAN, and hosts on the WAN link get /128 routes (RFC 7278). wan: the /64 stays on the WAN, and each LAN host gets a /128 route. split: /128 routes on both sides; the router itself cannot reach a host it has not learned yet. The /128 routes are added as the NDP proxy finds the hosts.

LAN side: RA advertisement

OptionDefaultDescription
-ra-min3m20sMinimum interval between unsolicited RAs (MinRtrAdvInterval).
-ra-max10mMaximum interval between unsolicited RAs (MaxRtrAdvInterval).
-ra-lifetime30mRouter lifetime carried in the RA.
-ra-mtu0MTU advertised in the RA. 0 advertises the WAN path MTU when it is smaller than the LAN interface MTU, taken from the upstream RA or the WAN interface, so a PPPoE line with 1492 no longer depends on path MTU discovery.
-ra-dnsDNS servers to advertise instead of the upstream ones, comma separated. Also used by the DHCPv6 server.
-ra-pref64NAT64 prefix to advertise (RFC 8781), such as 64:ff9b::/96. Empty passes on the one from the upstream RA. The length must be 32, 40, 48, 56, 64 or 96.
-ra-routePrefix to advertise as a Route Information option, repeatable.

LAN side: DHCPv6 server

OptionDefaultDescription
-dhcp6s-modeoffstateless answers only with options such as DNS; stateful also assigns addresses; off runs no server. The RA flags follow this choice.
-dhcp6s-pool1000-ffffRange of interface identifiers to assign from, in hexadecimal, as the low 64 bits.
-dhcp6s-staticFixed assignment, repeatable: mac=<MAC>,addr=::100, or duid=<hex>,addr=2001:db8::5.
-dhcp6s-lease-preferred1hPreferred lifetime of an assigned address.
-dhcp6s-lease-valid2hValid lifetime of an assigned address.

NDP proxy

OptionDefaultDescription
-ndproxy-modeautoauto turns forward on when the prefix is a /64 and stays off otherwise. forward probes the other side before answering, in both directions, so hosts on the WAN link and on the LAN reach each other too. prefix answers every WAN solicitation for an address in the LAN prefix without probing. static only puts the -ndproxy-static entries into the kernel proxy table. off disables the proxy.
-ndproxy-staticAddress or prefix to proxy in static mode, repeatable.
-ndproxy-excludePrefix never proxied, repeatable.
-ndproxy-ttl30sHow long a learned proxy entry lives.

Local address rotation

These options govern the router's own addresses on the LAN, and on the WAN with -wan-tempaddr.

OptionDefaultDescription
-tempaddr-modeofftemporary and both add rotating temporary addresses (RFC 8981) next to the static ones; off and stable keep only the static addresses.
-tempaddr-regen1hHow often a new temporary address is created.
-tempaddr-preferred1hPreferred lifetime of a temporary address.
-tempaddr-valid24hUpper limit of the valid lifetime of a temporary address. An address still in use is kept up to this limit, an unused one is removed earlier.
-tempaddr-max8Maximum number of temporary addresses at once.
-tempaddr-desync10mUpper limit of the random offset applied to each rotation.
-tempaddr-skip-dadfalseSkip duplicate address detection. Only for links known to be free of conflicts.
-tempaddr-drain-grace5sInterval between the two checks that decide an address is no longer in use.

Tunnel

OptionDefaultDescription
-tunnel-devsixup-ipv4Name of the IPv4-in-IPv6 tunnel device. Once the tunnel parameters are known, sixup creates or updates it, brings it up and assigns the IPv4 address. Empty creates no device.
-tunnel-mtu0MTU of the tunnel device. 0 means the WAN interface MTU minus 40.
-tunnel-route4-metric4096Metric of the IPv4 default route through the tunnel. It is high on purpose: an existing IPv4 default route keeps winning, and the tunnel takes over only when there is none. 0 adds no route.
-tunnel-natautoMaintain the nftables table inet sixup for traffic leaving the tunnel. auto configures the port-restricted source NAT required on MAP-E (RFC 7597), an ordinary source NAT on a line with its own IPv4 address, and none on DS-Lite, where the provider translates; in every case it clamps the TCP MSS to the tunnel MTU. off writes no rules. Nothing outside the table is touched, and the table is removed on exit.
-tunnel-mape-rulestrueWhen DHCPv6 carries no MAP-E option, derive the MAP-E parameters from the delegated prefix using the rule tables of the Japanese IPoE providers (v6plus, BIGLOBE, OCN, NURO).
-tunnel-capturetrueWhen DHCPv6 carries no tunnel option, capture tunnel traffic to find the parameters. Needs -dhcp6c-mode other than off, and is not done in a dry run.
-tunnel-capture-max2mHow long the capture waits. It ends at the first tunnel packet; if none arrives, it gives up and tries again when the prefix or the address changes.

NAT64

OptionDefaultDescription
-nat64offjool configures NAT64 with the Jool kernel module (4.1 or later, loaded with modprobe jool): an instance translating 64:ff9b::/96, advertised in the RA, whose output goes through the source NAT above, so the ports of a MAP-E line have one owner. off configures none. DNS64 is left to a resolver of your choice.
-jool-instancesixupName of the Jool instance sixup creates and removes.
-jool-port-ranges3How many of the port ranges of a MAP-E line go to the translator; netfilter keeps the rest, and the two never hand out the same port. Ignored when the line owns every port of its address.

Runtime

OptionDefaultDescription
-state-dir/var/lib/sixupDirectory for the DUID, the secret behind the stable addresses, the ULA and the leases. Keep it across restarts, or the provider may hand out a different prefix.
-no-sysctlfalseLeave forwarding, accept_ra and the other sysctls alone, for setups that manage them elsewhere.
-settle1sHow long the parameters must stay unchanged before they are applied, so the RA, the delegated prefix, DNS and the capture result arriving one after another at startup are applied together. Withdrawals are applied at once.
-dry-runfalseGo through obtaining and renewing the parameters and finding the tunnel, printing as it goes, without changing the system or sending RAs to the LAN.
-dry-run-timeout0How long a dry run lasts. 0 runs until interrupted.
-log-levelinfoLowest level printed: debug, info, warn or error.
-vfalseSame as -log-level debug.
-versionPrint the version and exit.
-licensePrint the licence of sixup and of the work it derives from, and exit.
dhcpv6
ds-lite
golang
ipv6
linux
map-e
ndp-proxy
networking
router
v6plus

Contributors

lqs

22 commits

lqs/sixup

🌐 IPv6 router daemon for Linux, fully automatic. DHCPv6-PD, RA, DHCPv6 server, NDP proxy, DS-Lite/MAP-E tunnels. One static binary.

Go

0

22 commits

updated Sep 24, 2026

See the code

See what people are saying

README

sixup: IPv6 routing, fully automatic

English | 简体中文 | ę—„ęœ¬čŖž

CI License: MIT

In the past, setting up IPv6 routing on Linux took a number of programs. odhcp6c obtained the prefix, radvd sent the Router Advertisements, odhcpd served DHCPv6, ndppd proxied Neighbor Discovery, and a few scripts passed parameters between them and restarted whatever had to be restarted.

sixup does all of it in one program, the state and the parameters of each stage passing inside it rather than through scripts. When the line hands out a different prefix, the interface addresses, the Router Advertisements, the DHCPv6 leases, the proxy entries and the tunnel endpoints all follow from that one event. No manual step, no restart.

Features

  • Handles the whole job of an IPv6 router, with no other daemon to configure
  • Detects how the prefix arrives, DHCPv6-PD or an RA, and hands clients their addresses and configuration through its own RA and DHCPv6 services
  • When the ISP hands out a new prefix, addresses, RAs, leases, proxy entries and tunnel endpoints follow
  • Shares a single upstream /64 with the LAN as RFC 7278 prescribes, Neighbor Discovery proxy included, splits a shorter prefix across the segments
  • Builds a DS-Lite, MAP-E or IPIP6 tunnel as needed, and keeps MAP-E source ports inside the assigned port set
  • One static binary under 5 MiB, dependent on no external command and no system service

Quick start

[!WARNING] sixup is under development and has not been released yet. Parts of it have never run on a real line, so it may not work at all, and options change from one commit to the next.

Pick the package for your distribution (.deb, .rpm, .apk or Arch Linux .pkg.tar.zst) or a static binary from the releases page. There is no formal release yet, only the dev pre-release.

Check what the line provides, without changing anything:

sudo sixup -wan eth0 -dry-run

Obtain the prefix from the WAN interface and configure one LAN interface from it:

sudo sixup -wan eth0 -lan eth1

The prefix is obtained by whichever method the line supports. No further options are needed.

To divide a delegated prefix across several LAN segments, give each interface a subnet id:

sudo sixup -wan eth0 -lan eth1:0 -lan eth2:1

Note: a single /64 covers one LAN segment. On a line that delegates nothing, subnet id 0 gets the prefix and the other segments get none; give them a ULA with -lan-ula auto if they need to reach each other.

Note: on a MAP-E line the source port has to stay inside the port set the line was given, or return traffic never arrives. sixup maintains those nftables rules in a table of its own, inet sixup, removed when it exits. Pass -tunnel-nat off to write them yourself.

Options

[!WARNING] sixup has not been released yet, so options may be renamed or removed without notice.

sixup -h lists every option in the groups below.

  • A boolean option is turned off with =false, for example -wan-ra=false.
  • A duration takes Go syntax: 30s, 10m, 1h30m.
  • A repeatable option is given once per value: -lan eth1 -lan eth2.

Interfaces and prefixes

OptionDefaultDescription
-wanWAN interface. Required.
-lanLAN interface, repeatable, as name[:subnet-id]. The subnet id, in decimal, picks which /64 of the delegated prefix goes to this interface; without one, the interfaces take 0, 1, 2 in the order given. Several LAN interfaces need a delegated prefix.
-lan-ulaULA prefix advertised next to the global prefix. auto generates a random /48 and keeps it in the state directory; a prefix such as fd12:3456:789a::/48 is used as given. Comma separated for several.
-lan-iidInterface identifiers of the router's own addresses on each LAN prefix, comma separated, one address each, same syntax as -wan-iid. Empty means one RFC 7217 stable address.
-lan-deprecate-hold10mHow long a withdrawn prefix keeps being advertised with a preferred lifetime of 0, so clients stop using it.

WAN side: DHCPv6 client

OptionDefaultDescription
-dhcp6c-modeautoauto follows the M and O flags of the upstream RA, on always runs the client, off never does.
-dhcp6c-pd-len56Prefix length hinted when requesting a delegated prefix (IA_PD). 0 requests none.
-dhcp6c-ia-natrueAlso request an address for the WAN interface itself (IA_NA).
-dhcp6c-pd-grace10sHow long to wait for a delegated prefix after startup. Until then an RA prefix only serves the WAN side and is not handed to the LAN, so it never has to be withdrawn again.
-dhcp6c-releasefalseSend RELEASE on exit to give back the prefix and addresses. Off by default: the DUID is kept, so a restart renews the same prefix. A dry run always releases.

WAN side: upstream RA and addresses

OptionDefaultDescription
-wan-ratrueListen to upstream RAs as a second prefix source, and maintain the default route from them.
-wan-slaactrueConfigure SLAAC addresses on the WAN interface for RA prefixes with the A flag set.
-wan-iidInterface identifiers of the static SLAAC addresses on the WAN interface, comma separated, one address each. Each is stable or empty for an RFC 7217 stable address, eui64 to derive it from the MAC address, or a fixed suffix such as ::1 or ::1111:2222:3333:4444. The first one is reported as the WAN address.
-wan-tempaddrfalseAlso rotate temporary addresses on the WAN interface, following the -tempaddr-* options.
-wan-preferpdWhich prefix wins when both a delegated prefix and an RA prefix are available: pd or ra.
-wan-shared64lanLayout when the upstream gives only one /64. lan: the /64 goes to the LAN, and hosts on the WAN link get /128 routes (RFC 7278). wan: the /64 stays on the WAN, and each LAN host gets a /128 route. split: /128 routes on both sides; the router itself cannot reach a host it has not learned yet. The /128 routes are added as the NDP proxy finds the hosts.

LAN side: RA advertisement

OptionDefaultDescription
-ra-min3m20sMinimum interval between unsolicited RAs (MinRtrAdvInterval).
-ra-max10mMaximum interval between unsolicited RAs (MaxRtrAdvInterval).
-ra-lifetime30mRouter lifetime carried in the RA.
-ra-mtu0MTU advertised in the RA. 0 advertises the WAN path MTU when it is smaller than the LAN interface MTU, taken from the upstream RA or the WAN interface, so a PPPoE line with 1492 no longer depends on path MTU discovery.
-ra-dnsDNS servers to advertise instead of the upstream ones, comma separated. Also used by the DHCPv6 server.
-ra-pref64NAT64 prefix to advertise (RFC 8781), such as 64:ff9b::/96. Empty passes on the one from the upstream RA. The length must be 32, 40, 48, 56, 64 or 96.
-ra-routePrefix to advertise as a Route Information option, repeatable.

LAN side: DHCPv6 server

OptionDefaultDescription
-dhcp6s-modeoffstateless answers only with options such as DNS; stateful also assigns addresses; off runs no server. The RA flags follow this choice.
-dhcp6s-pool1000-ffffRange of interface identifiers to assign from, in hexadecimal, as the low 64 bits.
-dhcp6s-staticFixed assignment, repeatable: mac=<MAC>,addr=::100, or duid=<hex>,addr=2001:db8::5.
-dhcp6s-lease-preferred1hPreferred lifetime of an assigned address.
-dhcp6s-lease-valid2hValid lifetime of an assigned address.

NDP proxy

OptionDefaultDescription
-ndproxy-modeautoauto turns forward on when the prefix is a /64 and stays off otherwise. forward probes the other side before answering, in both directions, so hosts on the WAN link and on the LAN reach each other too. prefix answers every WAN solicitation for an address in the LAN prefix without probing. static only puts the -ndproxy-static entries into the kernel proxy table. off disables the proxy.
-ndproxy-staticAddress or prefix to proxy in static mode, repeatable.
-ndproxy-excludePrefix never proxied, repeatable.
-ndproxy-ttl30sHow long a learned proxy entry lives.

Local address rotation

These options govern the router's own addresses on the LAN, and on the WAN with -wan-tempaddr.

OptionDefaultDescription
-tempaddr-modeofftemporary and both add rotating temporary addresses (RFC 8981) next to the static ones; off and stable keep only the static addresses.
-tempaddr-regen1hHow often a new temporary address is created.
-tempaddr-preferred1hPreferred lifetime of a temporary address.
-tempaddr-valid24hUpper limit of the valid lifetime of a temporary address. An address still in use is kept up to this limit, an unused one is removed earlier.
-tempaddr-max8Maximum number of temporary addresses at once.
-tempaddr-desync10mUpper limit of the random offset applied to each rotation.
-tempaddr-skip-dadfalseSkip duplicate address detection. Only for links known to be free of conflicts.
-tempaddr-drain-grace5sInterval between the two checks that decide an address is no longer in use.

Tunnel

OptionDefaultDescription
-tunnel-devsixup-ipv4Name of the IPv4-in-IPv6 tunnel device. Once the tunnel parameters are known, sixup creates or updates it, brings it up and assigns the IPv4 address. Empty creates no device.
-tunnel-mtu0MTU of the tunnel device. 0 means the WAN interface MTU minus 40.
-tunnel-route4-metric4096Metric of the IPv4 default route through the tunnel. It is high on purpose: an existing IPv4 default route keeps winning, and the tunnel takes over only when there is none. 0 adds no route.
-tunnel-natautoMaintain the nftables table inet sixup for traffic leaving the tunnel. auto configures the port-restricted source NAT required on MAP-E (RFC 7597), an ordinary source NAT on a line with its own IPv4 address, and none on DS-Lite, where the provider translates; in every case it clamps the TCP MSS to the tunnel MTU. off writes no rules. Nothing outside the table is touched, and the table is removed on exit.
-tunnel-mape-rulestrueWhen DHCPv6 carries no MAP-E option, derive the MAP-E parameters from the delegated prefix using the rule tables of the Japanese IPoE providers (v6plus, BIGLOBE, OCN, NURO).
-tunnel-capturetrueWhen DHCPv6 carries no tunnel option, capture tunnel traffic to find the parameters. Needs -dhcp6c-mode other than off, and is not done in a dry run.
-tunnel-capture-max2mHow long the capture waits. It ends at the first tunnel packet; if none arrives, it gives up and tries again when the prefix or the address changes.

NAT64

OptionDefaultDescription
-nat64offjool configures NAT64 with the Jool kernel module (4.1 or later, loaded with modprobe jool): an instance translating 64:ff9b::/96, advertised in the RA, whose output goes through the source NAT above, so the ports of a MAP-E line have one owner. off configures none. DNS64 is left to a resolver of your choice.
-jool-instancesixupName of the Jool instance sixup creates and removes.
-jool-port-ranges3How many of the port ranges of a MAP-E line go to the translator; netfilter keeps the rest, and the two never hand out the same port. Ignored when the line owns every port of its address.

Runtime

OptionDefaultDescription
-state-dir/var/lib/sixupDirectory for the DUID, the secret behind the stable addresses, the ULA and the leases. Keep it across restarts, or the provider may hand out a different prefix.
-no-sysctlfalseLeave forwarding, accept_ra and the other sysctls alone, for setups that manage them elsewhere.
-settle1sHow long the parameters must stay unchanged before they are applied, so the RA, the delegated prefix, DNS and the capture result arriving one after another at startup are applied together. Withdrawals are applied at once.
-dry-runfalseGo through obtaining and renewing the parameters and finding the tunnel, printing as it goes, without changing the system or sending RAs to the LAN.
-dry-run-timeout0How long a dry run lasts. 0 runs until interrupted.
-log-levelinfoLowest level printed: debug, info, warn or error.
-vfalseSame as -log-level debug.
-versionPrint the version and exit.
-licensePrint the licence of sixup and of the work it derives from, and exit.
dhcpv6
ds-lite
golang
ipv6
linux
map-e
ndp-proxy
networking
router
v6plus

Contributors

lqs

22 commits

Languages

Go

97.2%

Shell

2.1%