Skip to content

Instantly share code, notes, and snippets.

@kroteau
Last active June 19, 2022 13:03
Show Gist options
  • Save kroteau/de05fa01c367a3329f85f99c0930e817 to your computer and use it in GitHub Desktop.
Save kroteau/de05fa01c367a3329f85f99c0930e817 to your computer and use it in GitHub Desktop.
Mikrotik DuckDns Updater w/IPv6 support
# inspired by https://github.com/beeyev/Mikrotik-Duckdns-Dynamic-IP-Updater
# DuckDNS Sub Domain
:local duckdnsSubDomain "CHANGEME"
# DuckDNS Token
:local duckdnsToken "CHANGEME"
# Online services which respond with your IPv4
:local ipv4detectList {"https://api4.my-ip.io/ip.txt"; "http://v4.ipv6-test.com/api/myip.php"}
# Online services which respond with your IPv6
:local ipv6detectList {"https://api6.my-ip.io/ip.txt"; "http://v6.ipv6-test.com/api/myip.php"}
#=============END OF CONFIG===============
:local previousIP; :local currentIP; :local currentIPv6; :local duckdnsFullDomain "$duckdnsSubDomain.duckdns.org";
# Function to resolve external IP using public web services
:local getip do={
# Parameters: 1 - list of urls
:local extIP;
:foreach url in=$1 do={
:do { :set extIP ([/tool fetch url=$url output=user as-value]->"data")} on-error={ :log error "DDNS: Service $url failed" };
if ( [:len "$extIP"]>0 ) do={ :return $extIP };
};
};
# Detect IPv6 (grab default route from ipv4 interface, search for a global ipv6 address on the same interface)
:local hasIPv6 ([:len [/ipv6 address find where interface=[/ip route get number=[/ip route find where dst-address="0.0.0.0/0" && active=yes ] gateway] global]] > 0);
# Resolve current DuckDNS subdomain ipv4 address since Mikrotik is limited on resolving ipv6
:do {:set previousIP [:resolve $duckdnsFullDomain]} on-error={ :log warning "DDNS: Could not resolve dns name $duckdnsFullDomain"};
# Detect router's public IPv4 address
:set currentIP [$getip $ipv4detectList];
# Detect router's public IPv6 address
if ($hasIPv6 = true) do={
:set currentIPv6 [$getip $ipv6detectList];
};
# Intentionally using put here instead of log debug, running the script from console/ssh outputs values w/o modifying the source
:put "DDNS: Resolved IPv4 ($previousIP), Detected IPv4 ($currentIP), HasIPv6 ($hasIPv6), Detected IPv6 ($currentIPv6)"
# Push DDNS update if IPv4 has changed
:if ($currentIP != $previousIP) do={
:local httpResponse; :local httpRequestUrl "https://www.duckdns.org/update\?domains=$duckdnsSubDomain&token=$duckdnsToken&verbose=true&ip=$currentIP";
# In case of IPv4&IPv6 update expand request url with ipv6 parameter and value
if ($hasIPv6 = true) do={
:set httpRequestUrl "$httpRequestUrl&ipv6=$currentIPv6"
};
:put "GET request: $httpRequestUrl"
# Make http request based on the settings
:do {:set httpResponse ([/tool fetch url=$httpRequestUrl output=user as-value]->"data")} on-error={ :log error "DDNS: request to duckdns server failed"};
# Log abnormal responses
:if ([:pick $httpResponse 0 2] != "OK") do={
:log warning "DDNS: abnormal response ($httpResponse)"
};
} else={ :put "DDNS: No update needed"};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment