NAME
    Net::DNS::ToolKit - tools for working with DNS packets

SYNOPSIS
      use Net::DNS::ToolKit qw(

            get1char
            get16
            get32
            put1char
            put16
            put32
            getIPv4
            putIPv4
            getstring
            putstring
            dn_comp
            dn_expand
            parse_char
            gethead
            newhead
            getflags
            get_qdcount
            get_ancount
            get_nscount
            get_arcount
            put_qdcount
            put_ancount
            put_nscount
            put_arcount
            inet_aton
            inet_ntoa
            sec2time
            ttlAlpha2Num
            collapse
            strip
            get_ns
            gettimeofday
      );

      $char = get1char(\$buffer,$offset);
      ($int, $newoff)  = get16(\$buffer,$offset);
      ($long, $newoff) = get32(\$buffer,$offset);
      $newoff = put1char(\$buffer,$offset,$u_char);
      $newoff = put16(\$buffer,$offset,$int);
      $newoff = put32(\$buffer,$offset,$long);
      $flags = getflags(\$buffer);
      $int = get_qdcount(\$buffer);
      $int = get_ancount(\$buffer);
      $int = get_nscount(\$buffer);
      $int = get_arcount(\$buffer);
      $newoff = put_qdcount(\$buffer,$int);
      $newoff = put_ancount(\$buffer,$int);
      $newoff = put_nscount(\$buffer,$int);
      $newoff = put_arcount(\$buffer,$int);
      ($netaddr,$newoff)=getIPv4(\$buffer,$offset);
      $newoff = putIPv4(\$buffer,$offset,$netaddr);
      ($offset,
       $id,$qr,$opcode,$aa,$tc,$rd,$ra,$mbz,$ad,$cd,$rcode,
       $qdcount,$ancount,$nscount,$arcount)
            = gethead(\$buffer);
      $newoff = newhead(\$buffer,$id,$flags,
            $qdcount,$ancount,$nscount,$arcount);
      ($b,$h,$d,$a)=parse_char($buffer,$offset);
      ($newoff,$name) = dn_expand(\$buffer,$offset);
      ($newoff,@dnptrs)=dn_comp(\$buffer,$offset,\$name,\@dnptrs);
      $dotquad = inet_ntoa($netaddr);
      $netaddr = inet_aton($dotquad);
      $timetxt = sec2time($seconds);
      $seconds = ttlAlpha2Num($timetext);
      $shorthost = collapse($zonename,$longhost);
      $tag = strip($P_tag);
      @nameservers = get_ns();
      ($secs,$usecs) = gettimeofday();

DESCRIPTION
    Routines to pick apart, examine and put together DNS packets. They can
    be used for diagnostic purposes or as building blocks for DNS
    applications such as DNS servers and clients or to allow user
    applications to interact directly with remote DNS servers.

    See: Net::DNS::ToolKit for individual Resource Record methods.

    These functions return a value and offset in list context and first
    value only in scalar context.

      ($int,$newoff)        = get16(...
      ($long,$newoff)       = get32(...
      ($netaddr,$newoff)    = getIPv4(...
      ($string,$newoff)     = getstring(...
      ($newoff,$name)       = dn_expand(...
      ($secs,$usecs)        = gettimeofday(...

    These functions return only a value or an offset.

      $newoff       = put1char(...
      $newoff       = put16(...  
      $newoff       = put32(...
      $newoff       = put_qdcount(...
      $newoff       = put_ancount(...
      $newoff       = put_nscount(...
      $newoff       = put_arcount(...
      $newoff       = putIPv4(...
      $newoff       = putstring(...
      $newoff       = newhead(...
      $flags        = getflags(...
      $int          = get_qdcount(...
      $int          = get_ancount(...
      $int          = get_nscount(...
      $int          = get_arcount(...
      $char         = get1char(...
      $dotquad      = inet_ntoa(...
      $netaddr      = inet_aton(...
      $timetxt      = sec2time(...
      $seconds      = ttlAlpha2Num(...
      $tag          = strip(...
      $shorthost    = collapse(...

    This function always return list context prefixed by a new offset.

      ($newoff,@dnptrs) = dn_comp(...
      ($offset,@list)   = gethead(...

    These functions always return list context.

      @list         = parse_char(...
      @nameservers  = get_ns(...

    * $char = get1char(\$buffer,$offset);
        Get a single character from the buffer at $offset

          input:        pointer to buffer,
                        offset into buffer
          output:       the "character"   
                   or   undef if the pointer
                        is outside the buffer

    * ($int, $newoff) = get16(\$buffer,$offset);
        Get a 16 bit integer from the buffer at $offset. Return the value
        and a new offset pointing at the next character.

        Returns and empty array on error.

          input:        pointer to buffer,
                        offset into buffer
          returns:      16 bit integer,
                        offset + size of int

        In SCALAR context, returns just the value.

    * $newoff = put1char(\$buffer,$offset,$u_char);
        Put an unsigned 8 bit value into the buffer at $offset. Return the
        value of the new offset pointer to the next char (usually end of
        buffer).

    * $newoff = put16(\$buffer,$offset,$int);
        Put a 16 bit integer into the buffer at $offset. Return the value of
        the new offset pointer to the the next char (usually end of buffer).

          input:        pointer to buffer,
                        offset into buffer,
                        16 bit integer
          returns:      offset + size of int

    * ($long, $newoff) = get32(\$buffer,$offset);
        Get a 32 bit long from the buffer at $offset. Return the long and a
        new offset pointing at the next character.

        Returns and empty array on error.

          input:        pointer to buffer,
                        offset into buffer
          returns:      32 bit long,
                        offset + size long

        In SCALAR context, returns just the value.

    * $newoff = put32(\$buffer,$offset,$long);
        Put a 32 bit long into the buffer at $offset. Return the value of
        the new offset pointer to the the next char (usually end of buffer).

          input:        pointer to buffer,
                        offset into buffer,
                        32 bit long
          returns:      offset + size of int

    * $flags = getflags(\$buffer);
        Get the flag bits from the header

          input:        pointer to buffer,
          returns:      flag bits

    * $int = get_qdcount(\$buffer);
        Get the contents of the qdcount.

          input:        pointer to buffer,
          returns:      16 bit integer,

    * $int = get_ancount(\$buffer);
        Get the contents of the ancount.

          input:        pointer to buffer,
          returns:      16 bit integer,

    * $int = get_nscount(\$buffer);
        Get the contents of the nscount.

          input:        pointer to buffer,
          returns:      16 bit integer,

    * $int = get_arcount(\$buffer);
        Get the contents of the arcount.

          input:        pointer to buffer,
          returns:      16 bit integer,

    * $newoff = put_qdcount(\$buffer,$int);
        Put a 16 bit integer into qdcount. Return an offset to ancount.

          input:        pointer to buffer,
                        16 bit integer,
          returns:      offset to ancount

    * $newoff = put_ancount(\$buffer,$int);
        Put a 16 bit integer into ancount. Return an offset to nscount.

          input:        pointer to buffer,
                        16 bit integer,
          returns:      offset to nscount

    * $newoff = put_nscount(\$buffer,$int);
        Put a 16 bit chunk into nscount. Return an offset to arcount.

          input:        pointer to buffer,
                        16 bit integer,
          returns:      offset to arcount

    * $newoff = put_arcount(\$buffer,$int);
        Put a 16 bit integer into arcount. Return an offset to answer
        section.

          input:        pointer to buffer,
                        16 bit integer,
          returns:      offset to question section

    * ($netaddr,$newoff)=getIPv4(\$buffer,$offset);
        Get an IPv4 network address from the buffer at $offset. Return the
        netaddr and a new offset pointing at the next character beyond.

        Returns and empty array on error.

          input:        pointer to buffer,
                        offset into buffer
          returns:      netaddr,
                        offset + size of ipaddr

        In SCALAR context, returns just netaddr.

    * $newoff = putIPv4(\$buffer,$offset,$netaddr);
        Put a netaddr into the buffer. Return the value of the new offset
        pointer to the the next char (usually end of buffer).

          input:        pointer to buffer,
                        offset into buffer,
                        packed IPv4 net address
          returns:      pointer to end of buffer

    * ($string,$newoff) = getstring(\$buffer,$offset,$length);
        Return a string of $length from the buffer.

          input:        pointer to buffer,
                        offset,
                        length of string
          returns:      string,
                        new offset to end
                        off string in buffer

    * $newoff = putstring(\$buffer,$offset,\$string);
        Append a string to $buffer at $offset.

          input:        pointer to buffer,
                        offset into buffer,
                        pointer to string
          returns:      new offset to end of buffer

    * ($offset,@headitems) = gethead(\$buffer);
          ($offset,
          $id,$qr,$opcode,$aa,$tc,$rd,$ra,$mbz,$ad,$cd,$rcode,
           $qdcount,$ancount,$nscount,$arcount)
                = gethead(\$buffer);

          Get the numeric codes for header variables

            0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
          -------------------------------------------------
           15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
          |                      ID                       |
          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
          |QR|   Opcode  |AA|TC|RD|RA| Z|AD|CD|   RCODE   |
          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
          |                    QDCOUNT                    |
          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
          |                    ANCOUNT                    |
          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
          |                    NSCOUNT                    |
          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
          |                    ARCOUNT                    |
          +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

          The length of this header is NS_HFIXEDSZ

          input:        pointer to message buffer
          returns:      offset to question section,
                        array of variables

    * $newoff=newhead(\$buffer,
    $id,$flags,$qdcount,$ancount,$nscount,$arcount);
        Creat a new header and return the offset to question

          input:        \$buffer
                        $id,
                        $flags,
                        $qdcount,
                        $ancount,
                        $nscount,
                        $arcount
          returns:      offset to question = NS_HFIXEDSZ
                    or  undefined on error

          If qdcount, ancount, nscount, arcount are
          not present, then they will be set to zero.

          example dump script:

          use lib qw(blib/lib blib/arch);
          use Net::DNS::Codes qw(:all);
          use Net::DNS::ToolKit::Debug qw(
                print_head
                print_buf
          );
          use Net::DNS::ToolKit qw(
                get1char
                parse_char
                newhead
          );
          my $buffer = '';
          newhead(\$buffer,
                1234,                   # ID
                QR | BITS_QUERY | RD,
                1,                      # questions
                5,                      # answers
                2,                      # ns authority
                3,                      # glue records
          );

          print_head(\$buffer);
          print_buf(\$buffer);

          Will produce the following output:

          ID     => 1234    
          QR      => 1    
          OPCODE  => QUERY
          AA      => 0
          TC      => 0
          RD      => 1
          RA      => 0
          Z       => 0
          AD      => 0
          CD      => 0
          RCODE   => NOERROR
          QDCOUNT => 1
          ANCOUNT => 5
          NSCOUNT => 2
          ARCOUNT => 3
          0     :  0000_0100  0x04    4    
          1     :  1101_0010  0xD2  210    
          2     :  1000_0001  0x81  129    
          3     :  0000_0000  0x00    0    
          4     :  0000_0000  0x00    0    
          5     :  0000_0001  0x01    1    
          6     :  0000_0000  0x00    0    
          7     :  0000_0101  0x05    5    
          8     :  0000_0000  0x00    0    
          9     :  0000_0010  0x02    2    
          10    :  0000_0000  0x00    0    
          11    :  0000_0011  0x03    3    

    * ($b,$h,$d,$a) = parse_char($char);
          return strings for the character in:

            binary    hex   decimal   ascii
          0011_1001  0x39      57      9

          as appropriate. Ascii is only 
          returned if printable.

        A simple script using this routine can provide a view into a DNS
        packet to examine the bits and byte. Very useful while writing DNS
        client and server routines. See the example below.

    * ($name,$newoff) = dn_expand(\$buffer,$offset);
        Expands a compressed domain name into a full domain name.

          input:        pointer to buffer,
                        offset into buffer
          returns:      expanded name,
                        pointer to next RR

    * ($newoff,@dnptrs)=dn_comp(\$buffer,$offset,\$name,\@dnptrs);
        Compress a domain name and append it to the buffer.

          input:        pointer to buffer,
                        offset to insertion point,
                (usually end of buffer)
                        pointer to name,
                        pointer to array of offsets of
                          previously compressed names,
          returns:      new offset to end of buffer,
                        updated array of offsets to 
                          previous compressed names,

          NOTES:   1)   When the first domain name
                        is compressed, the \@dnptrs
                        array is ommited. dn_comp
                        will return an initialized
                        array that can then be used
                        for subsequent calls.

                  i.e.  initial call

          ($newoff,@dnptrs)=dn_comp(\$name,\$buffer,$offset);

                   2)   compression can be suppressed
                        for test purposes if the pointer
                        to $name is stored in a glob
                        reference rather than a scalar.

                  i.e.  $name = 'hostname.com';
                        local *glob = \$name;

          ($newoff,@dnptrs)=dn_comp(\$buffer,$offset,\*glob);
                        [use a pointer to *glob]

    * $dotquad = inet_ntoa($netaddr);
        Convert a packed IPv4 network address to a dot-quad IP address.

          input:        packed network address
          returns:      IP address i.e. 10.4.12.123

    * $netaddr = inet_aton($dotquad);
        Convert a dot-quad IP address into an IPv4 packed network address.

          input:        IP address i.e. 192.5.16.32
          returns:      packed network address

    * $timetxt = sec2time($seconds);
        Convert numeric seconds into a string of the form

          NNw NNd NNh NNm NNs

        for weeks, days, hours, minutes, seconds respectively.

          input:        seconds
          returns:      elapsed time text

    * $seconds = ttlAlpha2Num($timetext);
        Convert a string of time text of the form

          NNw NNd NNh NNm NNs

        into seconds. Upper case is OK.

          input:        ttl in form numeric
                        or alpha numeric
          returns:      seconds

    * $shorthost = collapse($zonename,$longhost);
        Remove the zone portion of a fully qualified domain name and return
        the host portion.

          input:        zone name,
                        fqdn
          returns:      short host name

          i.e.  zone = bar.com
                fqdn = foo.bar.com

          foo = collapse(zone,fqdn);

        Testing is not case sensitive. If the fqdn does not end in the zone
        name then the fqdn is returned.

    * $tag = strip($P_tag);
        Remove the leading character(s) from a type/class label.

          input:     label  # like T_MX or C_IN
          returns:   tag    # MX, IN

    * @nameservers = get_ns();
        Return a list of name server addresses in packed network form for
        use by this host.

    * ($secs,$usecs) = gettimeofday();
        Returns a time value that is accurate to the nearest microsecond but
        also has a range of years.

          input:    none
          returns:  seconds since epoch,
                    microseconds (of current sec)

INSTALLATION
    To install this module, type:

            perl Makefile.PL
            make
            make test
            make install

DEPENDENCIES
            perl 5.00503
            Net::DNS::Codes 0.06

EXPORT
    None

EXPORT_OK
    get1char get16 get32 put1char put16 put32 getIPv4 putIPv4 getstring
    putstring dn_comp dn_expand parse_char gethead newhead getflags
    get_qdcount get_ancount get_nscount get_arcount put_qdcount put_ancount
    put_nscount put_arcount inet_aton inet_ntoa sec2time ttlAlpha2Num
    collapse strip get_ns gettimeofday

AUTHOR
    Michael Robinton <michael@bizsystems.com>

ACKNOWLEDGEMENTS
    The following functions are used in whole or in part as include files to
    ToolKit.xs. The copyrights are include in the respective files.

      file:           functions:

      dn_expand.inc   dn_expand
      miniSocket.inc  inet_aton, inet_ntoa

    dn_expand is from Michael Fuhr's Net::DNS package (DNS.pm), copyright
    (c) 1997-2002. Thank you Michael.

    inet_aton, inet_ntoa are from the perl-5.8.0 release by Larry Wall,
    copyright 1989-2002. Thank you Larry for making PERL possible for all of
    us.

COPYRIGHT
        Copyright 2003, Michael Robinton <michael@bizsystems.com>
   
        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.

See also:
    Net::DNS::Codes(3), Net::DNS::ToolKit::RR(3),
    Net::DNS::ToolKit::Debug(3)

