Community discussions

MikroTik App
 
hapoo
Frequent Visitor
Frequent Visitor
Topic Author
Posts: 64
Joined: Wed Apr 24, 2019 1:35 am

Sync DHCP and DNS to Cloudflare

Sun Jun 23, 2024 6:53 pm

Hi everyone,

I've been using this for a while. Hopefully someone else finds it useful too. It's not very elegant, but it gets the job done.
On my internal network I prefer to assign domain names to important devices, and because I don't always use mikrotik as the default DNS server (eg I'm on vpn), I sync everything to Cloudflare.
It's two scripts. One copies DHCP entries to static DNS based on comments, and the second script copies static DNS entries to Cloudflare DNS.

DHCP_to_DNS script. This expects you to have the desired domain name as the first thing in the comment section of the DHCP entry, afterwards you can type anything.
So something like "printer.example.com This is my printer". Just change the domain variable to your domain.
:local domain "example.com"

:foreach k in=[/ip dhcp-server lease find] do={
	:local leaseComment [/ip dhcp-server lease get $k comment]
	:if ( $leaseComment ~$domain) do={
		:local cleanDomain  ([:pick $leaseComment 0 [:find $leaseComment "."]].".".$domain)
		:put $cleanDomain
		:local dhcpAddress [/ip dhcp-server lease get $k address]
		:if ([/ip dns static find name=$cleanDomain] = "") do={
			:put "not found $cleanDomain"
			/ip dns static add name=$cleanDomain address=$dhcpAddress
		} else={
			:put "found $cleanDomain"
			/ip dns static set [find name=$cleanDomain] address=$dhcpAddress
		}
	}
}
DNS_to_CF script. This copies all specified domains to your Cloudflare account. It relies on JParseFunctions https://raw.githubusercontent.com/Winan ... eFunctions, so you should have a copy of it.
Simply enter your api key, zone id and domain. If the entry exists on CF, it will change it. If it doesn't exits, it will create a new entry for it.
:local apiToken "<enter api key>"
:local zoneId "<enter zone id>"
:local cfIP 0
:local url 0
:local domain "example.com"

/system script run "JParseFunctions"; global JSONLoad; global JSONLoads; global JSONUnload

:foreach k in=[/ip dns static find] do={
	:local dnsName [/ip dns static get $k name]
	:if ( $dnsName ~$domain) do={
		:local dnsIP [/ip dns static get $k address]

		#lookup domain ip online
		:do {
			:set cfIP [:resolve $dnsName server=1.1.1.1];
		} on-error={
			:log info "$dnsName not found";
			:set cfIP "0";}

		#check if record doesn't match local dns
		:if (($cfIP != "0") && ($cfIP != $dnsIP)) do={

				#get record ID for domain
				:set url "https://api.cloudflare.com/client/v4/zones/$zoneId/dns_records?type=A&name=$dnsName";
				:global cfresult [/tool fetch url=$url http-method=get  as-value output=user http-header-field=("authorization: Bearer " . $apiToken . ", content-type: application/json")];
				:global dnsRecordId ([$JSONLoads ($cfresult->"data")]->"result"->0->"id")

				#if entry not found, make one
				:if ( [:len $dnsRecordId] < 5) do={
					:log info "$dnsName not found";
					:set url "https://api.cloudflare.com/client/v4/zones/$zoneId/dns_records"
					:local newId [/certificate scep-server otp generate minutes-valid=0 as-value;]
					/tool fetch url=$url http-method=post  as-value output=user http-header-field=("authorization: Bearer " . $apiToken . ", content-type: application/json") http-data=("{\"content\":\"".$dnsIP."\",\"name\":\"".$dnsName."\",\"type\":\"A\",\"id\":\"".$newId->"password"."\",\"proxied\":false}") 

				#if entry is found update it
				} else={
					:log info "$dnsName updating";
					:set url "https://api.cloudflare.com/client/v4/zones/$zoneId/dns_records/$dnsRecordId"
					/tool fetch url=$url http-method=put  as-value output=user http-header-field=("authorization: Bearer " . $apiToken . ", content-type: application/json") http-data=("{\"content\":\"".$dnsIP."\",\"name\":\"".$dnsName."\",\"type\":\"A\",\"id\":\"".$dnsRecordId."\",\"proxied\":false}")
				}
				:set cfresult
				:set dnsRecordId
		}
	}
}

$JSONUnload