Community discussions

MikroTik App
 
hobbes1069
newbie
Topic Author
Posts: 29
Joined: Sun Aug 16, 2015 3:43 pm

DynDNS script that works?

Thu Feb 08, 2018 10:44 pm

I've googled the heck out of this problem and none of the scripts I've found from the forums or the wiki seem to work. I've tried just about eveything I can think of and it seems no matter what I try the result is "404 Not Found" yet I've gotten curl and wget to work from my linux box.

My working theory is that it has to do with the Apache Basic authentication that members.dyndns.org uses.

Using wget I see it returns a 401 Unauthorized first but then wget picks up the Apache Basic authentication and tries again and it works. Using curl and specifying --basic also works.

Is it even possible to get the updating to work with /tool fetch?

Thanks,
Richard
 
zivtal
Frequent Visitor
Frequent Visitor
Posts: 57
Joined: Sun Feb 05, 2017 6:22 pm

Re: DynDNS script that works?

Fri Feb 09, 2018 10:42 pm

This is script that I made, Hope it will help you...
# Script name (must be same as you called the script)
:local ScriptName "dDNS"

# Define dynamic hosts [example 'INTERFACE|PROVAIDER@DYNAMICHOST' (via interface), example 'PROVAIDER@DYNAMICHOST' (via default gateway/interface)]
:local Hosts "dyndns@yourdomain.dyndns.net,dynu@yourdomain.dynu.net,lte1|dynu@yourdomain2.dynu.net"

# Define accounts [example 'provaider|username@password']
:local Accounts "dyndns|USERNAME@PASSWORD,dynu|USERNAME@PASSWORD"

:if ([:len [/system script job find script=$ScriptName]]>1) do={:error "Another copy of $ScriptName is running.";}

