PDA

View Full Version : Avahi + BIND Dynamic DNS server



leica
12-23-2010, 09:15 AM
Warning: The majority of this post is unexplained code and config. The uninitiated shall enter at their own risk and I shall not be liable for any head explosions or other damages.


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Last week, my Qwest gateway/router went out and I replaced it with an ancient D-Link that doesn't resolve local domain names. Many applications on my network depend on local DNS, so I decided to set up BIND on my HTPC. Initially, this was done using static IP addresses and a static zone file.

This morning, after having no sleep last night (I stayed up working on a Tumblr layout), I figured out this cool thing you can do with Avahi:

$ avahi-browse -prt _workstation._tcp
+;eth0;IPv4;travis\032\09148\0585b\05839\05863\058 83\05891\093;Workstation;local
+;eth0;IPv4;htpc\032\09100\05813\05872\05831\058e6 \058a0\093;Workstation;local
=;eth0;IPv4;travis\032\09148\0585b\05839\05863\058 83\05891\093;Workstation;local;travis.local;192.16 8.0.101;9;
=;eth0;IPv4;htpc\032\09100\05813\05872\05831\058e6 \058a0\093;Workstation;local;htpc.local;192.168.0. 103;9;So yeah, a parsable list of workstations on the network, their domain names, and their IPs. But how do we get this information to the DNS server?

I ended up writing a cron script (in PHP, lol). The implementation is horrible due to my sleep deprivation but you can get the general idea from this:

#!/usr/bin/php

<?php
$avahidata = explode("\n",`avahi-browse -ptr _workstation._tcp`);

$hosts="server localhost\nzone local\n";
$pointers="server localhost\nzone 0.168.192.in-addr.arpa\n";

$oldhosts="server localhost\nzone local\n";
$oldpointers="server localhost\nzone 0.168.192.in-addr.arpa\n";

for($i=0;$i<count($avahidata)-1;$i++){
$hostInformation=explode(";",$avahidata[$i]);
if($hostInformation[0] != "=") continue;

$hostname=$hostInformation[6];
$hostaddr=$hostInformation[7];
$ptraddr=implode(".",array_reverse(explode(".",$hostaddr)));

$hosts.="update add $hostname 2400 A $hostaddr\n";
$pointers.="update add $ptraddr.in-addr.arpa 2400 PTR $hostname\n";

$oldhosts.="update delete $hostname A\n";
$oldpointers.="update delete $ptraddr.in-addr.arpa PTR\n";
}

$hosts.="send\n";
$pointers.="send\n";

$oldhosts.="send\n";
$oldpointers.="send\n";

echo `cat .dns_purge_hosts | nsupdate`;
echo `cat .dns_purge_pointers | nsupdate`;

echo `echo "$hosts" | nsupdate`;
echo `echo "$pointers" | nsupdate`;

file_put_contents(".dns_purge_hosts",$oldhosts);
file_put_contents(".dns_purge_pointers",$oldpointers);

?>

Now, of course BIND is configured to allow updates from localhost...

acl lan { 192.168.0/24; 127.0.0.1; };

options {
directory "/var/named";
pid-file "/var/run/named/named.pid";
auth-nxdomain yes;
datasize default;
listen-on { any; };
forward first;
forwarders {
8.8.8.8;
8.8.4.4;
};
};

zone "local" {
type master;
file "local.zone";
check-names ignore;
allow-transfer { lan; };
allow-update { lan; };
};

zone "0.168.192.in-addr.arpa" {
type master;
file "0.168.192.in-addr.arpa.zone";
check-names ignore;
allow-transfer { lan; };
allow-update { lan; };
};

Now, the cron script runs every minute, which isn't really a problem since it doesn't use many resources. Everything works fine and here's some output from BIND to prove it.

23-Dec-2010 07:47:02.266 client 127.0.0.1#50731: updating zone 'local/IN': deleting rrset at 'travis.local' A
23-Dec-2010 07:47:02.266 client 127.0.0.1#50731: updating zone 'local/IN': deleting rrset at 'htpc.local' A
23-Dec-2010 07:47:02.643 client 127.0.0.1#44082: updating zone '0.168.192.in-addr.arpa/IN': deleting rrset at '101.0.168.192.in-addr.arpa' PTR
23-Dec-2010 07:47:02.643 client 127.0.0.1#44082: updating zone '0.168.192.in-addr.arpa/IN': deleting rrset at '103.0.168.192.in-addr.arpa' PTR
23-Dec-2010 07:47:02.731 client 127.0.0.1#61526: updating zone 'local/IN': adding an RR at 'travis.local' A
23-Dec-2010 07:47:02.732 client 127.0.0.1#61526: updating zone 'local/IN': adding an RR at 'htpc.local' A
23-Dec-2010 07:47:02.832 client 127.0.0.1#19283: updating zone '0.168.192.in-addr.arpa/IN': adding an RR at '101.0.168.192.in-addr.arpa' PTR
23-Dec-2010 07:47:02.833 client 127.0.0.1#19283: updating zone '0.168.192.in-addr.arpa/IN': adding an RR at '103.0.168.192.in-addr.arpa' PTR

And now I can successfully look up other hosts on the network.

$ nslookup htpc
Server: 192.168.0.103
Address: 192.168.0.103#53

Name: htpc.local
Address: 192.168.0.103

LiNuX
12-23-2010, 10:15 AM
nice fix there. I usually just have an extra router lying around in case my current ones can't resolve IPs or domains and it has happened before. What you did was pretty creative. I would be lazy.

leica
12-27-2010, 12:30 AM
Last night I modified this system to keep track of machines in MySQL so no unnecessary adds or deletes are sent to the DNS server.

steveo
09-22-2013, 01:42 PM
Last night I modified this system to keep track of machines in MySQL so no unnecessary adds or deletes are sent to the DNS server.

howdy. this is a cool tip. just what i've been looking for.

any chance you could share the MySQL enhancement?

Thanks!