{"id":1008,"date":"2013-07-09T23:48:14","date_gmt":"2013-07-09T23:48:14","guid":{"rendered":"http:\/\/www.randomnoun.com\/wp\/?p=1008"},"modified":"2016-09-21T21:19:17","modified_gmt":"2016-09-21T21:19:17","slug":"a-slightly-less-simple-dynamic-dns-server","status":"publish","type":"post","link":"https:\/\/www.randomnoun.com\/wp\/2013\/07\/09\/a-slightly-less-simple-dynamic-dns-server\/","title":{"rendered":"A slightly less simple Dynamic DNS server"},"content":{"rendered":"<pre style=\"display:none\"><style>\r\n.footnoteref { vertical-align: super; font-size: 80%; }\r\n.footnoteline { width:50%; height:2px; border-top: solid 1px gray; \"\/>\r\n<\/style><\/pre>\n<p>So <a href=\"https:\/\/www.randomnoun.com\/wp\/2013\/07\/08\/a-dead-simple-dynamic-dns-server\/\">earlier in the week<\/a>, I posted up the source of <b>ddserver.pl<\/b>, which is a Dynamic DNS server which I&#8217;m using to track a machine with a rapidly-changing IP out on the internet<a name=\"fn1back\" href=\"#fn1\" class=\"footnoteref\">[1]<\/a>.<\/p>\n<p>I&#8217;ve updated that post with a bit more detail about how to use it, so check it again if you tried to install it and get stymied by the lack of documentation supplied (it now has some sample apache config and the contents of the reload cronjob).<\/p>\n<p>This entry is about some additional features that make the script slightly less simple, but slightly more useful, if this is the sort of thing that you think is useful.<\/p>\n<h2>Round-tripping zone files<\/h2>\n<p>So if you run <code>ddserver.pl<\/code> from a clean installation, and create a new <a href=\"http:\/\/en.wikipedia.org\/wiki\/List_of_DNS_record_types\"><code>A<\/code> record<\/a> for your computer called &#8216;<code>test<\/code>&#8216; in the &#8216;<code>example.com<\/code>&#8216; zone, you&#8217;ll get a bind file created in <code>\/etc\/bind\/dynamic\/db.example.com<\/code> that looks like this:<\/p>\n<pre lang=\"txt\" line=\"1\" highlight=\"19\">\r\n;\r\n; BIND data file for example.com zone\r\n; this file is automatically generated by ddserver.pl.\r\n;\r\n$TTL    604800\r\n@       IN      SOA     ns1.example.com. soaContact.example.com (\r\n                2013071001         ; (YYYYMMDDNN) Serial INCREMENT THIS EVERY TIME FILE CHANGES\r\n                                   ; (triggers zone transfer if secondary configured)\r\n                      7200         ; Refresh\r\n                     86400         ; Retry\r\n                   2419200         ; Expire\r\n                      7200 )       ; Negative Cache TTL\r\n;\r\n\r\nexample.com.         7200    IN      NS      ns1.example.com.\r\nexample.com.         7200    IN      NS      ns2.example.com.\r\n;\r\n; === START OF GENERATED CONFIGURATION\r\ntest    300     IN      A       1.2.3.4\r\n; === END OF GENERATED CONFIGURATION\r\n\r\n; if you are manually modifying this file, anything added before or after\r\n; the automatically generated markers above should be preserved.\r\n; Except for the serial number, of course, because that's special.\r\n\r\n<\/pre>\n<p>If you&#8217;re running your own bind server, you probably have a raft of other DNS records for your domain, which are more fixed than the records being maintained by <code>ddserver.pl<\/code>. <\/p>\n<p><code>ddserver.pl<\/code> supports maintaining these manually by modifying the contents of the zone file directly, since only the text between the <\/p>\n<div style=\"margin:10px;\"><code>; === START OF GENERATED CONFIGURATION<\/code><\/div>\n<p>and <\/p>\n<div style=\"margin:10px;\"><code>; === END OF GENERATED CONFIGURATION<\/code><\/div>\n<p>markers is modified by the script during subsequent updates. <\/p>\n<p>This means that other entries, formatting and comments are kept intact whenever the <code>ddserver.pl<\/code> script reads and writes the file, meaning you can roundtrip the file without discarding the non-machine-readable information.<\/p>\n<p>Which is nice if your zone files are filled with crap that needs a reference to a change request someone raised in 1998.<\/p>\n<h2>Templates<\/h2>\n<p>While this is all well and good, manual changes are still, well, manual. <\/p>\n<p>The templating mechanism allows you to deploy changes using whatever system you use to deploy configuration file changes (such as puppet, chef, sprinkle, stackful, salt<a name=\"fn2back\" href=\"#fn2\" class=\"footnoteref\">[2]<\/a>, or my personal favourite, vmaint), and have those changes merged into the dynamic data already stored in the file.<\/p>\n<p>Say I wanted to add a <a href=\"http:\/\/en.wikipedia.org\/wiki\/List_of_DNS_record_types\"><code>TXT<\/code> record<\/a> to the domain to prove to google analytics that I own the thing and wanted to make graphs showing the 30 hits or so a month that I get. I could either update the <code>\/etc\/bind\/dynamic\/db.example.com<\/code> file directly, restart bind, and this would work, or I could create\/update a template file (in <code>\/etc\/bind\/dynamic\/db.example.com<b>.template<\/b><\/code>) which looks like this:<\/p>\n<pre lang=\"txt\" line=\"1\" highlight=\"17\">\r\n;\r\n; BIND data file for example.com zone\r\n; this file is automatically generated by ddserver.pl and db.example.com.template.\r\n;\r\n$TTL    604800\r\n@       IN      SOA     ns1.example.com. soaContact.example.com (\r\n                2013071001         ; (YYYYMMDDNN) Serial INCREMENT THIS EVERY TIME FILE CHANGES\r\n                                   ; (triggers zone transfer if secondary configured)\r\n                      7200         ; Refresh\r\n                     86400         ; Retry\r\n                   2419200         ; Expire\r\n                      7200 )       ; Negative Cache TTL\r\n;\r\n\r\nexample.com.         7200    IN      NS      ns1.example.com.\r\nexample.com.         7200    IN      NS      ns2.example.com.\r\nexample.com.         7200    IN      TXT     \"google-site-verification=cLF9jhJ75wc3ITzLVr6tAH4ipXFX9_KqbETj3HgMoR8\"\r\n;\r\n; === START OF GENERATED CONFIGURATION\r\n<%= $bindrecords %>\r\n; === END OF GENERATED CONFIGURATION\r\n\r\n; if you are manually modifying this file, anything added before or after\r\n; the automatically generated markers above should be preserved.\r\n; although I recommend that you use the template file instead, because that\r\n; will take precedence the next time someone merges this thing\r\n<\/pre>\n<p>perform a <code>NOCHG<\/code> update using the commandline with the <code>forcetemplate<\/code> parameter set to <code>yes<\/code>, and the zonefile would be updated to reflect the template, whilst still preserving the dynamic records maintained by <code>ddserver.pl<\/code>; i.e. something like:<\/p>\n<pre lang=\"txt\" line=\"1\">\r\nperl \/var\/www\/dyndns.example.com\/cgi-bin\/ddserver.pl \/update? \\\r\n  username=admin password=admin \\\r\n  hostname=dummy.example.com \\\r\n  myip=NOCHG \\\r\n  forcetemplate=yes\r\n<\/pre>\n<p>The upshot of all this is that you can now ensure that the non-dynamic portions of the zonefile can be tracked via source control and deployed using some vaguely deterministic manner.<\/p>\n<h2>Propagating updates<\/h2>\n<p>In the example <code>ddserver.json<\/code> configuration file (which in this example would be located at <code>\/var\/www\/dyndns.example.com\/cgi-bin\/ddserver.json<\/code>) contained in the <a href=\"https:\/\/www.randomnoun.com\/wp\/2013\/07\/08\/a-dead-simple-dynamic-dns-server\/\">previous blog post<\/a>, the <code>nameservers<\/code> block appears as:<\/p>\n<pre lang=\"json\" line=\"78\">\r\n    \/* the nameservers for these zones (array) *\/\r\n    \"nameservers\" : [ \r\n        \"ns1.example.com\",\r\n        \"ns2.example.com\"\r\n    ]\r\n<\/pre>\n<p>If you despise <a href=\"http:\/\/en.wikipedia.org\/wiki\/DNS_zone_transfer\">axfr<\/a> for some reason, this can be enhanced to include a URL for each nameserver, thusly:<\/p>\n<pre lang=\"json\" line=\"78\">\r\n    \/* the nameservers for these zones (hash) *\/\r\n    \"nameservers\" : {\r\n      \"ns1.example.com\" : { \"dyndns\" : \"http:\/\/ns1.example.com\/ddserver.pl\" },\r\n      \"ns2.example.com\" : { \"dyndns\" : \"http:\/\/ns2.example.com\/ddserver.pl\" }\r\n    }\r\n<\/pre>\n<p>which will cause the <code>ddserver.pl<\/code> script to send any changes through to all other nameservers for your organisation. (The <code>ddserver.pl<\/code> script needs to be set up on these nameservers for this to work). <\/p>\n<p>You&#8217;d probably use HTTPS as well, I&#8217;d imagine.<\/p>\n<p>To prevent the script from sending changes to itself, you will need an extra configuration file in the directory holding the <code>ddserver.pl<\/code> script called <code>ddserver-hostname.txt<\/code>, containing the host name of that nameserver; i.e. something like this in <code>\/var\/www\/dyndns.example.com\/cgi-bin\/ddserver-hostname.txt<\/code>:<\/p>\n<pre lang=\"json\" line=\"1\">\r\nns1.example.com\r\n<\/pre>\n<p>You&#8217;d have thought that the script could work out it&#8217;s own hostname by itself, and you&#8217;d probably be right, but you&#8217;d also sometimes be wrong. <\/p>\n<p>Keeping it in a separate file also means that every nameserver can have identical <code>ddserver.json<\/code> configuration files as well, which is nice.<\/p>\n<p>If you don&#8217;t have multiple nameservers, then ignore this whole section.<\/p>\n<h2>Anything else?<\/h2>\n<p>You should probably be aware that <code>ddserver.pl<\/code>:<\/p>\n<ul>\n<li>doesn&#8217;t perform locking around file updates\n<li>doesn&#8217;t yet support support dynamic AAAA records if you&#8217;re using ipv6\n<li>doesn&#8217;t support the mx parameters of the dyndns update protocol\n<li>doesn&#8217;t actually support the zoneedit update protocol properly either\n<li>hasn&#8217;t really been tested at all, and probably therefore has bugs and as-yet-undiscovered security holes like you wouldn&#8217;t believe\n<li>during normal execution, and more importantly, when it breaks, there&#8217;s a logfile created (in the sample <code>ddserver.json<\/code> configuration file this is set to  <code>\/var\/log\/ddserver.log<\/code>).\n<p>If there&#8217;s no logfile, it probably means the user that the webserver is running under (usually <code>www-data<\/code>) doesn&#8217;t have access to the file, so you&#8217;d need to do something like this:<\/p>\n<p><code>sudo \/bin\/bash -c 'touch \/var\/log\/ddserver.log; chown www-data:www-data \/var\/log\/ddserver.log; chmod 664 \/var\/log\/ddserver.log'<\/code><\/p>\n<p>Which also reminds me&#8230; your <code>\/etc\/bind\/dynamic<\/code> directory should have group write permissions, and you should chgrp the folder to <code>www-data<\/code>, so something like this:<\/p>\n<p><code>sudo \/bin\/bash -c 'mkdir \/etc\/bind\/dynamic; chown bind:www-data \/etc\/bind\/dynamic; chmod 775 \/etc\/bind\/dynamic'<\/code> <\/p>\n<p>, although for some reason this isn&#8217;t what I&#8217;ve got running here.<\/p>\n<p>I may update this bit later, some time after I convert this all into a debian package. <\/p>\n<p>Possibly. <\/p>\n<p>It&#8217;s very long for a bullet point.\n<\/ul>\n<p>Also remember that unless you remembered to shorten the TTL (time-to-live) value just before you changed the IP address, which you can&#8217;t actually do unless you know when your IP is going to change or have a time machine, then any changes made to IP addresses will take a while to be visible to the outside world. I think the default is something like five minutes.<\/p>\n<h2>So is that it?<\/h2>\n<p>If you download any time in the next ten years, I&#8217;ll throw in a free <a href=\"https:\/\/www.randomnoun.com\/wp\/2013\/08\/19\/a-dynamic-dns-client-for-windows\/\">Dynamic DNS client for Windows<\/a>.<\/p>\n<div class=\"footnoteline\"><\/div>\n<p><a name=\"fn1\" href=\"#fn1back\">[1]<\/a> well, it changes about once every 24 hours, but that&#8217;s more rapid than, say, not at all.<br \/>\n<a name=\"fn2\" href=\"#fn2back\">[2]<\/a> bonus marks if you can work out why this site is called randomnoun.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So earlier in the week, I posted up the source of ddserver.pl, which is a Dynamic DNS server which I&#8217;m using to track a machine with a rapidly-changing IP out on the internet[1]. I&#8217;ve updated that post with a bit more detail about how to use it, so check it again if you tried to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":2937,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[52],"tags":[7,11,12,29,33],"class_list":["post-1008","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-programming","tag-ddserver","tag-dns","tag-dyndns","tag-namingwords","tag-perl"],"_links":{"self":[{"href":"https:\/\/www.randomnoun.com\/wp\/wp-json\/wp\/v2\/posts\/1008","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.randomnoun.com\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.randomnoun.com\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.randomnoun.com\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.randomnoun.com\/wp\/wp-json\/wp\/v2\/comments?post=1008"}],"version-history":[{"count":1,"href":"https:\/\/www.randomnoun.com\/wp\/wp-json\/wp\/v2\/posts\/1008\/revisions"}],"predecessor-version":[{"id":2939,"href":"https:\/\/www.randomnoun.com\/wp\/wp-json\/wp\/v2\/posts\/1008\/revisions\/2939"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.randomnoun.com\/wp\/wp-json\/wp\/v2\/media\/2937"}],"wp:attachment":[{"href":"https:\/\/www.randomnoun.com\/wp\/wp-json\/wp\/v2\/media?parent=1008"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.randomnoun.com\/wp\/wp-json\/wp\/v2\/categories?post=1008"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.randomnoun.com\/wp\/wp-json\/wp\/v2\/tags?post=1008"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}