:global UpdateDNS do={
	:local wan $5;
	:local dynprov $1;
	:local dynaddr $2;
	:local dynuser $3;
	:local dynpass $4;
	:local dynhost;
	:local dynurlv;

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

	:if (([:len $dynprov]=0) && ([:len $dynaddr]=0) && ([:len $dynuser]=0) && ([:len $dynpass]=0)) do={
		:error "example: \$UpdateDNS <provaider> <domain> <username> <password> <interface>\r\n<provaider>	dyndns dynu\r\n<domain>	mydomain.dyndns.org\r\n<username>	your username\r\n<password>	your password\r\n<interface>	send update by another interface such lte1\r\n";
	} else={
		:if (([:len $dynprov]=0) || ([:len $dynhost]=0)) do={:error "Provaider wan't set or not supported\r\n"}
		:if ([:len $dynaddr]=0) do={:error "Dynamic domain was not set\r\n"}
		:if ([:len $dynuser]=0) do={:error "Username was not set\r\n"}
		:if ([:len $dynpass]=0) do={:error "Password was not set\r\n"}
	}

 	:local ReadFile do={
		:local dynfile $1;
		:local dynaddr [:pick $dynfile ([:find $dynfile "."]+1) [:len $dynfile]];
		:local dynprov [:pick $dynfile 0 [:find $dynfile "."]];
		:local ipaddr;
		:if ([:len [/file find name=$dynfile]]>0) do={
			:local dyndata [file get $dynfile contents];
			:if ($dynprov="dyndns") do={
				:set $ipaddr [:pick $dyndata ([:find $dyndata " "]+1) [:len $dyndata]];
			}
			:if ($dynprov="dynu") do={
				:set $ipaddr [:resolve $dynaddr];
			}
			:if ([:pick $dyndata [:find $dyndata "nochg"] 5]="nochg") do={
				:log info ("<$dynprov> '".$dynaddr."' already updated ($ipaddr) ...");
			} else={
				:log warning ("<$dynprov> '".$dynaddr."' updated ($ipaddr) ...");
			}
		} else={
			:set $ipaddr [:resolve $dynaddr];
			:log warning ("<$dynprov> '".$dynaddr."' has been set ($ipaddr) ...");
		}
		:return $ipaddr;
	}

	:set dynhost [:resolve $dynhost];

   :local WanToIp 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];
    	}
    }

	:local RunOnHostDown do={
		:if ($1!=false) do={
			:local ipaddr [:tostr $1];
			:local ondown [:tostr $2];
			:local wan [:tostr $3];
			:local desc [:tostr $4];
			# If host already not response set delay 10 minutes before run script
			:if ([/ping $ipaddr count=3]=0) do={
				:if ([:len $wan]>0) do={
					:if ([/interface get value-name=type $wan]="lte") do={
						/system routerboard usb power-reset duration=10s
					}
					:if ([:pick [/interface get value-name=type $wan] ([:find [/interface get value-name=type $wan] "-"]+1) [:len [/interface get value-name=type $wan]]]="out") do={
						/interface disable $wan;
						:delay 200ms;
						/interface enable $wan;
					}
				}
				:set $ondown ("/log error \"retry update dynamic dns in 10 minutes.\"\r\n/delay 10m\r\n".$ondown);
			}
			# Create netwatch per hosts, if not exists
			:if ([:len [/tool netwatch find where host=$ipaddr]]=0) do={
				/tool netwatch add host=$ipaddr down-script=$ondown
				/tool netwatch set down-script=("/tool netwatch remove ".[/tool netwatch find where host=$ipaddr]."\r\n\r\n".[/tool netwatch get value-name=down-script [/tool netwatch find where host=$ipaddr]]) [/tool netwatch find where host=$ipaddr]
				:log info ("'$ipaddr' netwatch has been created by script.");
			} else={
				# Set netwatch self remove, if not exists
				:if ([:typeof [:find [/tool netwatch get value-name="down-script" [/tool netwatch find host=$ipaddr]] ("/tool netwatch remove ".[/tool netwatch find where host=$ipaddr])]]="nil") do={
					/tool netwatch set down-script=("/tool netwatch remove ".[/tool netwatch find where host=$ipaddr]."\r\n".[/tool netwatch get value-name=down-script [/tool netwatch find where host=$ipaddr]]) [/tool netwatch find where host=$ipaddr]
				}
				# Set append on-down event (run script)
				:if ([:typeof [:find [/tool netwatch get value-name="down-script" [/tool netwatch find host=$ipaddr]] $ondown]]="nil") do={
					/tool netwatch set down-script=([/tool netwatch get value-name="down-script" [/tool netwatch find host=$ipaddr]].$ondown) [/tool netwatch find host=$ipaddr];
				}
			}
			# Set log 'error' when host is down
			:if ([:typeof [:find [/tool netwatch get value-name="down-script" [/tool netwatch find host=$ipaddr]] $desc]]="nil") do={
				/tool netwatch set down-script=(("/log error \"'$desc' was down.\"\r\n").[/tool netwatch get value-name="down-script" [/tool netwatch find host=$ipaddr]]) [/tool netwatch find host=$ipaddr];
			}
			:if ([:typeof [:find [/tool netwatch get value-name="comment" [/tool netwatch find host=$ipaddr]] $desc]]="nil") do={
				:if ([:len [/tool netwatch get value-name="comment" [/tool netwatch find host=$ipaddr]]]>0) do={
					/tool netwatch set comment=([/tool netwatch get value-name="comment" [/tool netwatch find host=$ipaddr]].", '$desc'") [/tool netwatch find host=$ipaddr]
				} else={
					/tool netwatch set comment=("watching for dynamic hosts '$desc'") [/tool netwatch find host=$ipaddr]
				}
			}
		}
	}

	:local AddSchedulerPerHost do={
		:local schname [:tostr $1];
		:local schcode [:tostr $2];
		:local schtime 3600;
		:if ([:len [/system scheduler find name=$schname]]=0) do={
			/system scheduler add interval=$schtime on-event=$schcode comment=("check dynamic dns proviaders for updates every ".($schtime/60)." minutes.") name=$schname
		} else={
			:if ([:typeof [:find [/system scheduler get value-name="on-event" [/system scheduler find where name=$schname]] $schcode]]="nil") do={
				/system scheduler set interval=$schtime on-event=([/system scheduler get value-name=on-event $schname].$schcode) [/system scheduler find where name=$schname]
			}
		}
	}

	:log info ("<$dynprov> Update '".$dynaddr."' ...");
	:if (([:len [/interface find name=$wan]]>0) && ([/interface get value-name=disabled $wan]=no)) do={
		/ip route add distance=1 gateway=[$WanToIp $wan] dst-address=$dynhost comment="updating '$dynaddr' via '$wan'"
		:delay 800ms;
	}
	/tool fetch address=$dynhost src-path=$dynurlv mode=http user=$dynuser password=$dynpass dst-path=("$dynprov.".$dynaddr)
	/ip route remove [/ip route find where comment="updating '$dynaddr' via '$wan'"]
	$RunOnHostDown [$ReadFile ("$dynprov.".$dynaddr)] ("/log error (\"<$dynprov> '$dynaddr' is offline (netwatch) ...\");\r\n\$UpdateDNS $dynprov $dynaddr $dynuser $dynpass $wan\r\n\r\n") $wan $dynaddr;
	$AddSchedulerPerHost "UpdateDNS" ("/log info (\"<$dynprov> Update '$dynaddr' by scheduler ...\");\r\n\$UpdateDNS $dynprov $dynaddr $dynuser $dynpass $wan\r\n\r\n");
}

