The Swede in the middle of Silicon Valley

Showing posts with label dns. Show all posts
Showing posts with label dns. Show all posts

Wednesday, April 29, 2009

DNS query parser

The last days I've been working on our internal DNS servers looking at the new BIND statistics I enabled 2 weeks back. I sure found some interesting behaviors of some clients that shouldn't be there thanks to it.

Thinking a bit more at statistics I started looking at the query-log, if you have managed a DNS server you know that the query-log tends to build up quickly and it can become pretty unmanageable to troubleshoot unless you've some decent programming skills. Due to this I figured, hell, lets dump the data in a MySQL database so we can run some nice queries to see trending etc.

The code below is what I ended up with. What it does is creating a named pipe (FIFO) that allows BIND to write all query-log data directly a database after being parsed by the script.

Please notice that I'm still working on the code and will post the updates to this post, if you have any proposals or issues with it please email me.

Disclaimer: This code is very much untested and it's expensive to run from a CPU perspective, use caution!

...
logging {
channel query_log {
file "/var/log/querypipe";
time-stamp yes;
}
...


Once started all query-log data is sent to the script and gets parsed, once the writecache has reached it's top the data is being written to the database. The reason for maintaining a writecache is because MySQL with MyISAM has a lot better performance inserting several rows at once rather than one at the time, the backside to this is that you're data wont be real-time which may not be ideal depending on your reporting needs.

CREATE TABLE `queries` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` varchar(25) DEFAULT NULL,
`time` varchar(25) DEFAULT NULL,
`id` int(11) DEFAULT NULL,
`port` int(11) DEFAULT NULL,
`query` varchar(255) DEFAULT NULL,
`rr` varchar(25) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM


To run the code edit the variables to match your system settings, to demonize it run it with -D, once started, run rndc reload or restart your name-server to release locking of the query-log.


#!/usr/bin/perl

use Getopt::Long;
use DBI;
use POSIX qw(setsid);

my $daemon = 0;

Getopt::Long::GetOptions('daemon|D' => \$daemon);


if ($daemon) {
defined(my $pid = fork) or die "Can't fork: $!";
exit if $pid;
setsid or die "Can't start a new session: $!";
}

$SIG{INT} = \&terminate;
$SIG{HUP} = \&terminate;

sub terminate {
unlink $FIFO;
exit 0;
}

while (1) {

my $LOG_PATH = '/var/named/chroot/var/log/';
my $FIFO = $LOG_PATH.'querypipe';
my $RNDC = '/usr/sbin/rndc';
my $user = 'named';

my($login,$pass,$uid,$gid) = getpwnam($user) or die "$user not in passwd file";

my $db = DBI->connect("dbi:mysql:database=dns;host=localhost:3306;user=dns;password=dns") or die "Failed to connecto DB\n";

while (1) {
unless (-p $FIFO) {
unlink $FIFO;
system('mknod', $FIFO, 'p')
&& die "can't mknod $FIFO: $!";
}
chown $uid, $gid, $FIFO;
system("$RNDC reload");
open (FIFO, "< $FIFO") || die "can't read $FIFO: $!";
while () {
my($date, $time, $source, $port, $query, $rr) = /([0-9]{1,2}-[A-Za-z]{3}-[0-9]{4}) ([0-9]{2}:[0-9]{2}:[0-9]{2}).[0-9]{1,5} client (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})#([0-9]{1,5}): query: (.*) IN (.*) +/;

my $statement = $db->prepare("INSERT INTO `queries` values (NULL, '$date', '$time', '$source', '$port', '$query', '$rr')");
$statement->execute() or die "Failed to write to DB!";
}
close FIFO;
}
}


Planned additions:
- Help-messages
- Function to log
- Auto adjust write frequency based on load
- Clean-up
- Fix MySQL table to use appropriate fields

Sunday, April 5, 2009

Enabling your recursive BIND server to support DNSSEC

So I've been doing some BIND hacking this weekend looking into enabling my recursive BIND instance to do DNSSEC lookups if available.

Since the root-servers today doesn't have native support for DNSSEC DLV (Look-aside Validation) has to be used. ISC provides one of these giving somewhat of a proxying DNSSEC validation.

To enable DNSSEC lookups on your servers the easiest approach is to use dnssec-configure which reconfigures your named.conf with the appropiate variables. To enable, run:
dnssec-configure --dnssec=on --dlv=on -u -b
This will add the following to your config:
options {
...
dnssec-enable yes;
dnssec-validation yes;
dnssec-lookaside . trust-anchor dlv.isc.org.;
dnssec-accept-expired yes;
...
}

...
include "/etc/named.dnssec.keys";
Open up /etc/named.dnssec and add the following to enable DLV:
include "/etc/pki/dnssec-keys/dlv/dlv.isc.org.conf";
This includes the DNSKEY of dlv.isc.org which is required to validate lookups towards this server. Unless you include the key lookups will not work. Notice that you may have to shuffle the files around a bit to adopt to your setup.

After you restart named your BIND server will query the DLV server for secure lookups, if you have logging enabled you will be able to see DNSSEC debug records.

As you probably know, when using signed entities keys are refreshed with a set constant of time. The recommended time for a DNSKEY is 1 month. Due to this the key you have present in your dlv.isc.org.conf will become deprecated after 1 month. I decided to solve this by making a perl-script re-creating the dlv-configuration every night to ensure that my server doesn't loose the capability of doing lookups. If DLV is unavailable no recursion will work!

Here's the script:

#!/usr/bin/perl

use IO::File;
use strict;
use warnings;
use Net::DNS;
use Data::Dumper;

my $dlv_file = "/var/named/chroot/etc/pki/dnssec-keys/dlv/dlv.isc.org.conf";

my $res = Net::DNS::Resolver->new(
nameservers => [qw(127.0.0.1)],
recurse => 1,
debug => 0
);

my $dnssec_key = $res->query("dlv.isc.org", 'DNSKEY');

my $dlvconf = new IO::File('<'.$dlv_file);

sub nl2br {
my $t = shift or return;
$t =~ s/([\r\n])/$1/g;
return $t;
}

open FILE, ">".$dlv_file;
print FILE "trusted-keys {\n\n";
print FILE for map {

"dlv.isc.org. ".$_->flags.' '.$_->protocol.' '.$_->algorithm.' "'.nl2br($_->key)."\";\n"

} $dnssec_key->answer;

print FILE "};\n";
close (FILE);

chown 25, 25, $dlv_file;

system("rndc reload");

exit 0;

Add the script to crontab and it will automatically update the DLV key as needed.

Saturday, May 3, 2008

BIND: Semi-dual master


Lately I've tried to figure out a couple of ways to have a redudant master setup of BIND. BIND itself doesn't have any features to support this which has been bothering me as it would be useful to fail over to a secondary slave.

After numerous discussins on the bind-users list I've reached the conclusion of how I would do it, described in the picture to the right.

BIND slaves is able to notify other slaves when changes occur. To utilize this I would have 1 primary master, and a secondary master which acts as a slave towards the primary. Both of these servers wouldn't allow queries from clients but they would feed the slave-servers acting as DNS-servers for clients on the network.

Unfortunatly this doesn't solve the entire problem as the slave doesn't take flags such as allow-update, or update-policy. The best way to solve this is most likely going to be some kind of script syncing the primary config to a standby file at the secondary.

I'll be working on this solution the coming weeks and post further info I gather along the way.

Saturday, February 2, 2008

How to enable BIND with DNSSEC and Secure Dynamic Update using SIG(0)

For the last couple of days I've been struggling trying to figure out how to get DNSSEC with SDU (Secure Dynamic updates) to work using SIG(0) keys. I was almost at the edge of giving up when a colleague of mine proposed to try it out in RHEL 5.1 and file a bug report to RedHat, and so I did only to get the surprise that it worked perfectly fine.

Since I've spent so much time on this I decided to blog on how to do this. I hope someone get use of this blogpost.

First off please notice that this configuration was made using:

Red Hat Enterprise Linux Server release 5.1 (Tikanga)
Linux dl360-g5-i.mysql.com 2.6.18-53.1.6.el5 #1 SMP Wed Jan 16 03:56:43 EST 2008 i686 i686 i386 GNU/Linux
bind-chroot-9.3.3-10.el5



I can not guarantee that it will work with whatever setup you're using!

The tools used to enable DNSSEC and SDU is:

  • dnssec-keygen
  • dnssec-signzone
  • nsupdate
First off we need to configure named.conf, here's an example configuration:

options {
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";

version "secret";

querylog yes;

allow-transfer { 127.0.0.1; };

key-directory "/etc/keys";
};

logging {
channel my_security_channel {
file "/var/logs/named_log.txt" versions 20 size 40m;
print-time yes;
severity debug 2;
};

channel my_dynamic_channel {
file "/var/logs/dynamic_log.txt" versions 2 size 40m;
print-time yes;
severity debug 65535;
};

category default { my_security_channel; };

category default { my_dynamic_channel; };
category client { my_dynamic_channel; };
category config { my_dynamic_channel; };
category database { my_dynamic_channel; };
category delegation-only { my_dynamic_channel; };
category dispatch { my_dynamic_channel; };
category dnssec { my_dynamic_channel; };
category general { my_dynamic_channel; };
category lame-servers { my_dynamic_channel; };
category network { my_dynamic_channel; };
category notify { my_dynamic_channel; };
category queries { my_dynamic_channel; };
category resolver { my_dynamic_channel; };
category security { my_dynamic_channel; };
category unmatched { my_dynamic_channel; };
category update { my_dynamic_channel; };
category update-security { my_dynamic_channel; };
category xfer-in { my_dynamic_channel; };
category xfer-out { my_dynamic_channel; };

};

view "internal" {
match-clients { 127.0.0.1; };

recursion yes;
allow-recursion { localhost; };

zone "example.com" IN {
type master;
file "data/example.com.db.signed";
update-policy {
grant example.com subdomain example.com. any;
};
};
};

include "/etc/rndc.key";


This configuration is pretty straight forward and doesn't have to many elements to it but to an unknown user there might be some unknowns.

version "secret";
First off we want to make sure that a potential intruder isn't aware of which version of BIND we're using. If an intruder has knowledge about the flaws in a certain version of BIND we're taking the risk of being exploited.

key-directory "/etc/keys"
BIND needs to be aware of your private keys when doing updates, otherwise the changes you'll make will not be signed and you'll have to do a manual resign of the zone which kills the purpose of dynamic updates.

logging
When dealing with DNSSEC it's important to know what's going on, in the example configuration pretty much all logging is enabled to give us a wide picture of what kind of connections and data-transfers that's passing to and from your server. All of it isn't a necessary but logs are always more useful than one think.

view "internal"
This element isn't really necessary in this simple setup but if you have a DNS server that hosts different zones in different networks (external/internal) this is crucial to not distribute your internal zones. It also to enable the right person to get the right data.

recursion "yes"
Recursion allows clients to resolve domains and or hosts that your server isn't authoritative for. This isn't necessary in this example but can be useful.

allow-recursion { localhost };
This is yet an element which isn't necessary in this setup but it's important to know that you don't want to have recursion enabled for anyone but trusted sources. Your DNS server should only host your domains unless it's internal or intended to allow recursive traffic.

file "data/example.com.db.signed"
Usually you would probably use something like example.com.db but when signing the zone-file the name is changed to .signed there is however a flag in dnssec-signzone letting you decide the output name of the file so it's really up to you if you want to use the .signed suffix or not.

update-policy
To enable us to do dynamic updates we need to have permission to do it. The grant statements tells the BIND server what which key is allowed to change. There's multiple options for this but for now we want this key to be able to change anything.

Now that we've a configured named.conf we want to create a couple of directories for the files to be placed in. In this example we're using the chrooted package from RedHat, notice that you're setup might be different.

First of we want to create directories for the keys and log files
mkdir /var/named/chroot/var/logs
mkdir /var/named/chroot/etc/keys
Followed by that is a couple of symlinks to make our life easier when accessing files.
ln -s /var/named/chroot/etc/named.conf /etc/named.conf
ln -s /var/named/chroot/etc/keys /etc/keys
We also need to make sure that BIND has full permission of the folders, unless it has it wont be able to pick up the keys necessary.
chown -R named:named /var/named/chroot/var/logs
chown -R named:named /var/named/chroot/etc/keys
Now that we've all of the directories available we need to create a zone-file. Go to /var/named/chroot/var/named/data and open up your favorite editor. When you're in the editor you want to post the following conf:
$ORIGIN .
$TTL 3600 ; 1 hour
example.com IN SOA ns1.example.com. hostmaster.example.com (
2008020201 ; serial
7200 ; refresh
3600 ; retry
604800 ; expire
3600 ; minimum
)
NS ns1.example.com.
$ORIGIN example.com.
ns1 A 127.0.0.1
Remember that your settings may vary.

As we're finished with the zone file we need to create a couple of keys, one for DNSSEC and one for SDU. The reason why we've two different keys is because DNSSEC leverage DNSKEY while SDU uses KEY. This also adds an additional set of security by separating signing from updating.

To create the keys go to your key folder /etc/keys and execute the following commands:
dnssec-keygen -a rsasha1 -b 1024 -n zone example.com
dnssec-keygen -k -a rsasha1 -b 1024 -n zone example.com
The first command generates the keys you need to sign your zone, meanwhile the second generates the keys for the updates. When finished you'll have 4 keys named Kexample.com.+005+12345.private and .key.

What we need to do now is to add our DNSKEY and KEY to our zone file, you can either copy and paste the content in the .key files or execute the following command:
cat /etc/keys/Kexample.com.*.key >> /var/named/chroot/var/named/data/example.com.db
You'll now have two entries at the bottom of the zone file looking similar to this:
example.com. IN KEY 256 3 5 AwEAAcldVDO9D1NM7zVCOt2hrXoKJw8Vd2O37N5ykJcK2ODgDlCnXo6R lt/HjzIPZq4A04a0X/9AJVpDk8sZQP4kkbcv4WkXpmKSFJyhIW3B7b+k ouWnyPkym0EEFrSmIaKKQw4asMaH2Ei\
WBpOEWPeFWRtD2lX8YZRVm1tE Si8GH/oT
example.com. IN DNSKEY 256 3 5 AwEAActFWDC3bvmy6U5URVjz+EzmP/vbkUu8c0SUPpce3mv11DptfEo9 +BiY3A0NUPNfLXgIH1h75A6ZUPDBGApU54NsYJNo9bBPlcvWj7MA0VX6 wdPODqUNhuRfVrA8a3nuUC0PzSN1\
wC+sl396P91sWq9lYbYLjujm/nEg tREih0EB
We're now ready to sign our zone.

Go to your data directory /var/named/chroot/var/named/data/. It's now important that you sign with the correct key, compare the content in both .key keys and remember the name of the one containing the DNSKEY statement, this is the key we're going to use to sign our zone.
To sign the zone execute the following command:
dnssec-signzone -t -g -o example.com example.com.db /etc/keys/Kexample.com.+005+12345.private
This should give you an output that's similar to this:
example.com.db.signed
Signatures generated: 21
Signatures retained: 0
Signatures dropped: 0
Signatures successfully verified: 0
Signatures unsuccessfully verified: 0
Runtime in seconds: 0.114
Signatures per second: 182.734
If you get the errormessage dnssec-signzone: cannot load dnskey /etc/keys/Kexample.com.+005+26385.private: bad key type
you tried to use an incorrect key.

After running the script you'll have 3 new files in the data-directory:
  • example.com.db.signed
  • dsset-example.com
  • keyset-example.com

The one that's of interest for us is the example.com.db.signed file which should look similar to this:
$ORIGIN .
$TTL 3600 ; 1 hour
example.com IN SOA ns1.example.com. hostmaster.example.com. (
2008020202 ; serial
7200 ; refresh (2 hours)
3600 ; retry (1 hour)
604800 ; expire (1 week)
3600 ; minimum (1 hour)
)
RRSIG SOA 5 2 3600 20080304065047 (
20080203055047 51525 example.com.
TZNrgK8y35vEcDrB4pMVvf0+nV5HRcL+9gQvfxrlPV6F
rt9+8WjSQTug63G3YdpEWIPXB1hZvgovpWRrK6MsImex
Vvx8US59jJLjjQowG7DiD2XYcfg23ufgHfpNv71X0QuM
ZkyntzvGOL7wn+SgbJDglersJkbKJzFv5FJrBks= )
NS ns1.example.com.
RRSIG NS 5 2 3600 20080304054131 (
20080203054131 51525 example.com.
hTQF3MyTnlvfkvSCtUAvQltzyIo5vvo3K33cDzD+Ahc2
z9hBelkGLZu6XO0B3bvWLbzKzCFkUVjjMDtWPMnd3Srx
RGqspo1HGqvU0gT6W6OTXeevgKbcHZ0Ctt6gDF03EgEI
qmAlWlpRhWMCdgJ7XhM41fvsSE7LdiKsiX3XrE8= )
KEY 256 3 5 (
AwEAAcldVDO9D1NM7zVCOt2hrXoKJw8Vd2O37N5ykJcK
2ODgDlCnXo6Rlt/HjzIPZq4A04a0X/9AJVpDk8sZQP4k
kbcv4WkXpmKSFJyhIW3B7b+kouWnyPkym0EEFrSmIaKK
Qw4asMaH2EiWBpOEWPeFWRtD2lX8YZRVm1tESi8GH/oT
) ; key id = 17781
RRSIG KEY 5 2 3600 20080304054131 (
20080203054131 51525 example.com.
YpfIG5nM45Ty3HSpD0sGbeM84WhNCtVP9wayQPt9F6zd
6Tdu+NanfoAdiQ0oIDTd5nLToTk81sihcNClvAHPwpff
VtkQ2g+vEjJuPEL53vN6WL81Fh//a+6P8O410wxNGajC
rrYt5WI2bId8SJ+Sw0kzBgzxRoH+7F1+/O3zL2o= )
NSEC ns1.example.com. NS SOA KEY RRSIG NSEC DNSKEY
RRSIG NSEC 5 2 3600 20080304054131 (
20080203054131 51525 example.com.
rcQlAb+bS62KuNA4EpFFKpbmy+bFxw3sSZO+unB4CmM1
5PycFPbFm4m2+OQLoy20IM85ugszUsReOfCtEe/JEe6Q
eEQGm/JmFnQJ2mf5yYn4cN+DId8+FVwG6kvIcjCjmNbC
pz7NWYdM1lbeBFASIXF+es9rSg4kjSmJmS2f5Pg= )
DNSKEY 256 3 5 (
AwEAActFWDC3bvmy6U5URVjz+EzmP/vbkUu8c0SUPpce
3mv11DptfEo9+BiY3A0NUPNfLXgIH1h75A6ZUPDBGApU
54NsYJNo9bBPlcvWj7MA0VX6wdPODqUNhuRfVrA8a3nu
UC0PzSN1wC+sl396P91sWq9lYbYLjujm/nEgtREih0EB
) ; key id = 51525
RRSIG DNSKEY 5 2 3600 20080304054131 (
20080203054131 51525 example.com.
mkegJTmyMG6uEC9DkG7KUExvHOj3q2iDgaEmw7o9RB1s
ETUvwd8uteCH13TvBZ3EXMxdpEFaE4EhccYIArUlqarA
z1kzeCyslyIGS4TwsZTR94/cQY8F6Yv8cv8u+ISxSoO+
hZCLXOrQ9wyMhx82smT/NycwvLzHxtgikvWLWw4= )
$ORIGIN example.com.
ns1 A 127.0.0.1
RRSIG A 5 3 3600 20080304054131 (
20080203054131 51525 example.com.
BzvAbDGuu4rEE6kDjXehVIULkGajBJXF/B6D27k9DWIH
9MJ/vi9frE/E4jLz/frY3rHdDgtolGX05SphuEsFdmMo
G1a1yQIvfJVHY5L0Xc03qMquhsXVd5yJS5DwyxEZuxqZ
DMgeLjp0bm9M1FabOhpIcm4gQqu5JTxHo/5CEtw= )
NSEC testing A RRSIG NSEC
RRSIG NSEC 5 3 3600 20080304065047 (
20080203055047 51525 example.com.
tNNunF81mxfWJaUYtwtAkirNaV7J9cUKni7pZTL2FAMi
kmQDnTKQUP5a4nogDT9zB0gRxr0pL1lpVC3vSV7tJAl7
t7/R9DE6wO7I3VA08wTyKc2k9rS0xA06C4SPwWJGHZXl
nxxck4gAunaum+FXlqnY9YILnCbapWlCQGTkCa8= )
testing CNAME example.com.
RRSIG CNAME 5 3 3600 20080304065047 (
20080203055047 51525 example.com.
RknsWLMnxfD1ixiNezyHNLRSK/GKf19N9EXvQopa7pji
ziyqf3uYWKrJtnGQoe8vdpy8GbTrWw5ZzdxlYVe66cGC
q+saQEc9KdTOo6kDCH7WrXnY9Tko6+tPTZqM61XvyLQa
BqZKKi6bkktJv6orhbyx4KuyFdVTL/wW4h3HpUs= )
NSEC example.com. CNAME RRSIG NSEC
RRSIG NSEC 5 3 3600 20080304065047 (
20080203055047 51525 example.com.
GtV/5WFPMph2EVoPNe/fbhOxZG8sANoAw4GayI1esMqV
qTshx4yWlJt02TTtNc4AsAjk6NBi7ctQWXgtHitDeAzJ
pRhImA9RRY082WkG2GCCVCf4a/ldcf4SQt6E3C6wj+5P
iI+Uz4BjAAEHxfT7mB19m1YLo7MVhxlKe6QFW1c= )

Our zone is now signed and we can start bind.
/etc/init.d/named start
If the startup script complains about anything have a look at the permission and the config file.

As we're up and running we're now ready to run a Secure Dynamic update. For this we'll be using nsupdate.

To add a new A record execute the following:
nsupdate -d -v -k /etc/keys/Kexample.com.+005+12345.private
server 127.0.0.1
zone example.com
update add testing.example.com. 3600 A 127.0.0.1
show
send
show
Provided that you've all the permission and configuration right you should see something like this:
Creating key...
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 0 ;; flags: ; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0 ;; UPDATE SECTION: testing2.example.com. 3600 IN CNAME example.com. Sending update to 127.0.0.1#53 Outgoing update query: ;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 61419 ;; flags: ; ZONE: 1, PREREQ: 0, UPDATE: 1, ADDITIONAL: 1 ;; ZONE SECTION: ;example.com. IN SOA ;; UPDATE SECTION: testing2.example.com. 3600 IN CNAME example.com. ;; SIG0 PSEUDOSECTION: . 0 ANY SIG 0 5 0 0 20080203081438 20080203080438 17781 example.com. aa+FdvAx/qpSSHEO2SHFeG+dSWgJ3L81UfLOeyxA2QkxEJV6pHrCL34k eBs2W/Ay7KPL7UMd/OAyVo1tjotbeNFkbO8O/+/sBltNttHOOYg6W4Cf gvOX3z/OwGqVQiu2OluRGsu7tN3LEl4IlgJMChIg1yJ+xl7bSaoa8QQI OmU= Reply from update query: ;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 61419 ;; flags: qr ra ; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0 Outgoing update query: ;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 0 ;; flags: ; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0

You've now added an A record dynamically to your zone!

If you've a look in the log-file /var/named/chroot/var/logs/dynamic_log.txt you should see something similar to this:

03-Feb-2008 09:13:39.364 client 127.0.0.1#48060: TCP request
03-Feb-2008 09:13:39.364 client 127.0.0.1#48060: view internal: using view 'internal'
03-Feb-2008 09:13:39.364 client 127.0.0.1#48060: view internal: request is not signed
03-Feb-2008 09:13:39.364 client 127.0.0.1#48060: view internal: recursion available
03-Feb-2008 09:13:39.364 client 127.0.0.1#48060: view internal: query
03-Feb-2008 09:13:39.364 client 127.0.0.1#48060: view internal: AXFR request
03-Feb-2008 09:13:39.364 client 127.0.0.1#48060: view internal: transfer of 'example.com/IN': AXFR question section OK
03-Feb-2008 09:13:39.364 client 127.0.0.1#48060: view internal: transfer of 'example.com/IN': AXFR authority section OK
03-Feb-2008 09:13:39.364 client 127.0.0.1#48060: view internal: zone transfer 'example.com/AXFR/IN' approved
03-Feb-2008 09:13:39.364 client 127.0.0.1#48060: view internal: ns_client_attach: ref = 1
03-Feb-2008 09:13:39.364 client 127.0.0.1#48060: view internal: transfer of 'example.com/IN': AXFR started
03-Feb-2008 09:13:39.364 example.com. 3600 IN SOA ns1.example.com. hostmaster.example.com. 2008020206 7200 3600 604800 3600
03-Feb-2008 09:13:39.364 example.com. 3600 IN RRSIG SOA 5 2 3600 20080304081335 20080203071335 51525 example.com. ars67v4wWyWVuf/HPPfScgSUvGi7lX+qq0+nzMq\
8+uoeSUBkg4d8OHn6 FZ39YVVie4CQ/aV8J4aanwnrPnbuHeDEODuYr4btXpZRsF4WtsCfesyH ZhzqzKw04GS90/NNlAIedT+r0ZsCkkLR8kon4LecEyo8qPqbO3aUuX2I FgY=
03-Feb-2008 09:13:39.364 example.com. 3600 IN NS ns1.example.com.
03-Feb-2008 09:13:39.364 example.com. 3600 IN RRSIG NS 5 2 3600 20080304054131 20080203054131 51525 example.com. hTQF3MyTnlvfkvSCtUAvQltzyIo5vvo3K33cDzD+\
Ahc2z9hBelkGLZu6 XO0B3bvWLbzKzCFkUVjjMDtWPMnd3SrxRGqspo1HGqvU0gT6W6OTXeev gKbcHZ0Ctt6gDF03EgEIqmAlWlpRhWMCdgJ7XhM41fvsSE7LdiKsiX3X rE8=
03-Feb-2008 09:13:39.365 example.com. 3600 IN KEY 256 3 5 AwEAAcldVDO9D1NM7zVCOt2hrXoKJw8Vd2O37N5ykJcK2ODgDlCnXo6R lt/HjzIPZq4A04a0X/9AJVpDk8sZQP4kkbcv\
4WkXpmKSFJyhIW3B7b+k ouWnyPkym0EEFrSmIaKKQw4asMaH2EiWBpOEWPeFWRtD2lX8YZRVm1tE Si8GH/oT
03-Feb-2008 09:13:39.365 example.com. 3600 IN RRSIG KEY 5 2 3600 20080304054131 20080203054131 51525 example.com. YpfIG5nM45Ty3HSpD0sGbeM84WhNCtVP9wayQPt\
9F6zd6Tdu+NanfoAd iQ0oIDTd5nLToTk81sihcNClvAHPwpffVtkQ2g+vEjJuPEL53vN6WL81 Fh//a+6P8O410wxNGajCrrYt5WI2bId8SJ+Sw0kzBgzxRoH+7F1+/O3z L2o=
03-Feb-2008 09:13:39.365 example.com. 3600 IN NSEC ns1.example.com. NS SOA KEY RRSIG NSEC DNSKEY
03-Feb-2008 09:13:39.365 example.com. 3600 IN RRSIG NSEC 5 2 3600 20080304054131 20080203054131 51525 example.com. rcQlAb+bS62KuNA4EpFFKpbmy+bFxw3sSZO+un\
B4CmM15PycFPbFm4m2 +OQLoy20IM85ugszUsReOfCtEe/JEe6QeEQGm/JmFnQJ2mf5yYn4cN+D Id8+FVwG6kvIcjCjmNbCpz7NWYdM1lbeBFASIXF+es9rSg4kjSmJmS2f 5Pg=
03-Feb-2008 09:13:39.365 example.com. 3600 IN DNSKEY 256 3 5 AwEAActFWDC3bvmy6U5URVjz+EzmP/vbkUu8c0SUPpce3mv11DptfEo9 +BiY3A0NUPNfLXgIH1h75A6ZUPDBGApU54Ns\
YJNo9bBPlcvWj7MA0VX6 wdPODqUNhuRfVrA8a3nuUC0PzSN1wC+sl396P91sWq9lYbYLjujm/nEg tREih0EB
03-Feb-2008 09:13:39.365 example.com. 3600 IN RRSIG DNSKEY 5 2 3600 20080304054131 20080203054131 51525 example.com. mkegJTmyMG6uEC9DkG7KUExvHOj3q2iDgaEm\
w7o9RB1sETUvwd8uteCH 13TvBZ3EXMxdpEFaE4EhccYIArUlqarAz1kzeCyslyIGS4TwsZTR94/c QY8F6Yv8cv8u+ISxSoO+hZCLXOrQ9wyMhx82smT/NycwvLzHxtgikvWL Ww4=
03-Feb-2008 09:13:39.365 ns1.example.com. 3600 IN A 127.0.0.1
03-Feb-2008 09:13:39.365 ns1.example.com. 3600 IN RRSIG A 5 3 3600 20080304054131 20080203054131 51525 example.com. BzvAbDGuu4rEE6kDjXehVIULkGajBJXF/B6D27k9D\
WIH9MJ/vi9frE/E 4jLz/frY3rHdDgtolGX05SphuEsFdmMoG1a1yQIvfJVHY5L0Xc03qMqu hsXVd5yJS5DwyxEZuxqZDMgeLjp0bm9M1FabOhpIcm4gQqu5JTxHo/5C Etw=
03-Feb-2008 09:13:39.365 ns1.example.com. 3600 IN NSEC testing.example.com. A RRSIG NSEC
03-Feb-2008 09:13:39.365 ns1.example.com. 3600 IN RRSIG NSEC 5 3 3600 20080304081335 20080203071335 51525 example.com. q4HaSLSsYfO2SMw/MVnfiZsgxQ1PHCzHIaWmZG\
sZ4MkRwEYYPZN3ID1c kisMR2DUU+/5tzrJnflipOfyXTU0ecHGbIpiI8buuM/zqgHgEAxSFDJG TkA06pkqsXCfllDwh7ClLMaK/SeBdudvB2wXHNtUFfXNmmve+SHGsTE6 G+Q=
03-Feb-2008 09:13:39.365 testing.example.com. 3600 IN RRSIG NSEC 5 3 3600 20080304081335 20080203071335 51525 example.com. hVCltJNA9X2/dD77uwLzWrpmVYYvNEAkdTU4qV\
QL2+8ZHxt553DA3eFk DF5qd74L+rs2piDgVZ7L0qYzzPGO8pZAyw9HyGKF0adi40NdhVhPegy3 Tax1ThTcayuNTPE/t7nSwgfWKEDdSQVBjIZ4GFQKYIigAIGyKnmWKe2v 0JM=
03-Feb-2008 09:13:39.365 testing.example.com. 3600 IN NSEC example.com. A RRSIG NSEC
03-Feb-2008 09:13:39.365 testing.example.com. 3600 IN RRSIG A 5 3 3600 20080304081335 20080203071335 51525 example.com. FZi8W+FsfUjSur8HfMVjrn6hJEOL0ewZoKuwBJ9QA\
lsqLwYs0TRA3HGU nSN6pXypaw0d0udBo+0IQq/lW4C3FScDpNwCZqWlSmjMEpR/C7d7uPNh jUARGcq9pXdSaJ439QtSARLXNL/8tVZjCUglwYAX8/4bbPvjNOIPrOi1 NHs=
03-Feb-2008 09:13:39.365 testing.example.com. 3600 IN A 127.0.0.1
03-Feb-2008 09:13:39.365 example.com. 3600 IN SOA ns1.example.com. hostmaster.example.com. 2008020206 7200 3600 604800 3600
03-Feb-2008 09:13:39.365 client 127.0.0.1#48060: view internal: transfer of 'example.com/IN': sending TCP message of 2109 bytes
03-Feb-2008 09:13:39.365 client 127.0.0.1#48060: view internal: transfer of 'example.com/IN': AXFR ended
03-Feb-2008 09:13:39.365 client 127.0.0.1#48060: view internal: next
03-Feb-2008 09:13:39.365 client 127.0.0.1#48060: view internal: ns_client_detach: ref = 0
03-Feb-2008 09:13:39.365 client 127.0.0.1#48060: view internal: endrequest
03-Feb-2008 09:13:39.365 client 127.0.0.1#48060: read


To completely verify that you're record has been added do a zone-transfer and grep for your entry:

host -t axfr example.com localhost | grep testing

testing.example.com. 3600 IN RRSIG NSEC 5 3 3600 20080304081335 20080203071335 51525 example.com. hVCltJNA9X2/dD77uwLzWrpmVYYvNEAkdTU4qVQL2+8ZHxt553DA3eFk DF5qd74L+rs2piDgVZ7L0qYzzPGO8pZAyw9HyGKF0adi40NdhVhPegy3 Tax1ThTcayuNTPE/t7nSwgfWKEDdSQVBjIZ4GFQKYIigAIGyKnmWKe2v 0JM=
testing.example.com. 3600 IN NSEC example.com. A RRSIG NSEC
testing.example.com. 3600 IN RRSIG A 5 3 3600 20080304081335 20080203071335 51525 example.com. FZi8W+FsfUjSur8HfMVjrn6hJEOL0ewZoKuwBJ9QAlsqLwYs0TRA3HGU nSN6pXypaw0d0udBo+0IQq/lW4C3FScDpNwCZqWlSmjMEpR/C7d7uPNh jUARGcq9pXdSaJ439QtSARLXNL/8tVZjCUglwYAX8/4bbPvjNOIPrOi1 NHs=
testing.example.com. 3600 IN A 127.0.0.1
You now have a functioning DNSSEC and SDU setup.