463 lines
14 KiB
XML
463 lines
14 KiB
XML
|
<?xml version="1.0"?>
|
||
|
|
||
|
<!DOCTYPE rfc SYSTEM "rfc2629.dtd">
|
||
|
<!-- $Id -->
|
||
|
|
||
|
<?rfc toc="yes" ?>
|
||
|
<?rfc compact="yes" ?>
|
||
|
<?rfc editing="no" ?>
|
||
|
<?rfc iprnotified="no" ?>
|
||
|
<?rfc private="LibDNS API" ?>
|
||
|
|
||
|
<rfc ipr="none" category="info" docName="libdns-api-00.txt">
|
||
|
|
||
|
<front>
|
||
|
<title>LibDNS API</title>
|
||
|
<author initials="R." surname="Gieben" fullname="Miek Gieben">
|
||
|
<organization>NLnet Labs</organization>
|
||
|
<address>
|
||
|
<postal>
|
||
|
<street>Kruislaan 419</street>
|
||
|
<city>Amsterdam</city>
|
||
|
<code>1098 VA</code>
|
||
|
<country>The Netherlands</country>
|
||
|
</postal>
|
||
|
<email>miek@nlnetlabs.nl</email>
|
||
|
<uri>http://www.nlnetlabs.nl</uri>
|
||
|
</address>
|
||
|
</author>
|
||
|
<author initials="J." surname="Jansen" fullname="Jelte Jansen">
|
||
|
<organization>NLnet Labs</organization>
|
||
|
<address>
|
||
|
<postal>
|
||
|
<street>Kruislaan 419</street>
|
||
|
<city>Amsterdam</city>
|
||
|
<code>1098 VA</code>
|
||
|
<country>The Netherlands</country>
|
||
|
</postal>
|
||
|
<email>jelte@nlnetlabs.nl</email>
|
||
|
<uri>http://www.nlnetlabs.nl</uri>
|
||
|
</address>
|
||
|
</author>
|
||
|
<author initials="E." surname="Rozendaal" fullname="Erik Rozendaal">
|
||
|
<organization>NLnet Labs</organization>
|
||
|
<address>
|
||
|
<postal>
|
||
|
<street>Kruislaan 419</street>
|
||
|
<city>Amsterdam</city>
|
||
|
<code>1098 VA</code>
|
||
|
<country>The Netherlands</country>
|
||
|
</postal>
|
||
|
<email>erik@nlnetlabs.nl</email>
|
||
|
<uri>http://www.nlnetlabs.nl</uri>
|
||
|
</address>
|
||
|
</author>
|
||
|
<date month="January" year="2005" />
|
||
|
<keyword>DNS</keyword>
|
||
|
<keyword>Elite</keyword>
|
||
|
<keyword>Hacking</keyword>
|
||
|
<abstract>
|
||
|
<t>
|
||
|
A small abstract will come here, TBD.
|
||
|
</t>
|
||
|
</abstract>
|
||
|
</front>
|
||
|
|
||
|
<middle>
|
||
|
|
||
|
<section title="Introduction">
|
||
|
<t>
|
||
|
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.
|
||
|
</t>
|
||
|
<t>
|
||
|
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.
|
||
|
</t>
|
||
|
</section> <!-- "Introduction" -->
|
||
|
|
||
|
<section title="Differences With Other Libraries">
|
||
|
<t>
|
||
|
Short intermezzo detailing differences with other libraries. Most important
|
||
|
ones are the libc resolver interface (from BIND8) and the lwres_ interface
|
||
|
from BIND9.
|
||
|
</t>
|
||
|
</section> <!-- "Differences with other libraries" -->
|
||
|
|
||
|
<section title="Interfaces">
|
||
|
<t>
|
||
|
At its lowest level lDNS is only dependent on libc. It uses a
|
||
|
few networking systems calls; socket, bind, send/recv and friends.
|
||
|
</t>
|
||
|
<t>
|
||
|
Further more it is to be expected that lDNS will depend on OpenSSL for
|
||
|
its cryptography.
|
||
|
</t>
|
||
|
<t>
|
||
|
As said, lDNS is modelled after Net::DNS, therefor its application 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.
|
||
|
</t>
|
||
|
|
||
|
<t>
|
||
|
This API document was written by carefully looking at the documentation
|
||
|
contained in the Net::DNS Perl module.
|
||
|
</t>
|
||
|
</section> <!-- "Interfaces" -->
|
||
|
|
||
|
<section title="RDF Structure">
|
||
|
<t>
|
||
|
The rdf structure, the RData Field, is a type that contains the different
|
||
|
types in the rdata of an RR. Consider the following example:
|
||
|
<artwork>
|
||
|
example.com. IN MX 10 mx.example.com.
|
||
|
</artwork>
|
||
|
The "10 mx.example.com." is the rdata in this case. It consists of two
|
||
|
fields, "10" and "mx.example.com". These have the types (in this case)
|
||
|
LDNS_RDF_TYPE_INT8 and LDNS_RDF_TYPE_DNAME.
|
||
|
</t>
|
||
|
<t>
|
||
|
The following functions operate on this structure.
|
||
|
</t>
|
||
|
<t>
|
||
|
<list style="hanging">
|
||
|
<t hangText="dns_rdf *ldns_rdf_new(uint16_t s, ldns_rdf_type t, uint8_t *d):">
|
||
|
Create a new rdf structure. Return a pointer to it.
|
||
|
</t>
|
||
|
<t hangText="uint16_t ldns_rdf_size(ldns_rdf *r):">
|
||
|
Get the size of a rdf structure.
|
||
|
</t>
|
||
|
<t hangText="void ldns_rdf_set_size(ldns_rdf *r, uint16_t):">
|
||
|
Set the size of a rdf structure.
|
||
|
</t>
|
||
|
<t hangText="void ldns_rdf_set_type(ldns_rdf *r, ldns_rdf_type t):">
|
||
|
Set the type of a rdf structure.
|
||
|
</t>
|
||
|
<t hangText="ldns_rdf_type ldns_rdf_get_type(ldns_rdf *r):">
|
||
|
Get the type of a rdf structure.
|
||
|
</t>
|
||
|
<t hangText="void ldns_rdf_set_data(ldns_rdf *r, uint8_t *n):">
|
||
|
Set the (binary/network order) data of a rdf structure.
|
||
|
</t>
|
||
|
<t hangText="uint8_t *ldns_rdf_data(ldns_rdf *r):">
|
||
|
Get a pointer to the data in a rdf structure.
|
||
|
</t>
|
||
|
<t hangText="void ldns_rdf_free(ldns_rdf *r):">
|
||
|
Free a rdf structure.
|
||
|
</t>
|
||
|
<t hangText="ldns_rdf_new_frm_str(uint8_t *s, ldns_rdf_type t):">
|
||
|
Create a new rdf structure from a string and a specific rdf_type.
|
||
|
The type is needed to perform the correct conversion.
|
||
|
</t>
|
||
|
</list>
|
||
|
</t>
|
||
|
</section> <!-- "RDF Structure" -->
|
||
|
|
||
|
<section title="RR Structure">
|
||
|
<t>
|
||
|
These functions operate on ldns_rr structures.
|
||
|
</t>
|
||
|
<t>
|
||
|
<list style="hanging">
|
||
|
<t hangText="ldns_rr *ldns_rr_new(void):">
|
||
|
Returns a pointer to the newly created ldns_rr structure.
|
||
|
</t>
|
||
|
<t hangText="void ldns_rr_print(FILE *s, ldns_rr *r):">
|
||
|
Prints the record to the stream s.
|
||
|
</t>
|
||
|
<t hangText="ldns_buffer ldns_rr_rdatastr(ldns_rr *r):">
|
||
|
Returns a pointer to a ldns_buffer containing with string containing
|
||
|
RR-specific data.
|
||
|
</t>
|
||
|
<t hangText="ldns_rdf *ldns_rr_name(ldns_rr *r):">
|
||
|
Returns the record's owner name as a ldns_rdf type.
|
||
|
</t>
|
||
|
<t hangText="ldns_rdf_rr_type ldns_rr_get_type(ldns_rr *r):">
|
||
|
Returns the record's type.
|
||
|
</t>
|
||
|
<t hangText="ldns_rr_class ldns_rr_get_class(ldns_rr *r):">
|
||
|
Returns the record's class.
|
||
|
</t>
|
||
|
<t hangText="uint32_t ldns_rr_get_ttl(ldns_rr *r):">
|
||
|
Returns the record's time-to-live (TTL).
|
||
|
</t>
|
||
|
</list>
|
||
|
</t>
|
||
|
|
||
|
<t>
|
||
|
TODO the 'set' functions of the 'get'
|
||
|
</t>
|
||
|
</section> <!-- "RR Structure" -->
|
||
|
|
||
|
<section title="RR list Structure">
|
||
|
<t>
|
||
|
In the DNS the atomic data type is an RRset. This is a list
|
||
|
of RRs with the same ownername, type and class. Net::DNS doesn't
|
||
|
have rrsets as a seperate object.
|
||
|
</t>
|
||
|
<t>
|
||
|
In lDNS we have the ldns_rr_list, which just holds a bunch of RR's.
|
||
|
No specific check are made on the RRs that can be put in such a list.
|
||
|
Special wrapper functions exist which allow the usage of ldns_rr_list
|
||
|
of real (RFC compliant) RR sets.
|
||
|
</t>
|
||
|
<t>
|
||
|
TODO: See rr.c
|
||
|
</t>
|
||
|
</section> <!-- "RR list Structure" -->
|
||
|
|
||
|
<section title="Resolver Structure">
|
||
|
<t>
|
||
|
<list style="hanging">
|
||
|
<t hangText="ldns_resolver* ldns_resolver_new(void):">
|
||
|
Create a new resolver structure and return the pointer to that.
|
||
|
</t>
|
||
|
<t hangText="uint8_t ldns_version(resolver *res):">
|
||
|
Returns the version of lDNS.
|
||
|
</t>
|
||
|
<t hangText="ldns_pkt *ldns_mx(ldns_resolver *res, ldns_rdf_type *dname):">
|
||
|
Returns a ldns_pkt representing the MX records
|
||
|
for the specified dname. Function is documented differently in Net::DNS.
|
||
|
Do we need stuff like this?? XXX
|
||
|
</t>
|
||
|
<t hangText="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.
|
||
|
|
||
|
|
||
|
</t>
|
||
|
<t hangText="ldns_status ldns_resolver_nameserver_push(resolver *res,
|
||
|
ldns_rdf *ip):">
|
||
|
Add a new nameserver to the resolver. These nameservers are queried
|
||
|
when a search() or query() is done.
|
||
|
|
||
|
</t>
|
||
|
<t hangText="ldns_status ldns_resolver_searchlist_push(resolver *res,
|
||
|
ldns_rdf *domain):">
|
||
|
Add a domain to the searchlist of a resolver.
|
||
|
</t>
|
||
|
<t hangText=" 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.
|
||
|
If type is NULL it defaults to 'A',
|
||
|
If class is NULL it default to 'IN'.
|
||
|
</t>
|
||
|
<t hangText="ldns_pkt * ldns_resolver_query(ldns_resolver *res,
|
||
|
ldns_rdf *dom,
|
||
|
ldns_type *t,
|
||
|
ldns_class *cl):">
|
||
|
Perform a query. Only the default domain is added.
|
||
|
If type is NULL it defaults to 'A',
|
||
|
If class is NULL it default to 'IN'.
|
||
|
</t>
|
||
|
<t hangText=" 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
|
||
|
structure with the information from the nameserver.
|
||
|
If type is NULL it defaults to 'A',
|
||
|
If class is NULL it default to 'IN'.
|
||
|
</t>
|
||
|
</list>
|
||
|
</t>
|
||
|
<t>
|
||
|
TODO XX Gazillion helper functions to set port, src-port, etc. etc.
|
||
|
</t>
|
||
|
</section> <!-- "Resolver Structure" -->
|
||
|
|
||
|
<section title="Packet Structure">
|
||
|
<t>
|
||
|
A packet structure (ldns_pkt) has five sections:
|
||
|
<list style="numbers">
|
||
|
<t>The header section, a ldns_hdr structure.</t>
|
||
|
<t>The question section, a ldns_rr_list structure.</t>
|
||
|
<t>The answer section, a ldns_rr_list structure.</t>
|
||
|
<t>The authority section, a ldns_rr_list structure.</t>
|
||
|
<t>The additional section, a ldns_rr_list structure.</t>
|
||
|
</list>
|
||
|
</t>
|
||
|
<t>
|
||
|
<list style="hanging">
|
||
|
<t hangText="Header Structure (ldns_hdr):">
|
||
|
ldns_hdr represents the header section of a DNS packet.
|
||
|
</t>
|
||
|
<t hangText="Question Section (ldns_rr_list):">
|
||
|
A list of RRs in the Question section of a DNS packet.
|
||
|
</t>
|
||
|
<t hangText="Answer Section (ldns_rr_list):">
|
||
|
A list of RRs in the Question section of a DNS packet.
|
||
|
</t>
|
||
|
<t hangText="Authority Section (ldns_rr_list):">
|
||
|
A list of RRs in the Question section of a DNS packet.
|
||
|
</t>
|
||
|
<t hangText="Additional Section (ldns_rr_list):">
|
||
|
A list of RRs in the Question section of a DNS packet.
|
||
|
</t>
|
||
|
</list>
|
||
|
</t>
|
||
|
|
||
|
<t>
|
||
|
<list style="hanging">
|
||
|
<t hangText="ldns_pkt * ldns_pkt_new(void):">
|
||
|
Creates a new empty packet.
|
||
|
</t>
|
||
|
<t hangText="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?]
|
||
|
</t>
|
||
|
<t hangText="ldns_hdr *ldns_header(ldn_pkt *pkt):">
|
||
|
Returns a ldns_hdr structure representing the header section of
|
||
|
the packet.
|
||
|
</t>
|
||
|
<t hangText="ldns_rr_list *ldns_question(ldns_pkt *pkt):">
|
||
|
Returns a pointer to a ldns_rr_list representing the question section
|
||
|
of the packet.
|
||
|
</t>
|
||
|
<t hangText="ldns_rr_list *ldns_answer(ldns_pkt *pkt):">
|
||
|
Returns a pointer to a ldns_rr_list representing the answer section of
|
||
|
the packet.
|
||
|
|
||
|
</t>
|
||
|
<t hangText=" ldns_rr_list *ldns_authority(ldns_pkt *pkt):">
|
||
|
Returns a pointer to a ldns_rr_list representing the authority section
|
||
|
of the packet.
|
||
|
|
||
|
</t>
|
||
|
<t hangText=" ldns_rr_list *ldns_additional(ldns_pkt *pkt):">
|
||
|
Returns a pointer to a ldns_rr_list of representing the additional
|
||
|
section of the packet.
|
||
|
|
||
|
</t>
|
||
|
<t hangText=" 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.
|
||
|
|
||
|
</t>
|
||
|
<t hangText="ldns_buffer *ldns_pkt_string(ldns_pkt *pkt):">
|
||
|
Returns a ldns_buffer containing the string representation of the packet.
|
||
|
|
||
|
</t>
|
||
|
<t hangText="ldns_rdf* ldns_pkt_answerfrom(ldns_pkt *pkt):">
|
||
|
Returns the IP address from which we received this packet. User-created
|
||
|
packets will return NULL.
|
||
|
|
||
|
</t>
|
||
|
<t hangText="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??]
|
||
|
|
||
|
</t>
|
||
|
<t hangText="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.
|
||
|
|
||
|
</t>
|
||
|
<t hangText="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.
|
||
|
</t>
|
||
|
<t hangText="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.
|
||
|
</t>
|
||
|
<t hangText="ldns_rr_list *ldns_pkt_rrset(ldns_pkt *pkt,...):">
|
||
|
Retrieve all RRs in a packet matching certain criteria. XXX function needs
|
||
|
to be specified better.
|
||
|
</t>
|
||
|
<t hangText="void *ldns_pkt_print(FILE *s, ldns_pkt *p):">
|
||
|
Print packet p to stream s.
|
||
|
</t>
|
||
|
|
||
|
</list>
|
||
|
</t>
|
||
|
</section> <!-- "Packet Structure" -->
|
||
|
|
||
|
<section title="Specific RR Structures">
|
||
|
<t>
|
||
|
Some resource records can have special access function no other RR has.
|
||
|
Those are detailed here. XXX TODO don't exist (yet?).
|
||
|
</t>
|
||
|
</section> <!-- "Specific RR Structures" -->
|
||
|
|
||
|
<section title="Exported Defines and Macros">
|
||
|
<t>
|
||
|
insert your long list here.
|
||
|
</t>
|
||
|
</section> <!-- "Exported defines and macros" -->
|
||
|
|
||
|
<section title="Examples">
|
||
|
<t>
|
||
|
A small example, which queries a nameserver on localhost
|
||
|
to diplay the MX records for miek.nl.
|
||
|
</t>
|
||
|
|
||
|
<t>
|
||
|
<figure>
|
||
|
<artwork>
|
||
|
/**
|
||
|
* An example ldns program
|
||
|
* In semi-C code
|
||
|
*
|
||
|
* Setup a resolver
|
||
|
* Query a nameserver
|
||
|
* Print the result
|
||
|
*/
|
||
|
|
||
|
#include <ldns.h>
|
||
|
|
||
|
int
|
||
|
main(void)
|
||
|
{
|
||
|
ldns_resolver *res;
|
||
|
ldns_rdf *default_dom;
|
||
|
ldns_rdf *nameserver;
|
||
|
ldns_rdf *qname;
|
||
|
ldns_pkt *pkt;
|
||
|
|
||
|
/* init */
|
||
|
res = ldns_resolver_new();
|
||
|
if (!res)
|
||
|
return 1;
|
||
|
|
||
|
/* create a default domain and add it */
|
||
|
default_dom = ldns_rdf_new_frm_str("miek.nl.", LDNS_RDF_TYPE_DNAME);
|
||
|
nameserver = ldns_rdf_new_frm_str("127.0.0.1", LDNS_RDF_TYPE_A);
|
||
|
|
||
|
if (ldns_resolver_domain(res, default_dom) != LDNS_STATUS_OK)
|
||
|
return 1;
|
||
|
if (ldns_resolver_nameserver_push(res, nameserver) != LDNS_STATUS_OK)
|
||
|
return 1;
|
||
|
|
||
|
/* setup the question */
|
||
|
qname = ldns_rdf_new_frm_str("www", LDNS_RDF_TYPE_DNAME);
|
||
|
|
||
|
/* fire it off. "miek.nl." will be added */
|
||
|
pkt = ldns_resolver_query(res, qname, LDNS_RR_TYPE_MX, NULL);
|
||
|
|
||
|
/* print the resulting pkt to stdout */
|
||
|
ldns_pkt_print(stdout, pkt);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
</artwork>
|
||
|
</figure>
|
||
|
</t>
|
||
|
</section> <!-- title="Short Example" -->
|
||
|
|
||
|
</middle>
|
||
|
<back>
|
||
|
</back>
|
||
|
</rfc>
|