Community discussions

MikroTik App
 
RackKing
Member
Member
Posts: 380
Joined: Wed Oct 09, 2013 1:59 pm

Re: dynDNS Update Script

Wed Jul 29, 2015 2:52 pm

@gbr - thank you very much for posting this. I kind of works for me.... have a couple of questions. Note: I am a novice at scripting and still learning.

I have the script I provided working successfully on three routers.
Thanks very much GBR for the help and clarification.
 
Cormacs
newbie
Posts: 42
Joined: Sat Aug 29, 2015 2:27 am

Re: dynDNS Update Script

Thu Sep 10, 2015 4:42 am

I need some help. I have a dual PPPOE WAN set-up. I have modified a few scripts on here to make my own. I can't seem to find a proper dyndns script for a dual wan set-up. My one WAN I use to service all of my ports, my second WAN I would still like it's IP updated to a separate alias on DynDNS just for a just in case. Maybe my first WAN fails and I want to come in on the second one. None of the services are important to make an elaborate fail over system, I just want DynDNS to have both IP's. Here is what I got so far...

:local ddnsuser "******"
:local ddnspass "*******"
:local theinterface1 "********"
:local theinterface2 "*********"
:local ddnshost1 "**********"
:local ddnshost2 "*********"
:local ipddns1 [:resolve $ddnshost1];
:local ipddns2 [:resolve $ddnshost2];
:local ipfresh1 [ /ip address get [/ip address find interface=$theinterface1 ] address ]
:local ipfresh2 [ /ip address get [/ip address find interface=$theinterface2 ] address ]
:if ([ :typeof $ipfresh1 ] = nil ) do={
:log info ("DynDNS1: No ip address on $theinterface1 .")
} else={
:for i from=( [:len $ipfresh1] - 1) to=0 do={
:if ( [:pick $ipfresh1 $i] = "/") do={
:set ipfresh1 [:pick $ipfresh1 0 $i];
}
}

:if ($ipddns1 != $ipfresh1) do={
:log info ("DynDNS1: IP-DynDNS = $ipddns1")
:log info ("DynDNS1: IP-Fresh = $ipfresh1")
:log info "DynDNS1: Update IP needed, Sending UPDATE...!"
:local str "/nic/update?hostname=$ddnshost1&myip=$ipfresh1&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG"
/tool fetch address=members.dyndns.org src-path=$str mode=http user=$ddnsuser \
password=$ddnspass dst-path=("/DynDNS.".$ddnshost1)
:delay 1
:local str [/file find name="DynDNS.$ddnshost1"];
/file remove $str
:global ipddns1 $ipfresh1
:log info "DynDNS1: IP updated to $ipfresh1!"
} else={
:log info "DynDNS1: dont need changes";
}
}

:if ([ :typeof $ipfresh2 ] = nil ) do={
:log info ("DynDNS2: No ip address on $theinterface2 .")
} else={
:for i from=( [:len $ipfresh2] - 1) to=0 do={
:if ( [:pick $ipfresh2 $i] = "/") do={
:set ipfresh2 [:pick $ipfresh2 0 $i];
}
}

:if ($ipddns2 != $ipfresh2) do={
:log info ("DynDNS2: IP-DynDNS = $ipddns2")
:log info ("DynDNS2: IP-Fresh = $ipfresh2")
:log info "DynDNS2: Update IP needed, Sending UPDATE...!"
:local str "/nic/update?hostname=$ddnshost2&myip=$ipfresh2&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG"
/tool fetch address=members.dyndns.org src-path=$str mode=http user=$ddnsuser \
password=$ddnspass dst-path=("/DynDNS.".$ddnshost2)
:delay 1
:local str [/file find name="DynDNS.$ddnshost2"];
/file remove $str
:global ipddns2 $ipfresh2
:log info "DynDNS2: IP updated to $ipfresh2!"
} else={
:log info "DynDNS2: dont need changes";
}
}


