The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Net::DNS::Zone::ParserX - A Zone Pre-Parser (slightly altered fork in cpanel2autodns)

VERSION

version 0.1

SYNOPSIS

OO package that implements an RFC complient zone file (pre)parser. perldoc Net::DNS::Zone::Parser for details.

DESCRIPTION

The Net::DNS::Zone::Parser should be considered a preprocessor that "normalizes" a zonefile.

It will read a zonefile in a format conforming to the relevant RFCs with the addition of BIND's GENERATE directive from disk and will write fully specified resource records (RRs) to a filehandle. Whereby:

- all comments are stripped;
- there is one RR per line;
- each RR is fully expanded i.e. all domain names are fully qualified (canonicalised) and the CLASS and TTLs are specified.
- Some RRs may be 'stripped' from the source or otherwise processed. For details see the 'read' method.

Note that this module does not have a notion of what constitutes a valid zone; it only parses. For example, the parser will happilly parse RRs with ownernames that are below in another zone because a NS RR elsewhere in the zone.

FORK

Requirement for Net::DNS::SEC blocked adoption.

METHODS

new

   my $parser=Net::DNS::Zone::Parser->new($io);

Creates the a parser instance.

The optional argument should be a IO::File or IO::Handle type of object. If not specified a temporary IO::File type object will be created to which the lines will be printed. This object can be obtained using the get_io method

get_io

   my $io=$parser->get_io;
   $io->seek(0,0);
   print while (< $io >);

Returns the filehandle to which the zone file has been written. This is either the filehandle specified as argument to the new() method or one that points to a temporary file.

read

    my $parser=Net::DNS::Zone::Parser->new;
    $parser->read("/tmp/example.foo");
    $parser->read("/tmp/foo.db",
                { ORIGIN => "example.db",
                  };

# alternatively

    $returnval=$parser->read("/tmp/foo.db",
                { ORIGIN => "example.db",
                  CREATE_RR => 1,
                  STRIP_SEC => 1,
                  };
    if ($returnval) {
         die $returnval;
    }else{
         $RRarrayref=$parser->get_array();
    }

'read' reads a zonefile from disk to 'pre-processes' it. The first argument is a path to the zonefile. The second parameter is a hash with optional arguments to tweak the reading.

The read method returns 0 on success and a string starting with "READ FAILURE:" and a description on why the error occurred, on error.

The zone file is written (streamed) to a filehandle, also see the get_io method.

The HASH may contain 1 or more of the following arguments.

ORIGIN

the origin of the zone being parsed. if ommited the origin is taken to be the same as the name of the file.

CREATE_RR

if the value evaluates to TRUE an array of Net::DNS::RR objects is build that can be returned using the get_array method. When CREATE_RR is true the read module will fail if Net::DNS::RR->new() cannot parse the input i.e. when the RDATA of a RR is not correctly specified. Since the instance maintains the RR array in core setting this variable may be problematic for large zones.

STRIP_RRSIG

if the value evaluates to TRUE all RRSIG RRs in the zone are ignored i.e. stripped from the output

STRIP_NSEC

if the value evaluates to TRUE all NSEC RRs in the zone are ignored i.e. stripped from the output

STRIP_DNSKEY

if the value evaluates to TRUE all DNSKEY RRs and their related RRSIGs in the zone are ignored i.e. stripped from the output

STRIP_SEC

if the value evaluates to TRUE all DNSKEY, RRSIG and NSEC RRs in the zone are ignored i.e. stripped from the output

STRIP_OLD

if this value evaluates to TRUE all NXT and SIG RRs are ignored (the KEY RRs are _not_ ignored).

BUMP_SOA

if this value evaluates to TRUE the SOA serial will be increased by 1 when written to the filehandle.

get_array

Returns a reference to the array that is created if CREATE_RR is set to true during the read method.

get_origin

    my $origin=$parser->get_origin;

Returns the origin of the zone that was parsed.

build_regex

This code is simalar but not equal to the Net::DNS::RR function. The resulting regexp is just slightly different.

FUNCTIONS

processGENERATEarg

  use Net::DNS::Zone::Parser (processGENERATEarg)
  $generated=processGENERATEarg(0.0.${1,3},5,"inaddr.arpa."

This exported function parses the "LHS" and "RHS" from a BIND generate directive. The first argument contains the "LHS" or "RHS", the second argument the iterator vallue and the last argument contains the value of the "origin" that is to be added if the result of the generate is not a FQDN (it is the vallue that is stupidly appended if the synthesized name does not end with a ".").

From the BIND documentation:

lhs describes the owner name of the resource records to be created. Any single $ symbols within the lhs side are replaced by the iterator value. To get a $ in the output you need to escape the $ using a backslash \, e.g. \$. The $ may optionally be followed by modifiers which change the offset from the iterator, field width and base. Modifiers are introduced by a { immediately following the $ as ${offset[,width[,base]]}. e.g. ${-20,3,d} which subtracts 20 from the current value, prints the result as a decimal in a zero padded field of with 3. Available output forms are decimal (d), octal (o) and hexadecimal (x or X for uppercase). The default modifier is ${0,0,d}. If the lhs is not absolute, the current $ORIGIN is appended to the name.

Supported DIRECTIVEs

INCLUDE

$INCLUDE <path> [<origin>]

will read the file as specified by 'path'. If 'path' is absolute it will be interpreted as such. If it is relative it will be taken relative to the path of the zonefile that includes it.

Optionally $INCLUDE will take a 2nd argument that sets the current origin for relative domains.

The parser only accept IN class zone files.

TTL

Specifying the default TTL

ORIGIN

Specifying the origin used to complete non fully qualified domain names.

GENERATE

See the BIND documentation.

Related packages.

There are other packages with likewise functionality; they where not suitable for my purposes. But maybe they are suitable for you. So before you start using this module you may want to look at these.

DNS::Zone::File will parse a zonefile but will not expand domain names that are not fully qualified since it has no logic to interpret the RDATA of each individual RR. You can use this module to pre-process the file and then feed it to DNS::Zone::File (Default) to create a DNS::Zone instance.

DNS::ZoneFile has almost the same functionality as this code it the canonicalises RR records it is aware off. It also has an INCLUDE function. Being an abstraction of a zonefile it has an interface to add and delete RRs from the zonefile and print it. The code does not support a GENERATE feature.

Net::DNS::ZoneFile also almost has the same functionality, it supports the GENERATE, INCLUDE and ORIGIN primitives. It also supports more classes than just the IN class. However, this module first loads the complete zone in memory; which may be problematic for very large zones. It only seems to support a subset of the available RR types.

All of these classes are abstractions of zonefiles, not of zones i.e. there is no notion of where the zonecuts are and what data is out of zone.

TODO, BUGS and FEATURES.

FEATURE

This code only supports zones in the Zone files in the IN class.

FEATURE

More sanity checking on the RDATA for each RR.

The pre-processor it will only look for 'dnames' in the RDATA that need expansion and not check or validate other entries in the RDATA.

FEATURE

The zonefile formating rules allow the CLASS to be specified before the TTL. This code does not parse such lines.

FEATURE

The KX RR (RFC 2230) will have its RDATA expanded but since there is no implementation of it in Net::DNS it will fail to read if CREATE_RR => 1 in the read method.

TODO

This code needs to know of RR types that have RDATA with dnames.

For completeness these are the RRtypes that have domain names in their rdata and that have been implemented.

NS, CNAME, SOA, MB, PTR, MG, MR, PTR, MINFO, MX, RP, AFSDB, RT, SIG, NXT, SRV, DNAME, NSEC, and RRSIG

RRtypes that do not have domain names in their RDATA will be parsed transparently.

New types will need to be implemented if they become available. Please inform the developer of new RRtypes with a domain name in them that has not been implemented.

COPYRIGHT

Copyright (c) 2003, 2004 RIPE NCC. Author Olaf M. Kolkman <net-dns-sec@ripe.net>

All Rights Reserved

Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission.

THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

The $GENERATE primitive parser is based on code in Net::DNS::ZoneFile

SEE ALSO

perl(1), Net::DNS, Net::DNS::RR, Net::DNS::RR::RRSIG, Net::DNS::Zone

AUTHOR

Juerd Waalboer <juerd@tnx.nl>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2013 by Juerd Waalboer.

This is free software, licensed under:

  The (three-clause) BSD License