:foreach Host in=[:toarray $Hosts] do={
	:local wan;
	:local dynprov;
	:local dynaddr;
	: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 dynaddr [:pick $Host ([:find $Host "@"]+1) [:len $Host]];
	} else={
		:set dynprov [:pick $Host 0 [:find $Host "@"]];
		:set dynaddr [: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]];
	}
	:put ("\$UpdateDNS $dynprov $dynaddr $dynuser $dynpass $wan");
	$UpdateDNS $dynprov $dynaddr $dynuser $dynpass $wan;
}
 
hobbes1069
newbie
Topic Author
Posts: 29
Joined: Sun Aug 16, 2015 3:43 pm

Re: DynDNS script that works?

Mon Feb 12, 2018 6:48 pm

I'm also trying to use the new URL method with https rather than http for two reasons, it uses a token instead of my actual password and it's encrypted...

I don't know why this didn't work from the script but by hand I finally found a method that works:
/tool fetch url="https://<user>:<token>@members.dyndns.org/v3/update?hostname=<hostname>&myip=<newip>"
Thanks,
Richard
 
hobbes1069
newbie
Topic Author
Posts: 29
Joined: Sun Aug 16, 2015 3:43 pm

Re: DynDNS script that works?

Wed Feb 14, 2018 11:14 pm

I've gotten it work EXCEPT I'm getting some kind of syntax error I can't track down in the last if/else statement...
### Settings ###
:global ddnsuser <username>
:global ddnstoken "<token>"
:global ddnshost <fqdn>
:global theinterface "<wan-interface>"

### Script Begins ###
:global ipfresh [ /ip address get [/ip address find interface=$theinterface ] address ]
:global ipddns [:resolve $ddnshost]

# All return codes from members.dyndns.org
:global resultcodes {good="Update successful";
    nochg="WARNING: Update not needed, 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."
}

# Check ip address and remove subnet.
:if ([ :typeof $ipfresh ] = nil ) do={
    :log info ("DynDNS: 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];
        }
    }
}

# Determine if an update is required.
:if ($ipddns != $ipfresh) do={
    :local logname "dyndns.$ddnshost"
    :log info ("DynDNS: IP-DynDNS = $ipddns")
    :log info ("DynDNS: IP-Fresh = $ipfresh")
    :log info "DynDNS: Update IP needed, saving UPDATE...!"
    /tool fetch url="https://$ddnsuser:$ddnstoken@members.dyndns.org/v3/update?hostname=$ddnshost&myip=$ipfresh" keep-result=yes dst-path=$logname;
    :local result [ /file get [ /file find name="$logname" ] contents ]
    /file remove [ /file get [ /file find name="$logname" ]
    :put "Server returned: $result";
    # 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]
        }
    }
    :put "Return code is: $result";
    :foreach resultcode,desc in=$resultcodes do={
        :if ( $result = $resultcode ) do={
        :log info ("DynDNS: $desc")
        }
    }
    :log info ("DynDNS: IP updated to $ipfresh!")
} else={
    :log info ("DynDNS: IP-DynDNS = $ipddns")
    :log info ("DynDNS: IP-Fresh = $ipfresh")
    :log info "DynDNS: no update required"
}
 
elgarchatuma
just joined
Posts: 2
Joined: Thu Apr 19, 2018 3:17 am

Re: DynDNS script that works?

Thu Apr 19, 2018 3:23 am

## This Scripts Works with my rb951G-2hnd.

# Set needed variables
:local username "escribe-tu-usuario-user"
:local password "put-password-here"
:local hostname "putyour-hostname-here.dlinkddns.com"
:global systemname [/system identity get name]


:if ($systemname = "Site1" ) do= {
:set hostname "yourdomain1.dyndns.org"
}
:if ($systemname = "Site2" ) do= {
:set hostname "yourdomain2.dyndns.org"
}
:if ($systemname = "Site3" ) do= {
:set hostname "yourdomain3.dyndns.org"
}


: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"
: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 available at Perform Update - Dyn
:if (($currentIP != $previousIP) || ($dyndnsForce = true)) do={
:set dyndnsForce false
:set previousIP $currentIP
/tool fetch user=$username password=$password mode=http address="members.dyndns.org" \
src-path="/nic/update?hostname=$hostname&myip=$currentIP" dst-path="/dyndns.txt"
: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")
}
 
elgarchatuma
just joined
Posts: 2
Joined: Thu Apr 19, 2018 3:17 am

Re: DynDNS script that works?

Thu Apr 19, 2018 3:27 am

This Works with my rb951g-2hnd

# Set needed variables
:local username "escribe-tu-usuario-user"
:local password "put-password-here"
:local hostname "putyour-hostname-here.dlinkddns.com"
:global systemname [/system identity get name]