So far it works great with one minor hiccup. One of the address' will always resolve incorrectly. Even though if I ping the address I get the proper IP back. Microtik always resolves the wrong address and thinks it requires an update. It is updating both address just find, I'm just worried DynDNS will black list me because of a minutely update. It always comes up...
DynDNS2: IP-DynDNS = old ip from a while ago
DynDNS2: IP-Fresh = Proper IP as obtained from the interface
Update require
continues to update.

The update process for both interfaces goes through without a problem and I can resolve the host no problem. Just for some reason the script doesn't resolve the ip properly and forces an unrequired update.
 
Cormacs
newbie
Posts: 42
Joined: Sat Aug 29, 2015 2:27 am

Re: dynDNS Update Script

Thu Sep 10, 2015 12:18 pm

It seems to have fixed itself overnight. Now it resolves both hosts no problem. I have been reading that these routers some times have issues with dns holding on to cached sites? Is this possible my issue?
 
Cormacs
newbie
Posts: 42
Joined: Sat Aug 29, 2015 2:27 am

dynDNS Update Script

Thu Sep 10, 2015 12:46 pm

I figured my own issue out. I realized I had the dyndns ttl set to 4 hours, so the router was holding on to the cached DNS value for 4 hours. I set it back done to 60 seconds, now it only does it for a max of 60 seconds.


Sent from my iPhone using Tapatalk
 
mike8itall
just joined
Posts: 2
Joined: Thu Dec 31, 2015 8:39 pm

Re: dynDNS Update Script

Thu Dec 31, 2015 9:09 pm

@gbr

Thanks a lot gbr. For others information, after going down the line and trying all the code in this thread, I was finally able to verify this code as working properly with RB2011UiAS v6.33.3 so far.



Edit: remove spurious blank lines introduced by cut'n'paste.

This was before I saw the email suggesting an increase in the delay.

This code is in production on two routers, one running 6.30.1 and on 6.30.
# Based on a script found on the Internet.Will add attribution if I find it.
# Changed 20150719 by Graeme Ruthven (graeme@kula.co.nz)
# Modified to:
# - update using authentication in URL as original method appeared to stop working.
#   This was about the time of the RouterOS 6.30 release, but may be unrelated.
# - Get the previous IP from the contents of the dyndns.txt file, as the global variable
#   doesn't appear to persist.
#
# Reference: https://help.dyn.com/remote-access-api/perform-update/

:local username "<dyn.com user name>"
:local password "<dyn.com password or, better, Updater Client Key>"
:local hostname "<dyn.com host name>"
:local emailAddress "<where to send notifications>"

:local url "dummy"
:local previousIP

:global dyndnsForce

:set dyndnsForce false

:log info ("UpdateDynDNS starts.")

# print some debug info
#:log info ("UpdateDynDNS: username = $username")
#:log info ("UpdateDynDNS: password = $password")
#:log info ("UpdateDynDNS: hostname = $hostname")
#:log info ("UpdateDynDNS: previousIP = $previousIP")

# I have some doubt over the persistence of the global previousIP.
# This value should be stored in /dyndns.txt after the last update attempt,
# preceded by the status and a space.
# For status values see: https://help.dyn.com/remote-access-api/return-codes/

:if ([:len [/file find name=dyndns.txt]] > 0) do={
   :local ipfile [/file get dyndns.txt contents]
   :local ipstart ([find $ipfile " " -1] + 1)
   :local ipend [:len $ipfile]
   :set previousIP [:pick $ipfile $ipstart $ipend]
} else={
   :set previousIP "0.0.0.0"
}

# get the current IP address from the internet (in case of double-nat)
/tool fetch mode=http address="checkip.dyn.com" src-path="/" dst-path="/dyndns.checkip.html"
:delay 1
:local result [/file get dyndns.checkip.html contents]

