Creating your own noip

search for: in: entire forum this post
you are here: root => Tech Tutorials => Creating your own noip
member since:
folders:
3
posts:
6
replies:
0

Creating your own noip

I like to be able to connect to my home computers from work and it can be done via SSH or VNC as long as you have setup the needed port-forwarding in your home router however 1 problem that remains is the fact that my home IP address keeps changing (since its dynamic). My go to solution over the years has been to use the free service at noip.com. However in the last few years I haven't been liking their service so much anymore because they keep sending me emails (every 30 days) asking me to click a link to keep my *free host active otherwise it expires pretty fast. And I don't always check my emails fast enough. Result: I often find that when I want to connect to my home computers from outside my noip free host usually has expired, or the client is not running properly anymore on my home computers to keep the IP up to date. So I decided to create my own simple noip service so that I can have one of my sub-domains always point to my home IP even if this IP is changing regularly. Here is how I did it, I thought maybe this could help someone else.

First of all I will assume that you have Bind9 running on your server and have some domains that are using your own name servers so to allow them to be configured on your own Bind installations. I am running on Ubuntu server 14, most of it should be pretty similar on any Linux distro.

Step 1 - Updating DNS with nsupdate

The first challenge was to learn to update my DNS with the nsupdate command. The command was already available on my server I did not have to install it, however when I tried using it it did not work for me, eventually I managed to get it working here is how:

First of all I didn't want all this experimental dynamic Bind settings update to mess up my running websites but I did not either want to purchase a new domain for the cause. So I started by creating a new zone in Bind which was a subdomain of another domain I already use. For this tutorial I will pretend the domain in question was mydomain.com. mydomain.com has its bind zone under /etc/bind/zones/db.mydomain.com and is defined under /etc/bind/named.conf.local as a zone. So I created a new zone named noip.mydomain.com which has its definition under /etc/bind/zones/db.noip.mydomain.com and is also defined in /etc/bind/named.conf.local. This works fine as long as the zone for mydomain.com does not have a wildcard entry in it!

my zone in named.conf.local looks like this:

code:
zone "noip.videolister.org" {
        type master;
        file "/etc/bind/zones/db.noip.videolister.org";
        allow-transfer {"good-guys";};
        allow-update {any;};
        };



(note that allow-update any means anyone can update the zone. This normally should be protected by a key but I will get back to that later. Also allow-transfer good-guys is a bind ACL setting to allow a slave server to pull a copy of the DNS. This second part is unrelated to our tutorial)

the file db.noip.mydomain.com was initially a copy of the file db.mydomain.com in which I changed all occurences of mydomain.com to noip.mydomain com, but you will see that after allowing nsupdate to modify it it gets quite changed in form.

Next the basic command to update DNS via nsupdate goes like this:

create a file and put these contents in it (for this tuto lets say this file is named mynsupdate.txt):

code:
server localhost
zone noip.mydomain.com
update delete test1.noip.mydomain.com.
update add test6.noip.mydomain.com. 3600 A 4.2.2.2
show
send



then run this in the terminal:

code:
nsupdate -v mynsupdate.txt



And if you are lucky you should see nsupdate show you new DNS definition without any error messages. However in my case it initially did not work I had to do 2 changes to get it working. I could see more details about the errors I was getting in /var/log/syslog

to fix this error:
code:
Dec 16 11:22:59 dns1 kernel: [49671335.189689] type=1400 audit(1418757779.712:12): apparmor="DENIED" operation="mknod" parent=1 profile="/usr/sbin/named" name="/etc/bind/zones/myzone.com.db.jnl" pid=31154 comm="named" requested_mask="c" denied_mask="c" fsuid=107 ouid=107
Dec 16 11:22:59 dns1 kernel: [49671335.306304] type=1400 audit(1418757779.828:13): apparmor="DENIED" operation="mknod" parent=1 profile="/usr/sbin/named" name="/etc/bind/zones/rev.2.10.10.in-addr.arpa.jnl" pid=31153 comm="named" requested_mask="c" denied_mask="c" fsuid=107 ouid=107



type this:
code:
# ln -s /etc/apparmor.d/usr.sbin.named /etc/apparmor.d/disable/
# service apparmor restart



and to fix this error:
code:
Dec 16 11:30:54 dns1 named[32640]: /etc/bind/zones/myzone.com.db.jnl: create: permission denied
Dec 16 11:30:54 dns named[32640]: /etc/bind/zones/rev.2.0.10.in-addr.arpa.jnl: create: permission denied



type that:
code:
# chown -R bind:bind /etc/bind/zones


