LibDNS - API

   LibDNS (or lDNS) is modelled after the Net::DNS perl library. It has
   been shown that Net::DNS  can be used vefficiently for 
   programming DNS aware applications. We want to bring the same level
   of efficiency to C programmers.

   The lDNS API consist of two layers. The top-layer, this is
   what is actually exported to the application via the library. And the
   bottom-layer, this is what lDNS needs to compile and function.

Differences with other DNS libraries
   * lwres - TODO
   * ???  

Bottom Layer
   lDNS is currently only dependent on libc and uses a few networking
   system calls (send/recv and friends). 

   Furhter more, it is to be expected that lDNS is going to depend on
   a cryptographic library. This will probably be OpenSSL.

Top Layer
   As said, lDNS is modelled after Net::DNS, therefor its API looks very
   much like the one used for Net::DNS. Some modification are made
   ofcourse, because not all functionality of Perl can be caught in C.

   The following API details are a rewrite of 'perldoc Net::DNS:XXX' where
   XXX is the actual manpage. At the top of each section it will state from
   which Perl manual page it has been converted.

API
* From: Net::DNS - Perl interface to the DNS resolver

  Resolver Structures [ldns_resolver]
    ldns_resolver* ldns_resolver_new(void)

    A program can have multiple resolver structurs, each maintaining its own
    state information such as the nameservers to be queried, whether
    recursion is desired, etc.

  Packet Structures [ldns_pkt]
    ldns_pkt* ldns_pkt_new(void)

    ldns_resolver queries return ldns_pkt structures. A ldns_pkt structure
    has five sections:

    1  The header section, a ldns_hdr structure.
    2  The question section, a ldns_rr_list structure.
    3  The answer section, a ldns_rr_list structure.
    4  The authority section, a ldns_rr_list structure.
    5  The additional section, a ldns_rr_list structure.

  1. Header Structure [ldns_hdr]
    ldns_hdr represents the header section of a DNS packet.

  2. Question Section [no special type is used]
    ldns_rr_list structure. A list of RRs in the Question section of a DNS
    packet.

  3. Answer Section [no special type is used]
    ldns_rr_list structure. A list of RRs in the Question section of a DNS
    packet.

  4. Authority Section [no special type is used]
    ldns_rr_list structure. A list of RRs in the Question section of a DNS
    packet.
    
  5. Additional Section [no special type is used]
    ldns_rr_list structure. A list of RRs in the Question section of a DNS
    packet.

  Where:
  RR List Structure [ldns_rr_list]
    An array containing Resource Records (RR).
   
  RR Structures [ldns_rr]
    A single Resource Record.

* From: Net::DNS::Resolver - DNS resolver class

Functions on ldns_resolver

  ldns_version(resolver *res)
    Returns the version of lDNS.

  ldns_mx(ldns_resolver *res, char *dname)
    Returns a ldns_rr_list representing the MX records
    for the specified name; the list will be sorted by preference. Returns
    an empty list if the query failed or no MX records were found.

    This method does not look up A records -- it only performs MX queries.
 
  ldns_status ldns_resolver_domain(resolver *res, ldns_rdf *domain)
    Set the default domain for this resolver. This domain is added
    when a query is made with a name without a trailing dot.

  ldns_status ldns_resolver_nameserver_push(resolver *res, ldns_rdf *ip)
    [ldns_rdf ip??]
    Add a new nameserver to the resolver. These nameservers are queried
    when a search() or query() is done.
    
  [IS THIS NEEDED?]
  ldns_status ldns_resolver_searchlist_push(resolver *res, ldns_rdf *domain)
    Add a domain to the searchlist of a resolver. 

  For all function here the following applies:
    if type is NULL it defaults to 'A',
    if class is NULL it default to 'IN'.

  ldns_pkt * ldns_resolver_search(ldns_resolver *res, 
  				ldns_rdf *domain, 
				ldns_rr_type *type, 
				ldns_class *class)
    Perform a query. Try all the nameservers in the *res structure. Apply
    the search list. And default domain.

  ldns_pkt * ldns_resolver_query(ldns_resolver *res, 
                                 ldns_rdf *dom,
                                 ldns_type *t, 
				 ldns_class *cl)
    Only the default domain is added.
    
  ldns_pkt * ldns_resolver_send(ldns_resolver *res,
                                ldns_rdf *domain, 
                                ldns_type *type, 
                                ldns_class *class)

    No search list nor default domain is applied. Return a pointer to a ldns_pkt 
    strcuture with the information from the nameserver.

 [Then there are a bunch a helper function which set the port etc. etc.]


