Last active
April 23, 2021 15:24
-
-
Save v12/8892066 to your computer and use it in GitHub Desktop.
RouterOS (MikroTik) Yandex DNS subdomain A record updater.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
######## | |
# Name: yandex-ddns | |
# Author: v12 | |
# URL: https://gist.github.com/v12/8892066 | |
######## | |
### Settings section | |
# There is no way of getting token automatically via script, so you should get it manually: https://pddimp.yandex.ru/get_token.xml?domain_name=example.com | |
# More info: http://api.yandex.ru/pdd/doc/reference/api-dns_get_token.xml | |
:local apiToken "12345678910123456789101234567891012345678910123456789101234567" | |
# Your domain delegated to Yandex | |
:local YaDNSdomain "example.com" | |
# Subdomain which you're going to update (only subdomain, not the full hostname) | |
# If you want to update A record for subdomain.example.com, you should set this variable to "subdomain" | |
:local YaDNSsubdomain "subdomain" | |
:local YaDNSTTL "300" | |
# Interface which IP address will be used for update | |
:local interfaceName "ether1-gateway" | |
:local updateHost "pddimp.yandex.ru" | |
:local updateHostIp [ :resolve $updateHost ] | |
:local updateUrl "nsapi/" | |
:local updateQueryGeneral ( ".xml\?token=" . $apiToken . "&domain=" . $YaDNSdomain ) | |
:local updateQueryGeneralSub ( $updateQueryGeneral . "&subdomain=" . $YaDNSsubdomain ) | |
### Settings section END | |
:local findSubdomainEntry do={ | |
:local searchOffset 0 | |
:if ([:typeof $1] = "num") do={ :set searchOffset $1 } | |
:if ([:typeof $1] = "str") do={ :set searchOffset [ :tonum $1 ] } | |
:local searchEntrySubstr ( "<record domain=\"" . $subdomain . "." . $domain . "\"" ) | |
:local searchEntrySubstrPos [ :find $string $searchEntrySubstr $searchOffset ] | |
:if ([:typeof $searchEntrySubstrPos] != "num") do={ | |
:return false | |
} | |
:return [ :pick $string ($searchEntrySubstrPos + [ :len $searchEntrySubstr ] ) [ :find $string "</record>" $searchEntrySubstrPos ] ] | |
} | |
:log info "[Ya.DNS] Attempting to update A record for $YaDNSsubdomain.$YaDNSdomain" | |
:if ([ :len [ /interface find name=$interfaceName ] ] = 0 ) do={ | |
:log warning "[Ya.DNS] No interface '$interfaceName' was found, please do check updater script configuration." | |
:error "[Ya.DNS] No interface '$interfaceName' was found, please do check updater script configuration." | |
} | |
# Get current IP address for interface | |
:local currentInterfaceIp [ :tostr [ /ip address get [/ip address find interface=$interfaceName] address ] ] | |
:set currentInterfaceIp [ :pick $currentInterfaceIp 0 [ :find $currentInterfaceIp "/" ] ] | |
:if ([ :len $currentInterfaceIp ] = 0 ) do= { | |
:log info "[Ya.DNS] No IP address is assigned to the interface '$interfaceName'." | |
:error "[Ya.DNS] No IP address is assigned to the interface '$interfaceName'." | |
} | |
/tool fetch mode=https address=$updateHostIp host=$updateHost src-path=( $updateUrl . "get_domain_records" . $updateQueryGeneral ) dst-path="YaDNS.txt" | |
:local result [/file get YaDNS.txt contents] | |
# Checking whether request is successful or not | |
:local error [:pick $result ([:find $result "<error>"]+7) [:find $result "</error>"]] | |
:if ($error != "ok") do={ | |
:log warning "[Ya.DNS] Unable to get list of records for $YaDNSdomain ($error)" | |
:error "[Ya.DNS] Unable to get list of records for $YaDNSdomain ($error)" | |
} | |
# Searching an entry with the subdomain | |
:local aRecordEntry | |
:local doneSearchingEntry false | |
:local entrySearchLastResult | |
while (!$doneSearchingEntry) do={ | |
:set entrySearchLastResult [ $findSubdomainEntry subdomain=$YaDNSsubdomain domain=$YaDNSdomain string=$result ([ :find $result $entrySearchLastResult ] + 1) ] | |
:if ([:typeof $entrySearchLastResult] = "str") do={ | |
:local currentEntryTypeSearch "type=\"" | |
:local currentEntryTypePos ([ :find $entrySearchLastResult $currentEntryTypeSearch ] + [ :len $currentEntryTypeSearch ]) | |
:if ([ :pick $entrySearchLastResult $currentEntryTypePos [ :find $entrySearchLastResult "\"" $currentEntryTypePos ] ] = "A") do={ | |
:set aRecordEntry $entrySearchLastResult | |
:set doneSearchingEntry true | |
} | |
} else={ | |
:set doneSearchingEntry true | |
} | |
} | |
:local queryParams ( "&content=" . $currentInterfaceIp . "&ttl=" . $YaDNSTTL . "&subdomain=" . $YaDNSsubdomain ) | |
:local queryAction "add_a_record" | |
if ($doneSearchingEntry && ([ :typeof $aRecordEntry ] != "str")) do={ | |
# Create new entry | |
:log info "[Ya.DNS] Not found A entry for $YaDNSsubdomain.$YaDNSdomain. Attempting to create one." | |
:put "[Ya.DNS] Not found A entry for $YaDNSsubdomain.$YaDNSdomain. Attempting to create one." | |
} else={ | |
# Get the IP that is already assigned to the existing record | |
:local currentRecordIp [ :toip [ :pick $aRecordEntry ([ :find $aRecordEntry ">" ] + 1) [ :len $aRecordEntry ] ] ] | |
# Compare current IP on our interface with the IP in the record | |
:if ($currentRecordIp = $currentInterfaceIp) do={ | |
:log info "[Ya.DNS] IP address hasn't changed since last update. Terminating." | |
:error "[Ya.DNS] IP address hasn't changed since last update. Terminating." | |
} else={ | |
# Searching id of entry we found | |
:local recordIdSubstr "id=\"" | |
:local recordIdSubstrStart ( [ :find $aRecordEntry $recordIdSubstr ] + [ :len $recordIdSubstr ] ) | |
:local recordId [ :pick $aRecordEntry $recordIdSubstrStart [ :find $aRecordEntry "\"" $recordIdSubstrStart ] ] | |
:set queryAction "edit_a_record" | |
:set queryParams ( $queryParams . "&record_id=" . $recordId ) | |
} | |
} | |
/tool fetch \ | |
mode=https \ | |
address=$updateHostIp \ | |
host=$updateHost \ | |
src-path=( $updateUrl . $queryAction . $updateQueryGeneral . $queryParams ) \ | |
dst-path="YaDNS_2.txt" | |
:set result [/file get YaDNS_2.txt contents] | |
# Avoiding "no such item" bug: fetch result needs some time to be saved | |
:delay 1000ms | |
/file remove "YaDNS.txt" | |
/file remove "YaDNS_2.txt" | |
# Checking whether request is successful or not | |
:set error [:pick $result ([:find $result "<error>"]+7) [:find $result "</error>"]] | |
:if ($error != "ok") do={ | |
:log warning "[Ya.DNS] Unable to update record for $YaDNSsubdomain.$YaDNSdomain ($error)" | |
:error "[Ya.DNS] Unable to update record for $YaDNSsubdomain.$YaDNSdomain ($error)" | |
} | |
:log info "[Ya.DNS] Successfuly updated A record for $YaDNSsubdomain.$YaDNSdomain ($currentInterfaceIp)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment