[net-dns-users] IXFR methods
Chris Buxton
chris at buxtonfamily.us
Tue Dec 18 20:22:55 UTC 2012
Hello all,
As Doug said, it's very nice to have a list.
Has anyone else created an IXFR method for Net::DNS::Resolver? I have, and I think it's pretty good, but I think it could probably be improved.
Here's my code -- requires perl 5.10 or later:
# Hack IXFR capability into Net::DNS::Resolver
sub Net::DNS::Resolver::Base::ixfr($$$)
{
my( $res, $zone, $serial ) = @_;
local $_;
# Send IXFR requests over TCP
$res->usevc(1);
# Construct the request. It contains an abbreviated SOA record in
# the authority section, where the only fields that matter are name,
# class, type, and old serial number.
my $packet = new Net::DNS::Packet( $zone, 'IXFR' );
my $soa = Net::DNS::RR->new(
name => $zone,
type => 'SOA',
mname => '',
rname => '',
serial => $serial,
refresh => 0,
retry => 0,
expire => 0,
minimum => 0
);
$packet->push( authority => $soa );
# Send the request and store the result in an array reference.
my $result = $res->send( $packet );
# The method here is, we're going to accumulate records into arrays
# of @$items, and then put those into @$hunks like [ $mode, $items
# ]. We then push each $hunk onto @diff. $mode will switch from '+'
# to '-' and back again for each new @$hunk. Therefore:
#
# @diff = (
# [ $mode, [ $rr, ... ] ],
# ...
# )
#
# Each @$hunk ends with an SOA record. Every time we encounter an
# SOA record, we start a new hunk right afterward (with the next
# record) and switch the $mode (the operator for each hunk).
#
# If you look carefully, you'll see that the very first SOA record
# is inserted into an empty @$items, but this @$items array doesn't
# get attached to @diff before being replaced with a fresh array. So
# we're processing it to set the $mode, but we're otherwise throwing
# it away.
#
# The last hunk (started after the final SOA record of the IXFR) has
# no records. Always. So we remove it before returning @diff.
# Therefore, an IXFR that requests changes since the current serial
# will return an empty array; an AXFR-style IXFR will contain
# exactly one hunk. To summarize:
#
# @diff == 1 # no changes since the presented serial number
# @diff == 2 # AXFR-style IXFR
# @diff > 2 # Normal IXFR containing changes
#
# Algorithm to interpret an IXFR courtesy of Mark Andrews @ISC, via
# a quick and dirty awk script he posted to BIND Users.
# Get ready to parse the result.
my( @diff, $hunk, $items );
my $mode = '-';
for my $rr ( $result->answer )
{
given( $rr->type )
{
when( 'SOA' )
{
push @$items, $rr;
$mode = ( $mode eq '-' ? '+' : '-' );
$hunk = [ $mode, [] ];
$items = $hunk->[1];
push @diff, $hunk;
}
when( [ qw( RRSIG NSEC NSEC3 NSEC3PARAM ) ] )
{
# Strip out DNSSEC records like this, as we can't really
# do anything useful with them
}
when( 'TSIG' )
{
# TODO: Add some error checking here
# For now, strip these out also
}
default
{
# Anything else gets added to @$items
push @$items, $rr;
}
}
}
# Discard the empty hunk from the end and return everything else
pop @diff;
return @diff;
}
Chris
More information about the net-dns-users
mailing list