# parse the current IP result
:local resultLen [:len $result]
:local startLoc [:find $result ": " -1]
:set startLoc ($startLoc + 2)
:local endLoc [:find $result "</body>" -1]
:local currentIP [:pick $result $startLoc $endLoc]

# Remove the # on next line to force an update every single time - useful for debugging,
# but you could end up getting blacklisted by DynDNS!

#:set dyndnsForce true

# Determine if dyndns update is needed
# more dyndns updater request details http://www.dyndns.com/developers/specs/syntax.html

:if (($currentIP != $previousIP) || ($dyndnsForce = true)) do={
   :log info ("Changing IP from $previousIP to $currentIP.")
   :set dyndnsForce false
   :set url "http://$username:$password@members.dyndns.org/nic/update?hostname=$hostname&myip=$currentIP&wildcard=no"
   /tool fetch url=$url mode=http dst-path="/dyndns.txt"
  
# Original code:
#   /tool fetch user=$username password=$password mode=http address="members.dyndns.org" \
#      src-path="nic/update?system=dyndns&hostname=$hostname&myip=$currentIP&wildcard=no" \
#      dst-path="/dyndns.txt"

   :delay 1

 #  :set previousIP $currentIP

   :local result [/file get dyndns.txt contents]
   :log info ("UpdateDynDNS: Dyndns update needed")
   :log info ("UpdateDynDNS: Dyndns Update Result: ".$result)

# email result:
   :local output "DynDNS Update Result: $result"
   /tool e-mail send to="$emailAddress" subject="DynDNS update $currentTime" body="$output"
} else={
   :log info ("UpdateDynDNS: No dyndns update needed")
}
[/quote]
 
mike8itall
just joined
Posts: 2
Joined: Thu Dec 31, 2015 8:39 pm

Re: dynDNS Update Script

Thu Dec 31, 2015 10:14 pm

I have the RB2011UiAS running version 6.33.3, and I'm having issues getting the scheduler to run my dynDNS script.

I've seen a couple others having issues scheduling their script.
Mine won't work, and I don't think I can blame the scheduler.
When ran from the terminal, the feedback is "no such item"

I have my script named exactly "dynDNS"
I can run the script under the script configuration window in the script list, and it works properly.
It properly logs that it updated my DNS server, and it also shows successfully updated in my dyn.com account.

So the script is there. The file really does exist.
Does anybody know why I might get this result in the terminal?

[admin@MikroTik] > /system script run dynDns
no such item
[admin@MikroTik] >
 
iwancs
just joined
Posts: 3
Joined: Tue Feb 16, 2016 2:48 am

Re: dynDNS Update Script

Sat Apr 23, 2016 2:11 pm

If anyone still having problem updating dynDNS, here is a working code i've tried with some help of others in many forums and article, i've tried this on RouterBoard 750G r2 ver. 3.23

# Set needed variables
:local username "DYNDNSUSER"
:local password "DYNDNSPASSWORD"
:local hostname "DYNDNSHOSTNAME"
:local previousIP [:put [:resolve $hostname]];
:delay 1
:global dyndnsForce
:global previousIP

# print some debug info
:log info ("UpdateDynDNS: username = $username")
:log info ("UpdateDynDNS: password = $password")
:log info ("UpdateDynDNS: hostname = $hostname")
:log info ("UpdateDynDNS: previousIP = $previousIP")

# get the current IP address from the internet (in case of double-nat)
/tool fetch mode=http address="checkip.dyndns.org" src-path="/" dst-path="/dyndns.checkip.html"
:delay 1
:local result [/file get dyndns.checkip.html contents]

# parse the current IP result
:local resultLen [:len $result]
:local startLoc [:find $result ": " -1]
:set startLoc ($startLoc + 2)
:local endLoc [:find $result "</body>" -1]
:local currentIP [:pick $result $startLoc $endLoc]
:log info "UpdateDynDNS: currentIP = $currentIP"

