345 lines
10 KiB
Text
Executable file
345 lines
10 KiB
Text
Executable file
#!rsc by RouterOS
|
|
# DNSDrone for Mikrotik - DNS Record Updater for FreeIPA
|
|
|
|
# This script:
|
|
# 1. Consolidates all configuration into a single CONFIG dictionary
|
|
# 2. Includes a function for making FreeIPA API calls
|
|
# 3. Gets current IP addresses from DHCP clients
|
|
# 4. Compares with existing DNS records
|
|
# 5. Updates records only when they differ
|
|
# 6. Handles both IPv4 and IPv6 records
|
|
# 7. Updates the prefix TXT record
|
|
#
|
|
# To use this:
|
|
# 1. Replace the configuration values in the CONFIG dictionary
|
|
# 2. Save it as a script in your Mikrotik router
|
|
# 3. Schedule it to run periodically or trigger it manually
|
|
#
|
|
# Note: You might need to adjust the HTTP headers and API calls based on your specific FreeIPA version and requirements. Also, ensure your Mikrotik router has proper SSL/TLS # certificates installed for HTTPS communication with the FreeIPA server.
|
|
|
|
# Configuration Variables
|
|
:local CONFIG {
|
|
"wanInterface"="VLAN666_Altibox";
|
|
"IpaServer"="ipa.demo1.freeipa.org";
|
|
"dnsZone"="demo1.freeipa.org";
|
|
"IpaUser"="admin";
|
|
"IpaPassword"="Secret123";
|
|
"apiVersion"="2.253";
|
|
"recordTTL"="300";
|
|
|
|
# Curlproxy
|
|
"curlproxyserver"="pubdns.dmz.skyfritt.net";
|
|
"curlproxyuser"="curluser";
|
|
"cookiefile"="cookie_output.txt";
|
|
|
|
# Record Names (without zone)
|
|
"dualStackName"="tik-test";
|
|
"ipv4OnlyName"="tik-test-v4";
|
|
"ipv6OnlyName"="tik-test-v6";
|
|
"prefixTxtName"="tik-test-prefix";
|
|
|
|
# Resolver Config
|
|
"DNSserver"="ipa.demo1.freeipa.org";
|
|
"DoHserver"="one.one.one.one";
|
|
|
|
# Script options (true/false)
|
|
"debug"="true"
|
|
|
|
}
|
|
|
|
# Functions:
|
|
|
|
:local GetIPACookie do={
|
|
|
|
# Import config
|
|
:local CONFIG $1;
|
|
|
|
# Save Cookie-information in tempoary local file via ugly ssh hack
|
|
|
|
/system ssh "$($CONFIG->"curlproxyserver")" user="$($CONFIG->"curlproxyuser")" \
|
|
command="curl -s -k -i -H 'Accept: text/plain' \
|
|
-H 'Content-Type: application/x-www-form-urlencoded' \
|
|
-H 'Referer: https://$($CONFIG->"IpaServer")/ipa' \
|
|
-H 'X-IPA-API-Version: $($CONFIG->"apiVersion")' \
|
|
--data-urlencode 'user=$($CONFIG->"IpaUser")' \
|
|
--data-urlencode 'password=$($CONFIG->"IpaPassword")' \
|
|
'https://$($CONFIG->"IpaServer")/ipa/session/login_password'" \
|
|
output-to-file="$($CONFIG->"cookiefile")"
|
|
|
|
# Needs time to save the cookiefile
|
|
|
|
/delay 2s
|
|
|
|
# Extract cookie-information from temporary filr
|
|
|
|
|
|
:local cookie;
|
|
:local fileContents [/file get "$($CONFIG->"cookiefile")" contents]
|
|
|
|
:local startIndex [:find $fileContents "Set-Cookie: ipa_session="]
|
|
:if ($startIndex != -1) do={
|
|
:set startIndex ($startIndex + 12)
|
|
|
|
:local endIndex [:find $fileContents "\n" $startIndex]
|
|
:if ($endIndex = -1) do={
|
|
:set endIndex [:len $fileContents]
|
|
}
|
|
|
|
:set cookie [:pick $fileContents $startIndex $endIndex]
|
|
}
|
|
|
|
# Cleaning up the cookiefile
|
|
/file remove "$($CONFIG->"cookiefile")"
|
|
|
|
:put "DEBUG (function: GetIPACookie):;
|
|
:put Ipakjeks: $cookie";
|
|
|
|
# Output
|
|
:return "$cookie";
|
|
|
|
}
|
|
|
|
|
|
:local GetLocalDynamicConfig do={
|
|
|
|
# Import config
|
|
:local CONFIG $1;
|
|
|
|
# Valid options: ipv4address, ipv6address, ipv6prefix
|
|
:local ConfigType $2;
|
|
|
|
# result variable
|
|
:local resultRAW;
|
|
:local resultClean;
|
|
|
|
:if ($ConfigType = "ipv4address" ) do={
|
|
|
|
# Retrive information
|
|
:set resultRAW [/ip dhcp-client get [/ip dhcp-client find interface="$($CONFIG->"wanInterface")"] address];
|
|
|
|
|
|
# Clean information
|
|
:set resultClean [:pick "$resultRAW" 0 [:find "$resultRAW" "/"]];
|
|
|
|
# :put "DEBUG: resultClean: $resultClean";
|
|
|
|
|
|
}
|
|
|
|
:if ($ConfigType = "ipv6address") do={
|
|
|
|
# Retrive information
|
|
:set resultRAW [/ipv6 dhcp-client get [/ipv6 dhcp-client find interface="$($CONFIG->"wanInterface")"] address];
|
|
|
|
# Clean information
|
|
:set resultClean [:pick "$resultRAW" 0 [:find "$resultRAW" ","]];
|
|
|
|
# :put "DEBUG: resultClean: $resultClean";
|
|
|
|
}
|
|
|
|
:if ($ConfigType = "ipv6prefix") do={
|
|
|
|
# Retrive information
|
|
:set resultRAW [/ipv6 dhcp-client get [/ipv6 dhcp-client find interface="$($CONFIG->"wanInterface")"] prefix];
|
|
|
|
# Clean information
|
|
:set resultClean [:pick "$resultRAW" 0 [:find "$resultRAW" ","]];
|
|
|
|
# :put "DEBUG: resultClean: $resultClean";
|
|
|
|
}
|
|
|
|
# Output
|
|
:return "$resultClean";
|
|
|
|
}
|
|
|
|
|
|
:local GetDynamicDNSRecords do={
|
|
|
|
# Import config
|
|
:local CONFIG $1;
|
|
|
|
# Valid options: ipv4address, ipv6address, ipv6prefix
|
|
:local ConfigType $2;
|
|
|
|
# Record name
|
|
:local RecordName $3;
|
|
|
|
# result variable
|
|
:local resultRAW;
|
|
:local resultClean;
|
|
|
|
:if ($ConfigType = "ipv4address" ) do={
|
|
|
|
# Retrive information
|
|
:set resultRAW [/resolve "$RecordName" server="$($CONFIG->"DNSserver")" type=ipv4]
|
|
|
|
# Clean information
|
|
:set resultClean "$resultRAW";
|
|
|
|
# :put "DEBUG: resultClean: $resultClean";
|
|
|
|
}
|
|
|
|
:if ($ConfigType = "ipv6address" ) do={
|
|
|
|
# Retrive information
|
|
:set resultRAW [/resolve "$RecordName" server="$($CONFIG->"DNSserver")" type=ipv6]
|
|
|
|
# Clean information
|
|
:set resultClean "$resultRAW";
|
|
|
|
# :put "DEBUG: resultClean: $resultClean";
|
|
|
|
}
|
|
|
|
|
|
:if ($ConfigType = "ipv6prefix") do={
|
|
|
|
# Fetch prefix TXT-record via DoH server:
|
|
:set resultRAW [/tool fetch url="https://$($CONFIG->"DoHserver")/dns-query?name=$RecordName&type=TXT" http-method=get output=user http-header-field="accept: application/dns-json" as-value];
|
|
|
|
# :put "DEBUG: resultRAW: $resultRAW";
|
|
|
|
# Get just the data content
|
|
:local resultJSON ($resultRAW -> "data");
|
|
|
|
# :put "DEBUG: resultJSON: $resultJSON";
|
|
|
|
# Extracting TXT-record-data
|
|
:local startIndex [:find $resultJSON "data\":\"" 0];
|
|
:local startPos ($startIndex + 7);
|
|
:local endIndex [:find $resultJSON "\"}" $startPos];
|
|
:local resultTXT [:pick $resultJSON $startPos $endIndex];
|
|
|
|
# Cleaning the prefix-variable (remove escaped double quotes)
|
|
:set resultClean [:pick $resultTXT 2 ([:len $resultTXT] - 2)];
|
|
|
|
# :put "DEBUG: resultClean: $resultClean";
|
|
|
|
}
|
|
|
|
# Output
|
|
:return "$resultClean";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:local UpdateDynamicDNSRecord do={
|
|
|
|
# Import config
|
|
:local CONFIG $1;
|
|
|
|
# Import IPACookie
|
|
:local IPACookie $2;
|
|
|
|
# Valid options: ipv4address, ipv6address, ipv6prefix
|
|
:local ConfigType $3;
|
|
|
|
# Record name
|
|
:local RecordName $4;
|
|
|
|
# Record content
|
|
:local RecordContent $5;
|
|
|
|
# result variable
|
|
:local resultRAW;
|
|
:local resultClean;
|
|
|
|
put "DEBUG: IPACookie: $IPACookie";
|
|
put "DEBUG: ConfigType: $ConfigType";
|
|
put "DEBUG: RecordName: $RecordName";
|
|
put "DEBUG: RecordContent: $RecordContent";
|
|
|
|
:if ($ConfigType = "ipv4address" ) do={
|
|
|
|
# Construct valid json-data:
|
|
# :local httpheader "\"Accept: application/json,Content-Type: application/json, Referer: https://$($CONFIG->"IpaServer")/ipa, X-IPA-API-Version: $($CONFIG->"apiVersion"), Cookie: $IPACookie \"\"";
|
|
:local httpdata "{\"method\":\"dnsrecord_mod\",\"params\":[[\"$($CONFIG->"dnsZone")\",\"$RecordName.\"],{\"arecord\":\"$RecordContent\",\"dnsttl\":$($CONFIG->"recordTTL")}]}";
|
|
|
|
:local IPACookieData "$cookie";
|
|
# :local IPACookieData "ipa_session=MagBearerToken=4ZTumSEI1zR%2fcPkbvlzM2lkT7CR9ojGOsvOzji0MO8ee61xUjZqXX3Ecs9n1FCHl0Vyn1U0EEooAAQk2DZ9GWT1Wt43Zx06sqDjDd5Ku8OJMa0W5SzkQuIQs%2f2hqkFoREevjwefgXurIlSxvDyVofXzJM726ZUAZsGICL9UawnWmo%2f7IVIqPRnNkb5g2NeMJKgThT0xuJ1G4nRY8w0CuIJV%2fJnVk9%2fjK%2bg%2bEjxhE3Lo%3d;path=/ipa;httponly;secure;";
|
|
|
|
|
|
put "DEBUG: (NEW)IPACookie = $IPACookie";
|
|
put "DEBUG: IPACookieData = $IPACookieData";
|
|
put "DEBUG: http-data=$httpdata";
|
|
|
|
/tool fetch url="https://$($CONFIG->"IpaServer")/ipa/session/json" \
|
|
http-method=post \
|
|
http-header-field="Accept: application/json,Content-Type: application/json,\
|
|
Referer: https://$($CONFIG->"IpaServer")/ipa,\
|
|
X-IPA-API-Version: $($CONFIG->"apiVersion"),\
|
|
Cookie: $IPACookieData" \
|
|
http-data="$httpdata" \
|
|
keep-result=no
|
|
|
|
# http-data="{\"method\":\"dnsrecord_mod\",\"params\":[[\"$($CONFIG->"dnsZone")\",\"$RecordName.\"],{\"arecord\":\"$RecordContent\",\"dnsttl\":$($CONFIG->"recordTTL")}]}" \
|
|
# Cookie: $IPACookie" \
|
|
|
|
}
|
|
|
|
|
|
# Output
|
|
:return "$resultClean";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Main Runtime
|
|
|
|
#:local IPACookie "drytest";
|
|
:local IPACookie [$GetIPACookie $CONFIG];
|
|
:put "DEBUG: IPACookie: $IPACookie";
|
|
|
|
:local CurrentIPv4address [$GetLocalDynamicConfig $CONFIG ipv4address];
|
|
:put "DEBUG CurrentIPv4address: $CurrentIPv4address";
|
|
|
|
:local CurrentIPv6address [$GetLocalDynamicConfig $CONFIG ipv6address];
|
|
:put "DEBUG: CurrentIPV6address: $CurrentIPv6address";
|
|
|
|
:local CurrentIPv6prefix [$GetLocalDynamicConfig $CONFIG ipv6prefix];
|
|
:put "DEBUG: CurrentIPv6prefix: $CurrentIPv6prefix";
|
|
|
|
|
|
|
|
|
|
# "$($CONFIG->"dualStackName").$($CONFIG->"dnsZone")"
|
|
|
|
:local CurrentDualStackRecordName "$($CONFIG->"dualStackName").$($CONFIG->"dnsZone")";
|
|
:local CurrentSingleStackIPv4RecordName "$($CONFIG->"ipv4OnlyName").$($CONFIG->"dnsZone")";
|
|
:local CurrentSingleStackIPv6RecordName "$($CONFIG->"ipv6OnlyName").$($CONFIG->"dnsZone")";
|
|
:local CurrentTXTRecordIPv6PrefixName "$($CONFIG->"prefixTxtName").$($CONFIG->"dnsZone")";
|
|
|
|
:local CurrentDualStackRecordv4 [$GetDynamicDNSRecords $CONFIG ipv4address $CurrentDualStackRecordName ];
|
|
:put "DEBUG: Dual-stack: $CurrentDualStackRecordName ipv4-resolves as $CurrentDualStackRecordv4";
|
|
|
|
:local CurrentDualStackRecordv6 [$GetDynamicDNSRecords $CONFIG ipv6address $CurrentDualStackRecordName ];
|
|
:put "DEBUG: Dual-stack: $CurrentDualStackRecordName ipv6-resolves as $CurrentDualStackRecordv6";
|
|
|
|
:local CurrentSingleStackRecordv4 [$GetDynamicDNSRecords $CONFIG ipv4address $CurrentSingleStackIPv4RecordName ];
|
|
:put "DEBUG: Single-stack-IPv4: $CurrentSingleStackIPv4RecordName ipv4-resolves as $CurrentSingleStackRecordv4";
|
|
|
|
:local CurrentSingleStackRecordv6 [$GetDynamicDNSRecords $CONFIG ipv6address $CurrentSingleStackIPv6RecordName ];
|
|
:put "DEBUG: Single-stack-IPv6: $CurrentSingleStackIPv6RecordName ipv6-resolves as $CurrentSingleStackRecordv6";
|
|
|
|
:local CurrentTXTRecordIPv6Prefix [$GetDynamicDNSRecords $CONFIG ipv6prefix $CurrentTXTRecordIPv6PrefixName ];
|
|
:put "DEBUG: $CurrentTXTRecordIPv6PrefixName resolves as $CurrentTXTRecordIPv6Prefix";
|
|
|
|
:local DebugUpdate [$UpdateDynamicDNSRecord $CONFIG $IPACookie ipv4address $CurrentSingleStackIPv4RecordName $CurrentIPv4address ];
|
|
:put "DEBUG: $DebugUpdate";
|
|
|