* From: Net::DNS::Packet - DNS packet object class

  ldns_pkt * ldns_pkt_new()
    Creates a new empty packet.

  ldns_buffer* ldns_pkt_data(ldns_pkt *pkt)
    Returns the packet data in binary format, suitable for sending to a
    nameserver. [XXX, suitable for sending to a NS?]

  ldns_hdr *ldns_header(ldn_pkt *pkt)
    Returns a ldns_hdr structure representing the header section of
    the packet.

  ldns_rr_list *ldns_question(ldns_pkt *pkt)
    Returns a pointer to a ldns_rr_list representing the question section
    of the packet.

  ldns_rr_list *ldns_answer(ldns_pkt *pkt)
    Returns a pointer to a ldns_rr_list representing the answer section of
    the packet.

  ldns_rr_list *ldns_authority(ldns_pkt *pkt)
    Returns a pointer to a ldns_rr_list representing the authority section
    of the packet.

  ldns_rr_list *ldns_additional(ldns_pkt *pkt)
    Returns a pointer to a ldns_rr_list of representing the additional
    section of the packet.

  void ldsn_pkt_print(ldns_pkt *pkt)
    Prints the packet data on the standard output in an ASCII format similar
    to that used in DNS zone files. See RFC1035.

  ldns_buffer *ldns_pkt_string(ldns_pkt *pkt)
    Returns a ldns_buffer containing the string representation of the packet.

  <return type unknown> ldns_pkt_answerfrom(ldns_pkt *pkt)
    Returns the IP address from which we received this packet. User-created
    packets will return NULL.

  uint16_t ldns_pkt_answersize(ldns_pkt *pkt)
    Returns the size of the packet in bytes as it was received from a
    nameserver. User-created packets will return 0. [XXX user-created??]

  ldns_status ldns_push(ldns_pkt *pkt, ldns_pkt_section section, ldns_rr *rr)
    Adds *rr to the specified section of the packet. Return LDNS_STATUS_OK
    on success, LDNS_STATUS_ERR otherwise.

  ldns_status ldns_unique_push(ldns_pkt *pkt, ldns_pkt_section section, ldns_rr *rr)
    Adds *rr to the specified section of the packet provided that the RR
    does not already exist in the packet. Return LDNS_STATUS_OK
    on success, LDNS_STATUS_ERR otherwise.

  ldns_rr *ldns_pop(ldns_pkt, ldns_pkt_section)
    Removes a RR from the specified section of the packet. Returns NULL if
    no RR's could be popped.

  <NEW, not in Net::DNS>
  ldns_rr_list *ldns_pkt_rrset(ldns_pkt *pkt, ....
    Retrieve all RRs in a packet matching certain criteria

-- STUFF BELOW IS TODO ---
Tsig is implemented after basic functionality is done

  dn_comp [TODO]
        $compname = $packet->dn_comp("foo.example.com", $offset);

    Returns a domain name compressed for a particular packet object, to be
    stored beginning at the given offset within the packet data. The name
    will be added to a running list of compressed domain names for future
    use.

  dn_expand [TODO]
        use Net::DNS::Packet qw(dn_expand);
        ($name, $nextoffset) = dn_expand(\$data, $offset);

        ($name, $nextoffset) = Net::DNS::Packet::dn_expand(\$data, $offset);

    Expands the domain name stored at a particular location in a DNS packet.
    The first argument is a reference to a scalar containing the packet
    data. The second argument is the offset within the packet where the
    (possibly compressed) domain name is stored.

    Returns the domain name and the offset of the next location in the
    packet.

  sign_tsig
        $key_name = "tsig-key";
        $key      = "awwLOtRfpGE+rRKF2+DEiw==";

        $update = Net::DNS::Update->new("example.com");
        $update->push("update", rr_add("foo.example.com A 10.1.2.3"));

        $update->sign_tsig($key_name, $key);

        $response = $res->send($update);

    Signs a packet with a TSIG resource record (see RFC 2845). Uses the
    following defaults:

        algorithm   = HMAC-MD5.SIG-ALG.REG.INT
        time_signed = current time
        fudge       = 300 seconds

    If you wish to customize the TSIG record, you'll have to create it
    yourself and call the appropriate Net::DNS::RR::TSIG methods. The
    following example creates a TSIG record and sets the fudge to 60
    seconds:

        $key_name = "tsig-key";
        $key      = "awwLOtRfpGE+rRKF2+DEiw==";

        $tsig = Net::DNS::RR->new("$key_name TSIG $key");
        $tsig->fudge(60);

        $query = Net::DNS::Packet->new("www.example.com");
        $query->sign_tsig($tsig);

        $response = $res->send($query);

    You shouldn't modify a packet after signing it; otherwise authentication
    will probably fail.

  sign_sig0
    SIG0 support is provided through the Net::DNS::RR::SIG class. This class
    is not part of the default Net::DNS distribution but resides in the
    Net::DNS::SEC distribution.

        $update = Net::DNS::Update->new("example.com");
        $update->push("update", rr_add("foo.example.com A 10.1.2.3"));
        $update->sign_sig0("Kexample.com+003+25317.private");

    SIG0 support is experimental see Net::DNS::RR::SIG for details.

--- END TODO ---

* From: Net::DNS::RR - DNS Resource Record class

   ldns_rr is the base structure for DNS Recorce Records.
   [ See also the manual pages for each RR type. - TODO??]
 
  ldns_rr *ldns_rr_new(void)
    Returns a pointer to a newly created ldns_rr structure.
    
  [TODO: do we want the stuff descibed below?]
  ldns_rr_new (from string)
     $a     = Net::DNS::RR->new("foo.example.com. 86400 A 10.1.2.3");
     $mx    = Net::DNS::RR->new("example.com. 7200 MX 10 mailhost.example.com.");
     $cname = Net::DNS::RR->new("www.example.com 300 IN CNAME www1.example.com");
     $txt   = Net::DNS::RR->new("baz.example.com 3600 HS TXT 'text record'");

    Returns a "Net::DNS::RR" object of the appropriate type and initialized
    from the string passed by the user. The format of the string is that
    used in zone files, and is compatible with the string returned by
    "Net::DNS::RR->string".

    The name and RR type are required; all other information is optional. If
    omitted, the TTL defaults to 0 and the RR class defaults to IN. Omitting
    the optional fields is useful for creating the empty RDATA sections
    required for certain dynamic update operations. See the
    "Net::DNS::Update" manual page for additional examples.

    All names must be fully qualified. The trailing dot (.) is optional.

  void ldns_rr_print(ldns_rr *r)
    Prints the record to the standard output. 

  ldns_buffer *ldns_rr_string(ldns_rr *r)
    Returns a ldns_buffer with the string representation of the RR. Calls the rdatastr method to
    get the RR-specific data.

  ldns_buffer ldns_rr_rdatastr(ldns_rr *r)
    Returns a pointer to a ldns_buffer containing with string containing
    RR-specific data. 

  ldns_rdf *ldns_rr_name(ldns_rr *r)
    Returns the record's domain name as a ldns_rdf type. [XXX how should we
    return stuff like this? ldns_rdf, uint8_t, ldns_buffer?

  ldns_rdf_rr_type ldns_rr_get_type(ldns_rr *r)
    Returns the record's type.

  ldns_rr_class ldns_rr_get_class(ldns_rr *r)
    Returns the record's class.

  uint32_t ldns_rr_get_ttl(ldns_rr *r)
    Returns the record's time-to-live (TTL).

  [TODO nodig??] rdlength
        $rdlength = $rr->rdlength;

    Returns the length of the record's data section.

  [TODO nodig??] rdata
        $rdata = $rr->rdata

    Returns the record's data section as binary data.
