Archive - DNS RSS Feed

AWS Route53 vs Rackspace Cloud DNS

Yesterday, Rackspace announced their new Cloud DNS service. This is clearly(?) a response to Amazon’s Route53 release a while back. With one big difference; Rackspace Cloud DNS is free (in combination with other Rackspace Cloud Products), whereas Route53 is not.

I’ll admit I haven’t tried the Rackspace service (yet), but here’s a quick comparison table anyway. Some questions (about branding and distribution) I couldn’t find answered on the Rackspace information page, so I used the support chat.

  Amazon Route53 Rackspace Cloud DNS
Management API* API*
Distribution Anycast** Anycast***
IPv6 - Yes
DNSSEC - -
Branding - -
RR Types A, AAAA, CNAME, MX, NS, PTR, SOA, SPF, SRV, TXT & “Alias”**** A, AAAA, CNAME, DKIM, MX, NS, SPF, SRV & TXT
Pricing Cheap Free

* Neither Amazon nor Rackspace has a management interface for the DNS services. DNS30 is however availible for Route53.
** 19 locations on 3 continents
*** 3 locations on 2 continents (see comment below)
**** Alias records are used to map resource record sets in your hosted zone to Elastic Load Balancing instances.

If the choice only stood between Route53 and Rackspace I think I’d go with Rackspace, just because of the IPv6 connectivity. But other providers should also be considered, Zerigo for example has an excellent DNS service.

Update: After the comment below by Daniel Morris at Rackspace I tried to contact the chat support again to get the information about the edge locations. Here’s the response:

Agent: I’m sorry but I am not positive I would recommend contacting the support team at 1-877-934-0407 or 0800 054 6345 | +44 20 8734 4345
Agent: I’m sorry for any inconvenience this has caused
Agent: have a great day

Not very impressed wit this fanatical support, to be honest.

GeoIP CSV to Bind ACL

Simple perl script for converting a GeoIP CSV file (latest version) to Bind ACL definitions.

#!/usr/bin/perl
 
use strict;
use warnings;
 
use Net::CIDR::Lite;
 
# Get files
my $infile  = $ARGV[0];
my $outfile = $ARGV[1];
 
# Open infile for reading
open(FILE, '<', $infile);
 
# Define iplist array
my %iplist;
 
# Loop infile
while(<FILE>) {
        # Set start, end and country variables
        my @line = split(/\"/, $_);
        my $start_ip = $line[1];
        my $end_ip   = $line[3];
        my $country  = $line[9];
 
        # Use the CIDR class to get networks in the range
        my $cidr = Net::CIDR::Lite->new;
        $cidr->add_range("$start_ip-$end_ip");
        my @networks = $cidr->list;
 
        # Put networks in the iplist array
        foreach(@networks) {
                $iplist{$country} .= "\t" . $_ . ';' . "\n";
        }
}
 
# Close the infile file handle
close FILE;
 
# Open outfile for writing
open(FILE, '>', $outfile);
 
# Loop iplist array
foreach my $country (sort keys %iplist) {
        # Write to outfile
        print FILE 'acl "' . $country . '" {' . "\n";
        print FILE $iplist{$country};
        print FILE '};' . "\n";
}
 
# Close the outfile file handle
close FILE;
 
# We're done

Simple usage:

$ ./geoip.pl GeoIPCountryWhois.csv countries.acl

You’ll need the Net::CIDR::Lite extension for Perl, in Debian/Ubuntu the package is called libnet-cidr-lite-perl.

Supermaster with PowerDNS

Adding new zones to an existing Bind master/slave setup can be a bit tedious, since NOTIFYs are ignored for zoned not already configured on the slave. PowerDNS solves this problem by introducing something called supermasters. When a supermaster sends a NOTIFY to a slave for a zone that doesn’t already exist, the slave server simply ads it to the database and fetches the data.

As a side note, I’ve previously written about how to sync djbdns zones with rsync.

For this example I’ll be using two Ubuntu 10.10 servers. ns1.example.com with ip address 10.0.0.10 and ns2.example.com with address 10.0.0.20. Start by installing MySQL and PowerDNS on them:

# aptitude install mysql-server pdns-backend-mysql

Create a database named pdns and populate it with the tables described in the documentation.

CREATE TABLE domains (
 id		 INT auto_increment,
 name		 VARCHAR(255) NOT NULL,
 master		 VARCHAR(128) DEFAULT NULL,
 last_check	 INT DEFAULT NULL,
 type		 VARCHAR(6) NOT NULL,
 notified_serial INT DEFAULT NULL, 
 account         VARCHAR(40) DEFAULT NULL,
 primary key (id)
)type=InnoDB;
 
CREATE UNIQUE INDEX name_index ON domains(name);
 
CREATE TABLE records (
  id              INT auto_increment,
  domain_id       INT DEFAULT NULL,
  name            VARCHAR(255) DEFAULT NULL,
  type            VARCHAR(6) DEFAULT NULL,
  content         VARCHAR(255) DEFAULT NULL,
  ttl             INT DEFAULT NULL,
  prio            INT DEFAULT NULL,
  change_date     INT DEFAULT NULL,
  primary key(id)
)type=InnoDB;
 
CREATE INDEX rec_name_index ON records(name);
CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
 
CREATE TABLE supermasters (
  ip VARCHAR(25) NOT NULL, 
  nameserver VARCHAR(255) NOT NULL, 
  account VARCHAR(40) DEFAULT NULL
);
 
GRANT SELECT ON supermasters TO pdns;
GRANT ALL ON domains TO pdns;
GRANT ALL ON records TO pdns;
 
GRANT SELECT ON supermasters TO pdns;
GRANT ALL ON domains TO pdns;
GRANT ALL ON records TO pdns;

Then edit /etc/powerdns/pdns.d/pdns.local on both servers to configure the backend and enable master/slave operation.

For ns1:

allow-axfr-ips=10.0.0.20
disable-axfr=no
master=yes
launch=gmysql
gmysql-host=127.0.0.1
gmysql-user=pdns
gmysql-dbname=pdns
gmysql-password=<password>

For ns2:

slave=yes
gmysql-host=127.0.0.1
gmysql-user=pdns
gmysql-dbname=pdns
gmysql-password=<password>

Make sure the new configuration is loaded, on both servers run:

# /etc/init.d/pdns restart

Now, add the supermaster to the database on ns2:

INSERT INTO supermasters (ip, nameserver, account) VALUES ('10.0.0.10', 'ns2.example.com', 'admin');

On ns1, create a domain:

INSERT INTO domains (name, type) VALUES ('example.com', 'MASTER');
INSERT INTO records (domain_id, name, content, type, ttl, prio) VALUES (1, 'example.com', 'ns1.example.com hostmaster.example.com 1', 'SOA', 86400, NULL);
INSERT INTO records (domain_id, name, content, type, ttl, prio) VALUES (1, 'example.com', 'ns1.example.com', 'NS', 86400, NULL);
INSERT INTO records (domain_id, name, content, type, ttl, prio) VALUES (1, 'example.com', 'ns2.example.com', 'NS', 86400, NULL);
INSERT INTO records (domain_id, name, content, type, ttl, prio) VALUES (1, 'ns1.example.com', '10.0.0.10', 'A', 86400, NULL);
INSERT INTO records (domain_id, name, content, type, ttl, prio) VALUES (1, 'ns2.example.com', '10.0.0.20', 'A', 86400, NULL);

Now try if it works on ns1:

# dig @10.0.0.10 ns example.com
...
;; QUESTION SECTION:
;example.com.			IN	NS

;; ANSWER SECTION:
example.com.		86400	IN	NS	ns2.example.com.
example.com.		86400	IN	NS	ns1.example.com.

;; ADDITIONAL SECTION:
ns2.example.com.	86400	IN	A	10.0.0.10
ns1.example.com.	86400	IN	A	10.0.0.20
...

The tables on ns2 haven’t been populated yet, but if we update the serial on ns1 and trigger a NOTIFY, it will sync up.

UPDATE records SET content = 'ns1.example.com hostmaster.example.com 2' WHERE id = '1';

The zone is now synchronized, try it out.

Also, consider using a web interface for the management, such as Poweradmin.

Syncing djbdns zones with rsync

I wrote earlier about publishing zones with djbdns. That post didn’t cover zone sync between djbdns servers. This small guide assumes we’ll be syncing all zones between two servers, s01 and s02.

Doing this by using ssh keys instead of regular login has the benefit of not asking for your password when syncing the zones. You can skip this step if you want.

On s01, do the following.

# ssh-keygen -t dsa
# scp ~/.ssh/id_dsa.pub s02:.ssh/authorized_keys

The edit the Makefile file in the root folder of djbdns on s01 and make it look like this.

remote: data.cdb
        /usr/bin/rsync -az -e ssh data.cdb s02:/etc/tinydns/root/data.cdb

data.cdb: data
        /usr/bin/tinydns-data

Adjust all paths according to your own setup.

Running make will now sync your zones to s02.

# make
/usr/bin/tinydns-data
/usr/bin/rsync -az -e ssh data.cdb s02:/etc/tinydns/root/data.cdb
#

gethostbyname in C

As a comparison to my earlier post. Doing this in C is much more efficient. This code prints out 2 (of the 3) A records for test.poller.se.

#include <stdio.h>
#include <netdb.h>
 
struct hostent *he;
struct in_addr **hosts;
 
main(void) {
        he = gethostbyname("test.poller.se");
 
        hosts = (struct in_addr **)he-&gt;h_addr_list;
 
        printf("%s\n", inet_ntoa(*hosts[0]));
        printf("%s\n", inet_ntoa(*hosts[1]));
 
        return 0;
}

This is much faster then the perl approach.

$ time for i in `seq 1 1000`; do ./gethostbyname > /dev/null; done
real    0m10.393s
user    0m0.764s
sys     0m9.065s
Page 1 of 212»