Skip to content

Instantly share code, notes, and snippets.

@xpwn3rx
Forked from bgrewell/he-ipv6-udm-pro.md
Last active December 30, 2025 19:44
Show Gist options
  • Select an option

  • Save xpwn3rx/6f92517567dca17206f2768cc6b36a71 to your computer and use it in GitHub Desktop.

Select an option

Save xpwn3rx/6f92517567dca17206f2768cc6b36a71 to your computer and use it in GitHub Desktop.
This gist explains how to set up IPv6 connectivity on your Ubiquiti UDM Pro or similar Ubiquiti devices using a Centurylink 6rd tunnel. Enable free IPv6 access to your network without relying on ISP support.

Forked from a lot of hard work done by Ben Grewell - Here: https://gist.github.com/bgrewell/faee67342085fb8fe98b446feeb10ced

Setup IPv6 Tunnel on Unifi Dream Machine Pro

This document has been updated based on setting this up for Centurylink 6RD IPv6

Setup Address Allocation

Run these commands from your UDM via SSH to obtain your IPv6 delegated prefix information for Centurylink:

LOCAL_IPv4=/sbin/ip route get 205.171.2.64 | awk -F"src " 'NR==1{split($2,a," ");print a[1]}'

CL_IPv6_ADDR=printf "2602:%02x:%02x%02x:%02x00::/56\n" $(echo $LOCAL_IPv4 | tr . ' ')

echo $CL_IPv6_ADDR

The output of this command will be your IPv6 delegated prefix.

Navigate to https://unifi.ui.com and go to your network management page. Navigate to Settings -> Networks and select the network you wish to enable IPv6 on such as Default then click on the IPv6 button.

  1. Select static for interface type
  2. Under Gateway IP/Subnet enter your Routed IPv6 Prefix from the command above - this needs to be updated each time your public IPv4 address changes, by hand - looking for a way to automate
  3. Under Advanced select manual
  4. Under Client Address Assignment select DHCPv6

The rest of the defaults should be fine. Note, you can only select down to 64 for delegation size inside the GUI. This is wrong but will work anyway, ignore the mismatch 56 vs 64

Unifi OS v4 - Configure Dream Machine Over SSH

Use the following instructions to setup an IPv6 tunnel with CenturyLink if you have version 4+ of Unifi OS running on your router. You will need the following information to setup the tunnel which you can get from your hurricane electric tunnel management page.

  • IPv4 Server Address
  • IPv4 Client Address
  • IPv6 Client Address
  1. Create the setup script in /persistent/system/setup-cl-ipv6.sh
#!/bin/bash

# Configuration Variables
TUNNEL_IFACE="cl-ipv6"
CL_IPv4="205.171.2.64"
LOCAL_IPv4=$(ip route get 8.8.8.8 | awk -F"src " 'NR==1{split($2,a," ");print a[1]}')
CL_IPv6_ADDR=$(printf "2602:%02x:%02x%02x:%02x00::/56\n" $(echo $IP | tr . ' '))
CHECK_INTERVAL=3600

# Function to check if the tunnel interface exists
interface_exists() {
    ip link show "$TUNNEL_IFACE" &> /dev/null
}

# Function to check if the interface is up
interface_is_up() {
    ip link show "$TUNNEL_IFACE" | grep -q "UP,LOWER_UP"
}

# Function to check if the IPv6 address is assigned
ipv6_addr_assigned() {
    ip -6 addr show dev "$TUNNEL_IFACE" | grep -q "$CL_IPv6_ADDR"
}

# Function to check if the default route exists
default_route_exists() {
    ip -6 route show default dev "$TUNNEL_IFACE" | grep -q "default"
}

# Function to set up the tunnel
setup_tunnel() {
    echo "$(date): Checking tunnel status..."

    # Add the IPv6 tunnel if it doesn't exist
    if ! interface_exists; then
        echo "$(date): Adding tunnel interface $TUNNEL_IFACE..."
        ip tunnel add "$TUNNEL_IFACE" mode sit remote "$CL_IPv4" local "$LOCAL_IPv4" ttl 255
    else
        echo "$(date): Tunnel interface $TUNNEL_IFACE already exists."
    fi

    # Bring the tunnel interface up if it's not already up
    if ! interface_is_up; then
        echo "$(date): Bringing up interface $TUNNEL_IFACE..."
        ip link set "$TUNNEL_IFACE" up
    else
        echo "$(date): Interface $TUNNEL_IFACE is already up."
    fi

    # Assign the IPv6 address if it's not already assigned
    if ! ipv6_addr_assigned; then
        echo "$(date): Assigning IPv6 address $CL_IPv6_ADDR to $TUNNEL_IFACE..."
        ip addr add "$CL_IPv6_ADDR" dev "$TUNNEL_IFACE"
    else
        echo "$(date): IPv6 address $CL_IPv6_ADDR is already assigned to $TUNNEL_IFACE."
    fi

    # Add the default IPv6 route if it doesn't exist
    if ! default_route_exists; then
        echo "$(date): Adding default IPv6 route via $TUNNEL_IFACE..."
        ip route add ::/0 dev "$TUNNEL_IFACE"
    else
        echo "$(date): Default IPv6 route via $TUNNEL_IFACE already exists."
    fi

    echo "$(date): Tunnel status check complete."
}

# Infinite loop to monitor and maintain the tunnel
while true; do
    setup_tunnel
    sleep "$CHECK_INTERVAL"
done

After you create the script make sure it's executable chmod +x /persistent/system/setup-cl-ipv6.sh

  1. Setup a systemd service to start the script on boot in /lib/systemd/system/cl-ipv6.service
[Unit]
Description=Set up Centurylink IPv6 tunnel after network is online
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/persistent/system/setup-cl-ipv6.sh
Restart=always
RestartSec=10
User=root

[Install]
WantedBy=multi-user.target
  1. Enable and Start the service
systemctl enable cl-ipv6.service
systemctl start cl-ipv6.service
  1. Ensure that the tunnel is functional by pinging Google’s IPv6 address - Note this took approximately 15 seconds after initial config to work
ping6 2001:4860:4860::8888
  1. You should be able to verify functionality by checking http://test-ipv6.com/index.html.en_US
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment