Skip to content

Instantly share code, notes, and snippets.

@zajdee
Last active December 14, 2025 09:28
Show Gist options
  • Select an option

  • Save zajdee/cf91124c8d8a4f05573b943024562fd0 to your computer and use it in GitHub Desktop.

Select an option

Save zajdee/cf91124c8d8a4f05573b943024562fd0 to your computer and use it in GitHub Desktop.
Mikrotik DS-Lite integration script and guide
# 1. Create an `aftr` option in the DHCPv6 Client->Client options
# - Comment: aftr
# - Name: aftr
# - Code: 64
# - Value: (empty)
# 2. Add the new `aftr` option to the DHCPv6 Client->interface configuration
# 3. Add this script to the DHCPv6 Client Script
# TODO: Create a firewall rule
# /ipv6 firewall filter
# add action=accept chain=input comment=dslite protocol=ipencap src-address=<aftr-ip>/128
# or a simplified (but slightly insecure) version:
# add action=accept chain=input comment=dslite protocol=ipencap
# 4. Renew the DHCP lease, the AFTR should be set as your IPIP6 Tunnel device's Remote address
# - The script will create a `dslite` interface, add an IPv4 to it, and set a (default) route
# Change the tunnel name and the WAN interface name here if you need to
:local tunName "dslite"
:local wanIf "wan"
# This route will be added via the DS-Lite tunnel.
# Set to 0.0.0.0/0 if you want to route all traffic that way
# Set to any other route if you want to
:local dstNet "0.0.0.0/0"
:global DecodeAFTR do={
:local string $1
:local reencoded
:local length
:local extract
:local i 0
:local strlength [:len $string]
# last character is a null character
:while (i < (strlength - 1)) do={
:set length [:convert [:pick $string $i] to=num]
:set extract [:pick $string ($i + 1) ($i + 1 + $length)];
:set i ($i + 1 + $length)
:set reencoded ($reencoded . $extract . ".")
}
if ([:len $reencoded] > 0) do={
# Remove the last dot at the end of the name. RouterOS doesn't like it.
:return [:pick $reencoded 0 ([:len $reencoded] - 1)]
} else={
# no data
:return $reencoded
}
}
:local naValid $"na-valid"
:local pdValid $"pd-valid"
# DS-Lite interface IP - do not change
:local ipCidr "192.0.0.2/29"
# only launch the script if we have received IA_NA or IA_PD
:if (($naValid = "1") || ($pdValid = "1")) do={
:local aftr [$DecodeAFTR ($options->"64")]
:if ([:typeof $aftr] = "nothing" || [:len $aftr] = 0) do={
:log warning "dhcpv6-aftr: AFTR option 64 not present in DHCPv6 reply"
} else={
:log debug "dhcpv6-aftr: AFTR: $aftr"
/interface ipipv6
:local tunId [find where name=$tunName]
:if ([:len $tunId] = 0) do={
:log error "dhcpv6-aftr: IPIP6 interface $tunName not found, adding"
/interface/ipipv6/add name=$tunName remote-address="3ffe::1" !keepalive comment="managed by dhcpv6-aftr"
:set tunId [find where name=$tunName]
}
:if ([:len [/ip/address/find where interface=$tunName and address=$ipCidr]] = 0) do={
:log warning "dhcpv6-aftr: Adding IP $ipCidr to interface $tunName"
/ip/address/add interface=$tunName address=$ipCidr comment="managed by dhcpv6-aftr"
} else={
:log info "dhcpv6-aftr: IP $ipCidr already set on interface $tunName"
}
:local wanMtu [/interface/get [find where name=$wanIf] mtu]
:local wantDsliteMtu ($wanMtu - 40)
:local dsliteMtu [/interface/get [find where name=$tunName] mtu]
:if ($dsliteMtu != $wantDsliteMtu) do={
/interface/set [find where name=$tunName] mtu=$wantDsliteMtu
:log warning "dhcpv6-aftr: Changing MTU on $tunName from $dsliteMtu to $wantDsliteMtu"
} else={
:log info "dhcpv6-aftr: MTU on $tunName already set to expected $wantDsliteMtu"
}
:if ([:len [/ip/route/find where dst-address=$dstNet and gateway=("%".$tunName)]] = 0) do={
/ip/route/add dst-address=$dstNet gateway=("%".$tunName) comment="managed by dhcpv6-aftr"
:log warning "dhcpv6-aftr: Setting route to $dstNet via %$tunName"
} else={
:log info "dhcpv6-aftr: Route to $dstNet via %$tunName already exists"
}
:local curRemote [get $tunId remote-address]
:log debug "tunName: $tunName, curRemote: $curRemote"
:if ($curRemote != $aftr) do={
:log warning "dhcpv6-aftr: updating $tunName remote-address from $curRemote to $aftr on device $tunName"
set $tunId remote-address=$aftr
} else={
:log info "dhcpv6-aftr: AFTR unchanged ($aftr)"
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment