Last update: 2004-09-19

// C O N T R O L - A L T - D E L . O R G

"Fate strikes down the strong man, Everyone weep with me " - O Fortuna
NAVIGATION>>
HOME PICS ABOUT NEWS CODE BOOKS MAIL
:: CODE
The three chief virtues of a programmer are: Laziness, Impatience and Hubris
-- Larry Wall
CONTACT
:. SuaveDNS 0.4

About

SuaveDNS is a set of programs which allows DNS administrators to easily add, remove, or update zones with an easy to use web based control panel. The DNS server is DjbDNS, and the data is stored in a MySQL database. It supports multiple languages (currently english and french), is easy to modify (uses the Smarty PHP templating system), and can have DNS zone information replicated to other servers easily. SuaveDNS now has an easy to use dynamic DNS server and client.

Status

Although this is a work in progress, I see no way in which it could become unstable. Therefore I would (and do) use this in a production system. Caveat Lector.

Todo

Input validation, more translations.

Demonstration (modifications disabled, version 0.3)

Click here (Username: dnstest , Password: dnstest) -- Disabled, hosting provider seems to have problems at the moment

Software

You will need to following software to make this all work:

For brevity, I will assume that Apache, Perl and PHP are already installed.

Installation

Install MySQL

If you want to keep your life simple, download the binary version of mysql from their web site or grab an rpm. Just make sure that the version that you are using supports InnoDB table type (Generally the Mysql-Max versions do, and the 4.X series I think).

If you need to install MySQL from source, here is the command to run to compile it on a linux box with all the right options:

# CFLAGS="-O3 -mcpu=pentiumpro" \
CXX=gcc CXXFLAGS="-O3 -mcpu=pentiumpro -felide-constructors" ./configure \
--prefix=/usr/local/mysql --enable-thread-safe-client --enable-local-infile --enable-assembler \
--disable-shared --with-client-ldflags=-all-static --with-mysqld-ldflags=-all-static \
--without-debug --with-innodb
# make
# make install

Here's an example configuration option for /etc/my.cnf for InnoDB (add it in the [mysqld] section)

innodb_data_home_dir = /usr/mysql/
innodb_data_file_path = ibdata1:40M;ibdata2:10M:autoextend
innodb_log_group_home_dir = /usr/mysql/
innodb_log_arch_dir = /usr/mysql/
innodb_flush_log_at_trx_commit=0
# You can set .._buffer_pool_size up to 50 - 80 %
# of RAM but beware of setting memory usage too high
set-variable = innodb_buffer_pool_size=64M
set-variable = innodb_additional_mem_pool_size=5M
# Set .._log_file_size to 25 % of buffer pool size
set-variable = innodb_log_file_size=64M
set-variable = innodb_log_buffer_size=5M
innodb_flush_log_at_trx_commit=1
set-variable = innodb_lock_wait_timeout=50

Make sure you tweak the buffer amounts and space allocation values here. If you aren't sure, read thefine documentation on the mysql.com web site. Once MySQL is installed, start it up. For RedHat users, this would be "service mysqld start", for almost everybody else: "safe_mysqld &".

Install daemontools

# tar xvfz daemontools-0.76.tar.gz
# cd admin/daemontools-0.76
# package/install
(This should install daemontools and start it up automatically)

Install DjbDNS:

# tar xvfz djbdns-1.05.tar.gz
# cd djbdns-1.05
# make setup check

Create the users that will be needed to run DjbDNS:

# useradd -d /dev/null -s /bin/false dnslog
# useradd -d /dev/null -s /bin/false dnscache
# useradd -d /dev/null -s /bin/false tinydns

Configure dnscache and tinydns. If you are running bind, now would be a good time to shut it down ("service named stop" for you redhat users, or "killall -9 named" for everybody else)

# dnscache-conf dnscache dnslog /etc/dnscache 127.0.0.1
# tinydns-conf tinydns dnslog /etc/tinydns <YOUR NAME SERVER IP HERE>
# cd /service (Create it if it doesn't exsist)
# ln -s /etc/dnscache
# ln -s /etc/tinydns
(dnscache and tinydns should start up in a few seconds)

Set your local dns cache to be dnscache by editing /etc/resolv.conf:

search youdomainnamehere.com
nameserver 127.0.0.1

Install suaveDNS:

# tar xvfz suaveDNS-0.3.tar.gz
# cd suaveDNS-0.3
# cp DNSUpdate.pl /usr/bin
# chmod 700 /usr/bin/DNSUpdate.pl
# cp -av suaveDNS /usr/local/apache/htdocs
# chmod 777 /usr/local/apache/htdocs/suaveDNS/templates_c
(Replace /usr/local/apache/htdocs with your web root folder)

Create the database which will hold your DNS information:

# mysqladmin create dnsadmin -p
(Enter the mysql root password)
# echo "GRANT ALL ON dnsadmin.* TO dnsadmin identified by 'YOURPASSWORDHERE'" | mysql mysql -u root -p

# mysqladmin reload -p
# mysqladmin refresh -p
# mysql dnsadmin -u dnsadmin -p <schema.sql
(Enter the password you just specified for the dnsadmin user)

Edit the programs to reflect your information.
In /usr/bin/DNSUpdate.pl:

### Change these lines to reflect the information you entered in previous steps:
my $DBNAME = 'dnsadmin';
my $DBUSER = 'dnsadmin';
my $DBPASS = 'YOURPASSWORDHERE';
my $DBHOST = 'YOUIPADDRESSHERE';

In /usr/local/apache/htdocs/suaveDNS/init.php:

// Change these lines to reflect the information you entered in previous steps:
$DBNAME = 'dnsadmin';
$DBUSER = 'dnsadmin';
$DBPASS = 'YOURPASSWORDHERE';
$DBHOST = 'YOUIPADDRESSHERE';
$ADMINUSER = 'YOURADMINUSERNAMEHERE';
$ADMINPASS = 'YOURADMINPASSWORDHERE';

Add a cron job to update the DNS data (crontab -e):

*/10 * * * * /usr/bin/DNSUpdate.pl 2>&1 > /dev/null

Point your browser to the location of where suaveDNS is in your web space and login to the system.
http://www.yourdomain.com/suaveDNS

Documentation

This is the part that I haven't had time to do yet, volunteers are welcome. The code should be pretty clear and easy to understand and document.

That said, here's the crash course:

Valid DNS Zones Are A Good Thing (tm)
suaveDNS uses a wizard interface to add new domains into it's database. For adding/modifying a domain you will have 4 steps to complete.

*** IMPORTANT NOTE *** There is NO input validation in the PHP code. However the database schema does place contraints on certain fields having a specific data type and length. You will be able to enter the information into the web wizard, but when you reach the last step (saving the information) the database will refuse the input and rollback all changes (you lose the zone you just created) if your information is invalid.

Step 1. Enter the domain name and time to live (TTL). The value of TTL (numeric in seconds) tells caching name servers how long to keep your record in their cache before removing it. A low TTL will mean that remote services will query your name server more often, while a higher TTL may mean that some servers won't necessarily have the most up to date information (this is mostly due to buggy name servers AKA bind not following the RFCs).

Example

Domain: test.com
TTL: 8000

 


Step 2. Name servers (NS). tinydns implements two types of name server records, and so does suaveDNS. The first type is the Start Of Authority (SOA) record, and every domain should have one of these. The other NS record type is just a plain NS record. TIP: Specify one of your name servers for the SOA (eg: ns1.test.com) and the others as regular NS records (eg: ns2.test.com, ns3.test.com, etc...).
You must also specify the servers IP address.

Example

Name server: ns1.test.com
IP Address: 127.0.0.2
Record Type: SOA

Name server: ns2.test.com
IP Address 127.0.0.3
Record Type: NS

Step 3. Mail Exchangers (MX). I have implemented two types of mail exchanger records based on tinydns. They are the general and host-specific MX records. Suppose you have a mail server mail.test.com which handles all mail for test.com, and a seperate server mailinglist.test.com, and would like all mail heading to mailinglist.test.com to go straight to that machine instead of mail.test.com, you can accomplish this by using host-specific MX records. You can also specify the distance (preference) for this record (numeric values only). This will be used by mail transport agents to make decisions on where to deliver the mail.

Example

Mail Exchanger: mail.domain.com
IP Address: 192.168.1.1
Preference: 10
Host Specific: General (whole domain)

Mail Exchanger: mail2.domain.com
IP Address: 192.168.1.2
Preference: 20
Host Specific: General (whole domain)

Mail Exchanger: mailinglist.domain.com
IP Address: 127.0.0.5
Preference 10
Host Specific: Specific to this host

Step 4. Adding hosts. There are two defined host types. These are 'A', and 'A+PTR'. The 'A' host type is simply an alias which maps a host to the supplied IP address. The 'A+PTR' record type is the same thing, except that a PTR record will also be created for the reverse DNS lookups. Note that in order for reverse DNS lookups to work properly, you must create a reverse zone. To do this, use the add domain functionatlity and specify the domain name as d.c.b.a.in-addr.arpa where a.b.c.d is the IP address class that has been delegated to your name server. You need only specify the domain name (ex: 1.0.0.127.in-addr.arpa) and name servers for this zone, PTR records will be created automatically.

Example

Host name: www.test.com
IP Address: 127.0.0.35
Record Type: A record

Host name: firewall.test.com
IP Address: 127.0.0.1
Record Type: A record with reverse PTR

Step 5. Review and save. If for any reason the data entered was invalid (a non-numeric value for a numeric field) the database will rollback the whole transaction which means that you will lose all the information you have entered for that domain. So please take the time to make sure all the values are as they should be.

DYNAMIC DNS CAPABILITIES

I have written a dynamic DNS server and client for anyone who wants to be able to easily update/add hosts to a domain. Although this was possible already (by connecting to the database and inserting/updating fields), some people may find it of some use.

In order to be able to use these programs, you will need the following:
ucspi-tcp (http://cr.yp.to) (On the server)
Perl (with the DBI,DBD::mysql,Crypt::CBC,Crypt::Blowfish and XML::Simple modules installed) (client and server)

Technical Overview

There are two components to the dynamic DNS software. The client and server communicate with each other using TCP/IP sockets with an XML based protocol. Sensitive information which travels over the network is encrypted.

Example XML message:
<SuaveDNS>
<Domain>example.com</Domain>
<Data>345635asdf435asd343lsdfjl346h234234lk3623dfaslkj54234lkjasdfl34k5j224</Data>
</SuaveDNS>

The <Data> tag contains a hex encoded string which is encrypted using cipher block chaining and the Blowfish block cipher. The initialization
vector is a random number and prepended to the encrypted data in the following format "RandomIV234534". The encrypted data consists of a
string formatted as follows "host|currentip|newip" The passprase used for the encryption is generated based on a substring
of the md5 checksum of the actual supplied password (which is also stored in the MySQL database).

Installing the server component

Install the uscpi-tcp as per the instructions on the web site http://cr.yp.to
Copy DynDNSUpdate to a convenient location (eg: /usr/local/bin)
Create the folder /etc/DynDNSUpdate
Copy the file <src>/suaveDNS-0.4/supervise/run to /etc/DynDNSUpdate and edit it to reflect your settings
Edit /usr/local/bin/DynDNSUpdate and modify the following variables to suit your installation:

my $timeout = 10; # How long we'll wait for data
my $DBNAME = 'dns'; # The dns database suaveDNS is using
my $DBUSER = 'dns'; # The user configured to use the database
my $DBPASS = 'PaSsWoRd'; # The database password for that user
my $DBHOST = 'localhost'; # The host on which this server resides. I don't recommend
# running DynDNSUpdate on a seperate server than the local machine,
# as you'll lose the security built into DynDNSUpdate

my $ALLOW_NEW_HOSTS = 1; # Set to 1 to allow the creation of new hosts. Set to 0 otherwise
my $ALLOW_IP_FROM_CONNECTION = 1; # Set to 1 to allow setting the IP address for a host based
# on the IP address the client software is connecting from.

Issue the following command: ln -s /etc/DynDNSUpdate /service/DynDNSUpdate (The server should start up in a couple of seconds).

Installing the client

The client software DynDNSClient can be installed on the target machine by copying it to a convenient folder (eg: /usr/local/bin).

Client Options:

Server:
--server=<SERVERIP>
This is the IP address of the server.

Port:
--port=<PORT>
This is the port at which the server is listening

Domain:
--domain=<DOMAIN>
This is the domain name for which you will be updating hosts.DynDNSClient currently only supports updating hosts on a single
domain per run.

Password:
--password=<PASSWORD>
This is the password which is stored on the server and associated with this domain.

Hosts:
--hosts <HOSTNAME>=<NEWIP> --hosts <HOSTNAME2>=<IP2> ... --hosts <HOSTNAMEn>=<IPn>
This is a list of hosts (multiple --hosts switches can be specified to update multiple hosts in one run) and IP addresses for each host. If
the IP address is specified as '' the IP address you are running DynDNSClient from will be used.

Host IP resolving:
--hostsold <HOSTNAME>=<OLDIP> --hostsold <HOSTNAME2>=<OLDIP2> ... --hostsold <HOSTNAMEn>=<IPn>
This is the current IP address associated with this host names you wish to update. This information need only be specified if you are sure that there is not more than one (1) IP address associated with each host. If --resolve=0 you must specify values for each host.

Automatic host IP resolving:
--resolve=1
This specifies wether or not you want DynDNSClient to attemps to automatically figure out what the current IP address for a host is (as opposed to specifying it with --hostsold).

Debugging:
--debug=1
Prints out what it's sending to the server.

Examples:
./DynDNSClient --password=asdf --server=127.0.0.1 --port=123 --domain=bob.com \
--resolve=1 --hosts a.bob.com=''

This would set the host a.bob.com to whatever the current IP address of where the client is connecting from (Assuming the server accepts updating a host from the remote connection IP address).

./DynDNSClient --password=asdf --server=127.0.0.1 --port=123 --domain=bob.com --resolve=0 \
--hosts a.bob.com=111.222.333.444 --hostsold a.bob.com=127.0.0.1

This would set a.bob.com (which resolved to 127.0.0.1) to point to 111.222.333.444

./DynDNSClient --password=asdf --server=127.0.0.1 --port=123 --domain=bob.com --resolve=1 \
--hosts a.bob.com=111.222.333.444 --hostsold a.bob.com=127.0.0.1 --hosts b.bob.com=''

This would set a.bob.com (which resolved to 127.0.0.1) to point to 111.222.333.444, and
would set b.bob.com to point to whatever IP address DynDNSClient is curerntly connecting from.

Potential uses

DynDNSClient can be run from the cron and automatically update a host record if you have DHCP and your IP address changes often.

If you add lots of hosts to a domain you can automate the process by running DynDNSClient from scripts.

If you do network monitoring, you can run DynDNSClient and do DNS failover when you have clusters of boxes.

Keep in mind that although DynDNSUpdate will update the MySQL database, the actualy cdb database that tinydns uses will only
be updated the next time that DNSUpdate is run, so it's generally a good idea to run DNSUpdate from the cron every couple
of minutes if you want to get the best of DynDNSUpdate.

Slave DNS servers / Replication

To create secondary dns servers using this setup is amazingly simple.

1 - Copy over DNSUpdate.pl to the target server and setup a cron job for it to run. Edit it to specify the $DBHOST of the 'main' dns server.
2 - Install daemontools (same procedure described above
3 - Install djbdns (same procedure as described above)

That's all there is to it. DNSUpdate will fetch it's data from the remote MySQL server and create a local data file. If for some reason DNSUpdate can't contact the remote server, it will time out and tinydns will simply continue using the last 'good' configuration that was pulled from the database. For added security the MySQL database could be replicated to the secondary DNS servers using MySQL's replication functionality, in which case DNSUpdate could use the slave MySQL server to pull it's data from. With very little work DNSUpdate could be made aware of slave MySQL servers, but that will be left as an exercise to the reader.

Rince and repeat to as many servers as you want.

License

Copyright © 2003 Mark Steele

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

Credits

Dan J. Bernstein for djbdns and daemontools (http://cr.yp.to)
Ted Kappes for the paginator code used in the domain search page (http://tkap.org/paginator)
Mark Steele for the PHP and Perl code which is the guts of suaveDNS.

© copyright 2004 Mark Steele