# Remove the # on next line to force an update every single time - useful for debugging,
# but you could end up getting blacklisted by DynDNS!

#:set dyndnsForce true

# Determine if dyndns update is needed
# more dyndns updater request details http://www.dyndns.com/developers/specs/syntax.html

:if (($currentIP != $previousIP) || ($dyndnsForce = true)) do={
:set dyndnsForce false
:set previousIP $currentIP
:log info "$currentIP or $previousIP"
/tool fetch user=$username password=$password mode=http address="members.dyndns.org" \
src-path="nic/update?system=dyndns&hostname=$hostname&myip=$currentIP&wildcard=no" \
dst-path="/dyndns.txt"
:delay 1
:local result [/file get dyndns.txt contents]
:log info ("UpdateDynDNS: Dyndns update needed")
:log info ("UpdateDynDNS: Dyndns Update Result: ".$result)
:put ("Dyndns Update Result: ".$result)
} else={
:log info ("UpdateDynDNS: No dyndns update needed")
}
 
User avatar
anav
Forum Guru
Forum Guru
Posts: 19107
Joined: Sun Feb 18, 2018 11:28 pm
Location: Nova Scotia, Canada
Contact:

Re: dynDNS Update Script

Sun Mar 11, 2018 7:23 pm

I figured my own issue out. I realized I had the dyndns ttl set to 4 hours, so the router was holding on to the cached DNS value for 4 hours. I set it back done to 60 seconds, now it only does it for a max of 60 seconds.


Sent from my iPhone using Tapatalk
What does it mean dyndns ttl set to 4 hours?
I looked around WINBOX and could not find a dyndns ttl? Is this prior to 4.61 syntax?

By the way this chaps script (cormac) seemed decent for my situation dual wan.
My one concern is that I am not sure if the information being sent is encrypted or not and should I worry?
I am using the update key provided vice password.
 
zivtal
Frequent Visitor
Frequent Visitor
Posts: 57
Joined: Sun Feb 05, 2017 6:22 pm

Re: dynDNS Update Script

Tue Mar 20, 2018 12:52 pm

I have made this script ddns.rsc, It's allow you to use dynDNS or Dynu with several dynamic domains and via specific interface(s)...
:local ddns do={
	:local dynhost
	:local dynurlv

	:if (([:len $provider]=0) or ([:len $host]=0) or ([:len $username]=0) or ([:len $password]=0)) do={
		:error "missing parameters"
	}

	:if ($provider="dynu") do={
		:set dynhost "api.dynu.com"
		:set dynurlv "/nic/update?hostname=$host"
	}
	:if ($provider="dyndns") do={
		:set dynhost "members.dyndns.org"
		:set dynurlv "/nic/update?hostname=$host&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG"
	}
	:set dynhost [:resolve $dynhost];

   :local wanGateway do={
    	:if ([:len [/ip dhcp-client find where interface=[:tostr $1]]]>0) do={
    		:return [/ip dhcp-client get [find interface=[:tostr $1]] gateway]
    	} else={
    		:return [$1]
    	}
    }

	# All return codes
	:global resultcodes {
		good="Update successful";
    	nochg="Update not needed, WARNING: repeated attempts may cause you to be blocked.";
    	badauth="The username and password pair do not match a real user.";
    	notfqdn="The hostname specified is not a fully-qualified domain name.";
    	nohost="The hostname specified does not exist in this user account.";
    	numhost="Too many hosts (more than 20) specified in an update.";
    	abuse="The hostname specified is blocked for update abuse.";
    	badagent="The user agent was not sent or HTTP method is not permitted.";
    	dnserr="DNS error encountered.";
    	911="There is a problem or scheduled maintenance on our side."
	}

	:log info ("updating dynamic dns '$host' from '$provider' ...");
	:if (([:len [/interface find name=$interface]]>0) and ([/interface get value-name=disabled $interface]=no)) do={
		/ip route add distance=1 gateway=[$wanGateway $interface] dst-address=$dynhost comment="updating '$host' via '$interface'"
		:delay 800ms;
	}
	/tool fetch address=$dynhost src-path=$dynurlv mode=http user=$username password=$password dst-path=("$provider.$host")

	:delay 2s
	:if ([:len [/file find name=("$provider.$host")]]>0) do={
		:local result [/file get value-name=contents [/file find name=("$provider.$host")]]
		# Separate return code from IP address
		:for i from=0 to=( [:len $result] - 1) do={
			:if ( [:pick $result $i] = " ") do={
				:set result [:pick $result 0 $i]
			}
		}
		:foreach resultcode,desc in=$resultcodes do={
			:if ($result=$resultcode) do={
				:log warning ("$provider ($host): $desc")
			}
		}
	} else={
		:log error ("Update dynamic dns '".$host."' failed...");
	}
	/file remove [/file find name=("$provider.$host")]
	/ip route remove [/ip route find where comment="updating '$host' via '$interface'"]
}

:do {
	## Configuration file
	:local fconfig [:parse [/system script get "ddns.cfg" source]]
	:local cfg [$fconfig]
	:local HOSTS ($cfg->"hosts")
	:local ACCOUNTS ($cfg->"accounts")
	## Foreach HOSTS
	:foreach Host in=[:toarray $HOSTS] do={
		:local wan
		:local dynprov
		:local dynhost
		:local dynuser
		:local dynpass
		:if ([:len [:pick $Host (-1) ([:find $Host "|"])]]>0) do={
			:set wan [:pick $Host 0 ([:find $Host "|"])]
			:set dynprov [:pick $Host ([:find $Host "|"]+1) [:find $Host "@"]]
			:set dynhost [:pick $Host ([:find $Host "@"]+1) [:len $Host]]
		} else={
			:set dynprov [:pick $Host 0 [:find $Host "@"]]
			:set dynhost [:pick $Host ([:find $Host "@"]+1) [:len $Host]]
		}
		:if ([:len [:pick $ACCOUNTS (-1) ([:find $ACCOUNTS "|"])]]>0) do={
			:foreach account in=[:toarray $ACCOUNTS] do={
				:if ([:pick $account 0 [:find $account "|"]]=$dynprov) do={
					:set dynuser [:pick $account ([:find $account "|"]+1) [:find $account "@"]]
					:set dynpass [:pick $account ([:find $account "@"]+1) [:len $account]]
				}
			}
		} else={
			:set dynuser [:pick $ACCOUNTS 0 [:find $ACCOUNTS "@"]]
			:set dynpass [:pick $ACCOUNTS ([:find $ACCOUNTS "@"]+1) [:len $ACCOUNTS]]
		}
		:if ((([:len $interface]=0) and ([:len $wan]=0)) or ($wan=$interface)) do={
			$ddns provider=$dynprov host=$dynhost username=$dynuser password=$dynpass interface=$wan
		}
	}
}
Include configuration file ddns.cfg
:local config {
	"hosts"="dynu@YOURDOMAIN,dyndns@YOURDOMAIN,INTERFACE|dynu@YOURDOMAIN";
	"accounts"="dyndns|USERNAME@PASSWORD,dynu|USERNAME@PASSWORD";
	"storage"="";
}
return $config
If you using PPPOE or any PPP connection you can add script into PPP profile while connected and do like this for automatic update:
/interface pppoe-client monitor INTERFACE once do={
	:local uptime ([:tonum [:pick [:tostr $uptime] 0 2]]*60*60+[:tonum [:pick [:tostr $uptime] 3 5]]*60+[:tonum [:pick [:tostr $uptime] 6 8]])
}
:if ($uptime<3) do={
	/system script run ddns
}
My script post in here for any questions: viewtopic.php?f=9&t=130992&p=643242&hilit=dynu#p643242

Who is online

Users browsing this forum: Ahrefs [Bot], quanbau and 14 guests