(credit => http://agiletesting.blogspot.ca/2014/12/dynamic-dns-updates​-with-nsupdate-new.html Thanks dude!)

After that I was able to run
code:
nsupdate -v mynsupdate.txt

and have the results no error and I could verify that it was working with
code:
host test6.noip.mydomain.com



Next step is to write a PHP page that you can access at whatever.com/noip/update?host=test6&secret=mypassword (over SSL to hide your password) and upon being accessed the page will verify that your domain and password are matching and if they are it will run shell commands to update your hosts with your current IP using nsupdate as demonstrated above.

I will build that and show you my code after but you should know that I got the idea from this post: http://pablohoffman.com/dynamic-dns-updates-with-a-simple-p​hp-script and while its nice to setup for myself I could pretty easily turn that into a free noip service, maybe later... and finally I should also restrict my allow-update with an actual key for security! [TO BE CONTINUED!!]

Step 2 - Getting the PHP script to work!

First I took the script from http://pablohoffman.com/dynamic-dns-updates-with-a-simple-p​hp-script as is because it seemed great but for some reason it did not initially work out for me. So I modified it and also made it a lot more verbose in order to be able to figure out what was wrong with it initially¬≠. Dont forget if things dont work out, have a look at /var/log/syslog (right after trying it!) there may be some errors in there. So here is the final version of my script (dont forget to edit the configuration part at the top!):

code:
<?php

//CONFIGURATION START
$hosts=array(
	"mynoiphost"=>"crazaypasswordddd",
);
$zone="noip.mydomain.com";
$dnsserver="localhost";
//CONFIGURATION END



function exec_n_output($cmd){
	echo "execing $cmd<br>";
	
	/*exec($cmd." 2>&1",$result);
	foreach ($result as &$value) {
			echo "$value<br>";
	}*/
	
	exec($cmd . ' 2>&1', $outputz);
    foreach ($outputz as $key => $value)
    { print($value . '<br />'); }
}
function logitlol($log_str){
	$logsfolder="logslol";
	$logsfilename="access.log";
	$maxlogsize=1024*10;
	
	//create logs directory if it does not exist
	if(!file_exists($logsfolder."/.htaccess")){
		mkdir("logslol",0755);
		if(!file_exists($logsfolder)){
			echo "unable to create logs folder<br>";
			return false;
		}else{
			file_put_contents($logsfolder."/.htaccess","Deny from all");
		}
	}
	
	//check if log is too big
	$logsize=filesize($logsfolder."/".$logsfilename);
	if($logsize>$maxlogsize){
		rename($logsfolder."/".$logsfilename,$logsfolder."/bak_".time()."_".$logsfilename);
	}
	
	echo "loggin $log_str<br>";
	file_put_contents($logsfolder."/".$logsfilename,$log_str."\n",FILE_APPEND);
}




$ip = $_SERVER['REMOTE_ADDR'];
$host = $_GET['host'];
$pass = $_GET['pass'];
$tmpfile = trim(`mktemp /tmp/nsupdate.XXXXXX`);


logitlol("access from $ip $host $pass");

if ((!$host) or (!$pass) or (!($hosts[$host] == $pass))) {
	//inform reason for failure
	if(!$host)echo "GET host is missing<br>";
	else if(!$pass)echo "GET pass is missing<br>";
	else if($hosts[$host]!=$pass)echo "GET pass incorrect for host<br>";
	//inform it failed
    echo "FAILED<br>";
    exit; 
}

$cmd="host $host.$zone | cut -d ' ' -f 4";
echo $cmd."<br>";
$oldip = trim(`$cmd`);
echo "$ip - $oldip<br>";
if ($ip == $oldip) {
    echo "UNCHANGED<br>";
    exit;
}




$nsucmd = "server $dnsserver
zone $zone
update delete $host.$zone. A
update add $host.$zone. 300 A $ip
show
send
";

$fp = fopen($tmpfile, 'w');
fwrite($fp, $nsucmd);
fclose($fp);
//`/usr/bin/nsupdate $tmpfile`;
echo "<pre>".file_get_contents($tmpfile)."</pre><br>";
exec_n_output("/usr/bin/nsupdate -v $tmpfile");
unlink($tmpfile);
echo "OK<br>";




I probably dont need to explain that but just in case, once this is on your server access it like this https://domainwherescriptis.com/folderwherescriptis/scriptfi​lename.php?host=mynoiphost&pass=crazaypasswordddd

(make sure you use https:// to connect in order to hide the password which is in the URL!

so at this point I finally have a working noip system of my own

next stepts are:
  1. increasing security by adding a key to updating the domain via nsupdate (remember that allow-update {any;};)
  2. maybe, making building a free public service out of that ...
post #50
permalink

moderators of this post

envis (level: ∞)
powered by Nodesforum