:if ($systemname = "Site1" ) do= {
:set hostname "yourdomain1.dyndns.org"
}
:if ($systemname = "Site2" ) do= {
:set hostname "yourdomain2.dyndns.org"
}
:if ($systemname = "Site3" ) do= {
:set hostname "yourdomain3.dyndns.org"
}


: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"
: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 available at Perform Update - Dyn
:if (($currentIP != $previousIP) || ($dyndnsForce = true)) do={
:set dyndnsForce false
:set previousIP $currentIP
/tool fetch user=$username password=$password mode=http address="members.dyndns.org" \
src-path="/nic/update?hostname=$hostname&myip=$currentIP" dst-path="/dyndns.txt"
: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
arnaldo
newbie
Posts: 45
Joined: Wed Sep 21, 2016 2:38 am
Location: localhost.localdomain

Re: DynDNS script that works?

Sat Apr 21, 2018 11:10 pm

This one allows for multiple interfaces, dynamic interfaces, and even more than one DNS entry per interface. I've been using it for a few years now.
:local ifs {"ppp1";"wan1";"wan1"};
:local hostnames {"a.homeip.net";"b.homeip.net";"c.homeip.net"};
:local user "your-account-name"; 
:local password "your-password";
:foreach k,v in=$ifs do={
        :local if [/ip address find interface="$v"];
        :if ($if="") do={
		:log info "DynDNS: Interface '$v' not available";
        } else={
	        :local newip [ /ip address get $if address];
	        :if ([:typeof $newip]=nil) do={ 
			:log info "DynDNS: No IP address on interface '$v'";
	        } else={
		        :set newip [:pick $newip 0 [:find $newip "/"]];
		        :local oldip [:resolve ($hostnames->$k)];
                        :local hostname ($hostnames->$k);
		        :if ($newip!=$oldip) do={
			        :log info "DynDNS: IP address changed for '$hostname/$v': $oldip -> $newip";
			        /tool fetch user=$user password=$password keep-result=no \
			        url="http://members.dyndns.org/nic/update\?hostname=$hostname&myip=$newip&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG";
			} else={
				:log info "DynDNS: IP address unchanged for '$hostname/$v': $oldip";
			}
		}
	}
}
 
lillecarl
just joined
Posts: 5
Joined: Thu Mar 02, 2017 12:36 pm

Re: DynDNS script that works?

Sun Apr 22, 2018 1:43 pm

There's the builtin one you can enable like this:
/ip cloud set ddns-enabled=yes
/ip cloud force-update
:delay 5s
/ip cloud print
Or you can use one from here:
https://github.com/Lillecarl/ROS_Script ... aster/DDNS
 
User avatar
anav
Forum Guru
Forum Guru
Posts: 19323
Joined: Sun Feb 18, 2018 11:28 pm
Location: Nova Scotia, Canada
Contact:

Re: DynDNS script that works?

Thu Dec 06, 2018 1:04 am

This one allows for multiple interfaces, dynamic interfaces, and even more than one DNS entry per interface. I've been using it for a few years now.
:local ifs {"ppp1";"wan1";"wan1"};
:local hostnames {"a.homeip.net";"b.homeip.net";"c.homeip.net"};
:local user "your-account-name"; 
:local password "your-password";
:foreach k,v in=$ifs do={
        :local if [/ip address find interface="$v"];
        :if ($if="") do={
		:log info "DynDNS: Interface '$v' not available";
        } else={
	        :local newip [ /ip address get $if address];
	        :if ([:typeof $newip]=nil) do={ 
			:log info "DynDNS: No IP address on interface '$v'";
	        } else={
		        :set newip [:pick $newip 0 [:find $newip "/"]];
		        :local oldip [:resolve ($hostnames->$k)];
                        :local hostname ($hostnames->$k);
		        :if ($newip!=$oldip) do={
			        :log info "DynDNS: IP address changed for '$hostname/$v': $oldip -> $newip";
			        /tool fetch user=$user password=$password keep-result=no \
			        url="http://members.dyndns.org/nic/update\?hostname=$hostname&myip=$newip&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG";
			} else={
				:log info "DynDNS: IP address unchanged for '$hostname/$v': $oldip";
			}
		}
	}
}
Hi Arnaldo, that looks interesting.
Lets say I have an URL of knowchit.homeip.net
username of cl0wn and password : notmyrealone
I have two ISPs, primary is na me=VLANfiber using vlanxx from the provider and is running on the ether interface on ethport5
secondary (failover) is name=cableISP running of the ether interface on ethport1

How do you mod your script for two interfaces where one is a primary and the other af failover etc......

Who is online

Users browsing this forum: No registered users and 25 guests