Dyndns Netcup script

Hello,

can somone help me adjust the script?
I want a Script with Dyndns with netcup.
https://www.netcup-wiki.de/wiki/API_Clients#Dynamisches_DNS
https://github.com/hazzl/netcup-ddns

:global DOMAIN = "DOMAIN"
:global CUSTOMERNO = "NUMBER"
:global APIKEY = "KEY"
:global APIPASSWD = "APIPASS"

:global cjson = require "luci.jsonc"
:global https = require "ssl.https"
:global ltn12 = require "ltn12"
:global socket = require "socket"
:global http = socket.http

global function send_command(coms,ids)
	global postbod
	global resbod = {}
	global post = {}
	coms.param.apikey = APIKEY
	coms.param.customernumber = CUSTOMERNO
	if (ids) then
		coms.param.apisessionid = ids 
	end
	postbod = cjson.stringify(coms)
	post = { 
		method = "POST",
		url = "https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON",
		headers = {
			["content-length"] = tostring(#postbod)
		},
		source = ltn12.source.string(postbod),
		sink = ltn12.sink.table(resbod)}
	https.request(post)
	return cjson.parse(table.concat(resbod))
end

global function clear()
	global t = {}
	t.param = {}
	return t
end

global com, id, response, ip4, modified

response = {}
http.request{url = "http://v4.ident.me", sink = ltn12.sink.table(response)}
ip4=table.concat(response)
if ip4 == "" then -- something went terribly wrong. Give up.
	return
end

response = socket.dns.toip(DOMAIN)
if ip4 == response then 
	return
end
global logfile=io.open("ddns.log","a")
io.output(logfile)
io.write(os.date() .. " new IP " .. ip4 .. "\n")
	
com = clear()
com.action = "login"
com.param.apipassword = APIPASSWD
response = send_command(com,id)
id = response.responsedata.apisessionid

com = clear()
com.action = "infoDnsRecords"
com.param.domainname = DOMAIN
response = send_command(com,id)
modified = false
for _,v in pairs (response.responsedata.dnsrecords) do
	if v.type == "A" and v.hostname ~= "mail" and v.destination ~= ip4 then
		v.destination = ip4
		modified = true
	end
end

if modified then
	com = clear()
	com.action = "updateDnsRecords"
	com.param.domainname = DOMAIN
	com.param.dnsrecordset = response.responsedata
	response = send_command(com,id)
	print (response.longmessage)
else
	print ("all records up to date")
end

com = clear()
com.action = "logout"
response = send_command(com,id)
io.close(logfile)

That looks like LUA code! If you had a router that run it, you’d need to upgrade it ASAP anyway for security vulnerabilities.

They changed scripting languages at some point before my time (maybe V5). MT built there own scripting language to replace it, and that’s what’s been used for at 5+ years. But in V6 and V7 RouterOS, you can use use IP>Cloud to do DDNS, then your actual DNS domain add a CNAME to that.

Certainly it be possible to write a script to directly talk to your DDNS provider, but more complex solution. /ip/cloud with CNAME is pretty easy.

and where is the mistake here? Unfortunately, that doesn’t work either?


/system script
add name=Netcup
policy=read,write,test
:global apikey "KEY"
:global apipassword "PASSWORD"
:global customerid "CUSTOMERNR"
:global theinterface "WAN1"
:global ddnshost "subdomain.domain.de"
:global ipddns [:resolve $ddnshost];
:global ipfresh [ /ip address get [/ip address find interface=$theinterface ] address ]
:if ([ :typeof $ipfresh ] = nil ) do={
:log info ("NetcupDDNS: No IP address on $theinterface .")
} else={
:for i from=( [:len $ipfresh] - 1) to=0 do={
:if ( [:pick $ipfresh $i] = "/") do={
:set ipfresh [:pick $ipfresh 0 $i];
}
}
:if ($ipddns != $ipfresh) do={
:log info ("NetcupDDNS: IP-Netcup = $ipddns")
:log info ("NetcupDDNS: IP-Fresh = $ipfresh")
:log info "NetcupDDNS: Update IP needed, Sending UPDATE...!"
:global jsonRequestBody "{json request body with new IP and other necessary info}"
/tool fetch url="https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON" http-method=post http-data=$jsonRequestBody mode=https dst-path=("/Netcup.".$ddnshost)
:delay 1
:global str [/file find name="Netcup.$ddnshost"];
/file remove $str
:global ipddns $ipfresh
:log info "NetcupDDNS: IP updated to $ipfresh!"
} else={
:log info "NetcupDDNS: dont need changes";
} }

I cannot say whether that script work.

BUT that script adding code is wrong…

  • you need a source=“” around the around script to add it via CLI
  • it the lines need to be escaped…
  • a “command verb” like “add” and it’s arguments should be together (e.g. on the same line) too

It generally easier to use webfig or winbox to cut-and-paste a script into the “source” in the UI. At the command line, you need to deal with escaping and line continuations… And, if you cut-and-paste using UI, you can then do an “/system script export” via CLI which will show all the needed escaping to use elsewhere (e.g. what’s below).

So this:

/system script
add name=Netcup policy=read,write,test source=":global apikey \"KEY\"\r\
    \n:global apipassword \"PASSWORD\"\r\
    \n:global customerid \"CUSTOMERNR\"\r\
    \n:global theinterface \"WAN1\"\r\
    \n:global ddnshost \"subdomain.domain.de\"\r\
    \n:global ipddns [:resolve \$ddnshost];\r\
    \n:global ipfresh [ /ip address get [/ip address find interface=\$theinterface ] address ]\r\
    \n:if ([ :typeof \$ipfresh ] = nil ) do={\r\
    \n:log info (\"NetcupDDNS: No IP address on \$theinterface .\")\r\
    \n} else={\r\
    \n:for i from=( [:len \$ipfresh] - 1) to=0 do={\r\
    \n:if ( [:pick \$ipfresh \$i] = \"/\") do={\r\
    \n:set ipfresh [:pick \$ipfresh 0 \$i];\r\
    \n}\r\
    \n}\r\
    \n:if (\$ipddns != \$ipfresh) do={\r\
    \n:log info (\"NetcupDDNS: IP-Netcup = \$ipddns\")\r\
    \n:log info (\"NetcupDDNS: IP-Fresh = \$ipfresh\")\r\
    \n:log info \"NetcupDDNS: Update IP needed, Sending UPDATE...!\"\r\
    \n:global jsonRequestBody \"{json request body with new IP and other necessary info}\"\r\
    \n/tool fetch url=\"https://ccp.netcup.net/run/webservice/servers/endpoint.php\?JSON\" http-method=post http-data=\$jsonRequestBody mode=https dst-p\
    ath=(\"/Netcup.\".\$ddnshost)\r\
    \n:delay 1\r\
    \n:global str [/file find name=\"Netcup.\$ddnshost\"];\r\
    \n/file remove \$str\r\
    \n:global ipddns \$ipfresh\r\
    \n:log info \"NetcupDDNS: IP updated to \$ipfresh!\"\r\
    \n} else={\r\
    \n:log info \"NetcupDDNS: dont need changes\";\r\
    \n} }"

The script now runs without errors. But the IP address does not update.

Yeah the script has stuff like:

:global jsonRequestBody "{json request body with new IP and other necessary info}"

That won’t work either. I don’t know where you got that script from, but perhaps there was some help on configuring it for your provider… as seem some specific details need to provided in the script.

I kinda think using the built-in /ip/cloud DDNS support be best. Then add a CNAME in your Netcup domain configuration, that points to the Mikrotik cloud DNS name (e.g. .mynetname.com).

See https://help.mikrotik.com/docs/display/ROS/Cloud#Cloud-DDNS

Hi,
I have made a script for RouterOS with some help here in the forums.

Feel free to use it:
https://github.com/toscdesign/netcup-ddns-for-mikrotik