<?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>