![]() |
![]()
| ![]() |
![]()
NAMEudns - stub DNS resolver library SYNOPSYS#include <udns.h> struct dns_ctx; struct dns_query; extern struct dns_ctx dns_defctx; struct dns_ctx *ctx; typedef void dns_query_fn(ctx, void *result, void *data); typedef int dns_parse_fn(const unsigned char *qnd, DESCRIPTIONThe DNS library, udns, implements thread-safe stub DNS resolver functionality, which may be used both traditional, synchronous way and asynchronously, with application-supplied event loop. While DNS works with both TCP and UDP, performing UDP query first and if the result does not fit in UDP buffer (512 bytes max for original DNS protocol), retrying the query over TCP, the library uses UDP only, but uses EDNS0 (RFC2671) extensions which allows larger UDP buffers. The library uses single UDP socket to perform all operations even when asking multiple nameservers. This way, it is very simple to use the library in asynchronous event-loop applications: an application should add only single socket to the set of filedescriptors it monitors for I/O. The library uses two main objects, resolver context of type struct dns_ctx, and query structure of type struct dns_query, both are opaque for an application. Resolver context holds global information about the resolver, such as list of nameservers to use, list of active requests and the like. Query objects holds information about a single DNS query in progress and are allocated/processed/freed by the library. Pointer to query structure may be treated as an identifier of an in-progress query and may be used to cancel the asynchronous query or to wait for it to complete. Asynchronous interface works as follows. An application initializes resolver context, submits any number of queries for it using one of supplied dns_submit_XXX() routines (each return the query identifier as pointer to query structure), waits for input on the UDP socket used by the library, and gives some control to the library by calling dns_ioevent() and dns_timeouts() routines when appropriate. The library performs all necessary processing and executes application supplied callback routine when a query completes (either successefully or not), giving it the result if any, pointer to the resolver context (from which completion status may be obtained), and the data pointer supplied by an application when the query has been submitted. When submitting a query, an application requests how to handle the reply -- to either return raw DNS reply packet for its own low-level processing, or it may provide an address of parsing routine of type dns_parse_fn to perform conversion of on-wire format into easy to use data structure (the library provides parsing routines for several commonly used resource record types, as well as type-safe higher-level interface that requests parsing automatically). The I/O monitoring and timeout handling may be either traditional select() or poll() based, or any callback-driven technique may be used. Additionally, the library provides traditional synchronous interface, which may be intermixed with asynchronous calls (during synchronous query processing, other asynchronous queries for the same resolver context continued to be processed as usual). An application uses one of numerous dns_resolve_XXX() routines provided by the library to perform a query. As with asynchronous interface, an application may either request to return raw DNS packet or type-specific data structure by providing the parsing routine to handle the reply. Every routine from dns_resolve_XXX() series return pointer to result or NULL in case of any error. Query completion status (or length of the raw DNS packet) is available from the resolver context using dns_status() routine, the same way as for the asynchronous interface. Internally, library uses on-wire format of domain names, referred to as DN format in this manual page. This is a series of domain labels with preceding length byte, terminated by zero-length label which is integral part of the DN format. There are several routines provided to convert from traditional asciiz string to DN and back. Higher-level type-specific query interface hides the DN format from an application. COMMON DEFINITIONSEvery DNS Resource Record (RR) has a type and a class. The library defines several integer constants, DNS_C_XXX and DNS_T_XXX, to use as symbolic names for RR classes and types, such as DNS_C_IN for Internet class, DNS_T_A for IPv4 address record type and so on. See udns.h header file for complete list of all such constants. The following constants are defined in udns.h header file:
Additionally, several constants are defined to simplify work with raw DNS packets, such as DNS response codes (DNS_R_XXX), DNS header layout (DNS_H_XXX) and others. Again, see udns.h for complete list. Library error codes (DNS_E_XXX) are described later in this manual page. RESOLVER CONTEXTResolver context, of type struct dns_ctx, is an object which is opaque to an application. Several routines provided by the library to initialize, copy and free resolver contexts. Most other high-level routines in this library expects a pointer to resolver context, ctx, as the first argument. There is a default resolver context available, named dns_defctx. When the context pointer ctx passed to a routine is NULL, dns_defctx is used. Several resolver contexts may be active at the same time, for example, when an application is multi-threaded and each thread uses resolver. In order to use the library, an application should initialize and open one or more resolver context objects. These are two separate actions, performed by dns_init() (or dns_reset()), and dns_open(). Between the two calls, an application is free to pefrorm additional initialisation, such as setting custom nameservers, options or domain search lists. Optionally, in case no additional custom initialisation is required, dns_init() may open the context if do_open argument (see below) is non-zero. When initializing resolver context, the library uses information from system file /etc/resolv.conf (see resolv.conf(5)), consults environment variables $LOCALDOMAIN, $NSCACHEIP, $NAMESERVERS and $RES_OPTIONS, and local host name to obtain list of local nameservers, domain name search list and various resolver options. The following routines to initialize resolver context are available: void dns_reset(ctx) int dns_init(ctx, int do_open) dns_reset() resets a given resolver context to
default values, preparing it to be opened by dns_open(). It is ok to
call this routine against opened and active context - all active queries will
be dropped, sockets will be closed and so on. This routine does not initialize
any parameters from system configuration files, use dns_init() for
this. There's no error return - operation always succeeds. dns_init()
does everything dns_reset() does, plus initializes various parameters
of the context according to system configuration and process environment
variables. If do_open is non-zero, dns_init() calls
dns_open(), so that the whole library initialisation is performed in a
single step.
struct dns_ctx *dns_new(struct dns_ctx *copy) void dns_free(ctx) dns_new() allocates new resolver context and
copies all parameters for a given resolver context copy, or default
context if copy is NULL, and returns pointer to the newly allocated
context. The context being copied should be initialized. dns_new() may
fail if there's no memory available to make a copy of copy, in which
case the routine will return NULL pointer. dns_free() is used to close
associated socket and free resolver context resources and cancelling
(abandoming) all active queries associated with it. It's an error to free
dns_defctx, only dynamically allocated contexts returned by
dns_new() are allowed to be freed by dns_free().
int dns_add_serv(ctx, const char *servaddr) int dns_add_serv_s(ctx, const struct sockaddr *sa) int dns_add_srch(ctx, const char *srch) Add an element to list of nameservers
(dns_add_serv(), as asciiz-string servaddr with an IP address of
the nameserver, and dns_add_serv_s(), as initialized socket address
sa), or search list (dns_add_srch(), as a pointer to domain
name) for the given context ctx. If the last argument is a NULL
pointer, the corresponding list (search or nameserver) is reset instead. Upon
successeful completion, each routine returns new number of elements in the
list in question. On error, negative value is returned and global variable
errno is set appropriately. It is an error to call any of this
functions if the context is opened (after dns_open() or
dns_init() with non-zero argument).
int dns_set_opts(ctx, const char *opts) set resolver context options from opts string, in
the same way as processing options statement in resolv.conf and
$RES_OPTIONS environment variable. Return number of
unrecognized/invalid options found (all recognized and valid options gets
processed).
void dns_set_opt(ctx, int opt, val) TODO The flags argument is a bitmask with
the following bits defined:
int dns_open(ctx) int dns_sock(const ctx) void dns_close(ctx) dns_open() opens the UDP socket used for queries
if not already open, and return associated filedescriptor (or negative value
in case of error). Before any query can be submitted, the context should be
opened using this routine. And before opening, the context should be
initialized. dns_sock() return the UDP socket if open, or -1 if not.
dns_close() closes the UDP socket if it was open, and drops all active
queries if any.
int dns_active(const ctx) return number of active queries queued for the given
context ctx, or zero if none.
int dns_status(const ctx) return status code from last operation. When using
synchronous interface, this is the query completion status of the last query.
With asynchronous interface, from within the callback routine, this is the
query completion status of the query for which the callback is being called.
When query submission fails, this is the error code indicating failure reason.
All error codes are negative and are represented by DNS_E_XXX
constants described below.
void dns_ioevent(ctx, time_t now) this routine may be called by an application to process
I/O events on the UDP socket used by the library, as returned by
dns_sock(). The routine tries to receive incoming UDP datagram from the
socket and process it. The socket is set up to be non-blocking, so it is safe
to call the routine even if there's no data to read. The routine will process
as many datagrams as are queued for the socket, so it is safe to use it with
either level-triggered or edge-triggered I/O monitoring model. The now
argument is either a current time as returned by time(), or 0, in which
case the routine will obtain current time by it's own.
int dns_timeouts(ctx, int maxwait, time_t now) process any pending timeouts and return number of
secounds from current time (now if it is not 0) to the time when the
library wants the application to pass it control to process more queued
requests. In case when there are no requests pending, this time is -1. The
routine will not request a time larger than maxwait secounds if it is
greather or equal to zero. If now is 0, the routine will obtain current
time by it's own; when it is not 0, it should contain current time as returned
by time().
typedef void dns_utm_fn(ctx, int timeout, void *data) void dns_set_tmcbck(ctx, dns_utm_fn *utmfn, void *data) An application may use custom callback-based I/O
multiplexing mechanism. Usually such a mechanism have concept of a
timer, and an ability to register a timer event in a form of a callback
routine which will be executed after certain amount of time. In order to use
such an event mechanism, udns provides an ability to register and de-register
timer events necessary for internal processing using whatever event mechanism
an application uses. For this to work, it is possible to assotiate a pointer
to a routine that will perform necessary work for (de)registering timer events
with a given resolver context, and udns will call that routine at appropriate
times. Prototype of such a routine is shown by dns_utm_fn typedef
above. Libudns assotiates single timer with resolver context. User-supplied
utmfn routine will be called by the library with the following
arguments:
The data argument passed to the routine will be the same as passed to dns_set_tmcbck(). When a timer expires, an application should call dns_timeouts() routine (see below). Non-callback timer usage is provided too. XXXX TODO: some more resolver context routines, like dns_set_dbgfn() etc. QUERY INTERFACEThere are two ways to perform DNS queries: traditional synchronous way, when udns performs all the necessary processing and return control to the application only when the query completes, and asynchronous way, when an application submits one or more queries to the library using given resolver context, and waits for completion by monitoring filedescriptor used by library and calling library routines to process input on that filedescriptor. Asynchronous mode works with callback routines: an application supplies an address of a routine to execute when the query completes, and a data pointer, which is passed to the callback routine. Queries are submitted to the library in a form of struct dns_query. To perform asynchronous query, an application calls one of the dns_submit_XXX() rounines, and provides necessary information for a callback, together with all the query parameters. When the query completes, library will call application-supplied callback routine, giving it the resolver context (which holds query completion status), dynamically allocated result (which will be either raw DNS packet or, if applicatin requested parsing the result by specifying non-NULL parse routine, ready-to-use type-specific structure), and a data pointer provided by an application when it submitted the query. It is the application who's responsible for freeing the result memory. Generic query callback routine looks like this: typedef void dns_query_fn(ctx, void *result, void *data)Type-specific query interface expects similar form of callback routine with the only difference in type of result argument, which will be pointer to specific data structure (decoded reply) instead of this void pointer to raw DNS packet data. Result parsing routine looks like this: typedef int dns_parse_fn(const unsigned char *qdn,When called by the library, the arguments are as follows: pkt points to the start of the packet received; end points past the end of the packet received; cur points past the query DN in the query section of the packet; qdn points to the original query DN. The routine should allocate a single buffer to hold the result, parse the reply filling in the buffer, and return the buffer using resultp argument. It returns 0 in case of error, or udns error code (DNS_E_XXX constants) in case of error. Note that by the time when the parse routine is called by the library, packet is already verified to be a reply to the original query, by matching query DN, query class and query type. Type-specific query interface supplies necessary parsing routines automatically. In case of error, query completion status as returned by dns_status(ctx), will contain one of the following values:
Library provides two series of routines which uses similar interface -- one for asynchronous queries and another for synchronous queries. There are two general low-level routines in each series to submit (asynchronous interface) and resolve (synchronous interface) queries, as well as several type-specific routines with more easy-to-use interfaces. To submit an asynchronous query, use one of dns_submit_XXX() routine, each of which accepts query parameters, pointers to callback routine and to callback data, and optional current time hint. Note type-specific dns_submit_XXX() routines expects specific type of the callback routine as well, which accepts reply as a pointer to corresponding structure, not a void pointer). Every dns_submit_XXX() routine return pointer to internal query structure of type struct dns_query, used as an identifier for the given query. To resolve a query synchronously, use one of dns_resolve_XXX() routines, which accepts the same query parameters (but not the callback pointers) as corresponding dns_submit_XXX(), and return the query result, which is the same as passed to the callback routine in case of asynchronous interface. In either case, the result memory (if the query completed successefully) is dynamically allocated and should be freed by an application. If the query failed for any reason, the result will be NULL, and error status will be available from dns_status(ctx) routine as shown above. struct dns_query * dns_submit_dn(ctx, submit a query for processing for the given resolver
context ctx. Two routines differs only in 3rd argument, which is domain
name in DN format (dn) or asciiz string (name). The query will
be performed for the given domain name, with type qtyp in class
qcls, using option bits in flags, using RR parsing routine
pointed by parse if not-NULL, and upon completion, cbck function
will be called with the data argument. In case of successeful query
submission, the routine return pointer to internal query structure which may
be treated as an identifier of the query as used by the library, and may be
used as an argument for dns_cancel() routine. In case of error, NULL
will be returned, and context error status (available using
dns_status() routine) will be set to corresponding error code, which in
this case may be DNS_E_BADQUERY if the name of dn is invalid,
DNS_E_NOMEM if there's no memory available to allocate query structure, or
DNS_E_TEMPFAIL if an internal error occurred.
void *dns_resolve_dn(ctx, synchronous interface. The routines perform all the steps
necessary to resolve the given query and return the result. If there's no
positive result for any reason, all the routines return NULL, and set context
error status (available using dns_status() routine) to indicate the
error code. If the query was successeful, context status code will contain
either the length of the raw DNS reply packet if parse argument was
NULL (in which case the return value is pointer to the reply DNS packet), or 0
(in which case the return value is the result of parse routine). If the
query successeful (return value is not NULL), the memory returned was
dynamically allocated by the library and should be free()d by application
after use.
void *dns_resolve(ctx, struct dns_query *q) wait for the given query q, as returned by one of
dns_submit_XXX() routines, for completion, and return the
result. The callback routine will not be called for this query. After
completion, the query identifier q is not valid. Both
dns_resolve_dn() and dns_resolve_p() are just wrappers around
corresponding submit routines and this dns_resolve() routine.
void dns_cancel(ctx, struct dns_query *q) cancel an active query q, without calling a
callback routine. After completion, the query identifier q is not
valid.
TYPE-SPECIFIC QUERIESIn addition to the generic low-level query interface, the library provides a set of routines to perform specific queries in a type-safe manner, as well as parsers for several well-known resource record types. The library implements high-level interface for A, AAAA, PTR, MX and TXT records and DNSBL and RHSBL functionality. These routines returns specific types as result of a query, instead of raw DNS packets. The following types and routines are available. struct dns_rr_null { NULL RR set, used as a base for all other RR type structures. Every RR structure as used by the library have four standard fields as in struct dns_rr_null. IN A Queriesstruct dns_rr_a4 { /* IN A RRset */ The dns_rr_a4 structure holds a result of an IN A query, which is an array of IPv4 addresses. Callback routine for IN A queries expected to be of type dns_query_a4_fn, which expects pointer to dns_rr_a4 structure as query result instead of raw DNS packet. The dns_parse_a4() is used to convert raw DNS reply packet into dns_rr_a4 structure (it is used internally and may be used directly too with generic query interface). Routines dns_submit_a4() and dns_resolve_a4() are used to perform A IN queries in a type-safe manner. The name parameter is the domain name in question, and flags is query flags bitmask, with one bit, DNS_NOSRCH, of practical interest (if the name is absolute, that is, it ends up with a dot, DNS_NOSRCH flag will be set automatically). IN AAAA Queriesstruct dns_rr_a6 { /* IN AAAA RRset */ The dns_rr_a6 structure holds a result of an IN AAAA query, which is an array of IPv6 addresses. Callback routine for IN AAAA queries expected to be of type dns_query_a6_fn, which expects pointer to dns_rr_a6 structure as query result instead of raw DNS packet. The dns_parse_a6() is used to convert raw DNS reply packet into dns_rr_a6 structure (it is used internally and may be used directly too with generic query interface). Routines dns_submit_a6() and dns_resolve_a6() are used to perform AAAA IN queries in a type-safe manner. The name parameter is the domain name in question, and flags is query flags bitmask, with one bit, DNS_NOSRCH, of practical interest (if the name is absolute, that is, it ends up with a dot, DNS_NOSRCH flag will be set automatically). IN PTR Queriesstruct dns_rr_ptr { /* IN PTR RRset */ The dns_rr_ptr structure holds a result of an IN PTR query, which is an array of domain name pointers for a given IPv4 or IPv6 address. Callback routine for IN PTR queries expected to be of type dns_query_ptr_fn, which expects pointer to dns_rr_ptr structure as query result instead of raw DNS packet. The dns_parse_ptr() is used to convert raw DNS reply packet into dns_rr_ptr structure (it is used internally and may be used directly too with generic query interface). Routines dns_submit_a4ptr() and dns_resolve_a4ptr() are used to perform IN PTR queries for IPv4 addresses in a type-safe manner. Routines dns_submit_a6ptr() and dns_resolve_a6ptr() are used to perform IN PTR queries for IPv6 addresses. IN MX Queriesstruct dns_mx { /* single MX record */ The dns_rr_mx structure holds a result of an IN MX query, which is an array of mail exchangers for a given domain. Callback routine for IN MX queries expected to be of type dns_query_mx_fn, which expects pointer to dns_rr_mx structure as query result instead of raw DNS packet. The dns_parse_mx() is used to convert raw DNS reply packet into dns_rr_mx structure (it is used internally and may be used directly too with generic query interface). Routines dns_submit_mx() and dns_resolve_mx() are used to perform IN MX queries in a type-safe manner. The name parameter is the domain name in question, and flags is query flags bitmask, with one bit, DNS_NOSRCH, of practical interest (if the name is absolute, that is, it ends up with a dot, DNS_NOSRCH flag will be set automatically). TXT Queriesstruct dns_txt { /* single TXT record */ The dns_rr_txt structure holds a result of a TXT query, which is an array of text records for a given domain name. Callback routine for TXT queries expected to be of type dns_query_txt_fn, which expects pointer to dns_rr_txt structure as query result instead of raw DNS packet. The dns_parse_txt() is used to convert raw DNS reply packet into dns_rr_txt structure (it is used internally and may be used directly too with generic query interface). Routines dns_submit_txt() and dns_resolve_txt() are used to perform IN MX queries in a type-safe manner. The name parameter is the domain name in question, and flags is query flags bitmask, with one bit, DNS_NOSRCH, of practical interest (if the name is absolute, that is, it ends up with a dot, DNS_NOSRCH flag will be set automatically). Note that each TXT string is represented by struct dns_txt, while zero-terminated (and the len field of the structure does not include the terminator), may contain embedded null characters -- content of TXT records is not interpreted by the library in any way. SRV Queriesstruct dns_srv { /* single SRV record */ The dns_rr_srv structure holds a result of an IN SRV (rfc2782) query, which is an array of servers (together with port numbers) which are performing operations for a given service using given protocol on a target domain name. Callback routine for IN SRV queries expected to be of type dns_query_srv_fn, which expects pointer to dns_rr_srv structure as query result instead of raw DNS packet. The dns_parse_srv() is used to convert raw DNS reply packet into dns_rr_srv structure (it is used internally and may be used directly too with generic query interface). Routines dns_submit_srv() and dns_resolve_srv() are used to perform IN SRV queries in a type-safe manner. The name parameter is the domain name in question, service and protocl specifies the service and the protocol in question (the library will construct query DN according to rfc2782 rules) and may be NULL (in this case the library assumes name parameter holds the complete SRV query), and flags is query flags bitmask, with one bit, DNS_NOSRCH, of practical interest (if the name is absolute, that is, it ends up with a dot, DNS_NOSRCH flag will be set automatically). NAPTR Queriesstruct dns_naptr { /* single NAPTR record */ The dns_rr_naptr structure holds a result of an IN NAPTR (rfc3403) query. Callback routine for IN NAPTR queries expected to be of type dns_query_naptr_fn, expects pointer to dns_rr_naptr structure as query result instead of raw DNS packet. The dns_parse_naptr() is used to convert raw DNS reply packet into dns_rr_naptr structure (it is used internally and may be used directly too with generic query interface). Routines dns_submit_naptr() and dns_resolve_naptr() are used to perform IN NAPTR queries in a type-safe manner. The name parameter is the domain name in question, and flags is query flags bitmask, with one bit, DNS_NOSRCH, of practical interest (if the name is absolute, that is, it ends up with a dot, DNS_NOSRCH flag will be set automatically). DNSBL InterfaceA DNS-based blocklists, or a DNSBLs, are in wide use nowadays, especially to protect mailservers from spammers. The library provides DNSBL interface, a set of routines to perform queries against DNSBLs. Routines accepts an IP address (IPv4 and IPv6 are both supported) and a base DNSBL zone as query parameters, and returns either dns_rr_a4 or dns_rr_txt structure. Note that IPv6 interface return IPv4 RRset. struct dns_query * dns_submit_a4dnsbl(ctx,Perform (submit or resolve) a DNSBL query for the given dnsbl domain and an IP addr in question, requesting either A or TXT records. RHSBL InterfaceRHSBL is similar to DNSBL, but instead of an IP address, the parameter is a domain name. struct dns_query * dns_submit_rhsbl(ctx, const char *name, const char *rhsbl,Perform (submit or resolve) a RHSBL query for the given rhsbl domain and name in question, requesting either A or TXT records. LOW-LEVEL INTERFACEDomain Names (DNs)A DN is a series of domain name labels each starts with length byte, followed by empty label (label with zero length). The following routines to work with DNs are provided. unsigned dns_dnlen(const unsigned char *dn) return length of the domain name dn, including the
terminating label.
unsigned dns_dnlabels(const unsigned char *dn) return number of non-zero labels in domain name
dn.
unsigned dns_dnequal(dn1, dn2) test whenever the two domain names, dn1 and
dn2, are equal (case-insensitive). Return domain name length if equal
or 0 if not.
unsigned dns_dntodn(sdn, ddn, dnsiz) copies the source domain name sdn to destination
buffer ddn of size dnsiz. Return domain name length or 0 if
ddn is too small.
int dns_ptodn(name, namelen, dn, dnsiz, isabs) int dns_sptodn(name, dn, dnsiz) convert asciiz name name of length namelen
to DN format, placing result into buffer dn of size dnsiz.
Return length of the DN if successeful, 0 if the dn buffer supplied is
too small, or negative value if name is invalid. If isabs is
non-NULL and conversion was successeful, *isabs will be set to either 1
or 0 depending whenever name was absolute (i.e. ending with a dot) or
not. Name length, namelength, may be zero, in which case
strlen(name) will be used. Second form, dns_sptodn(), is a
simplified form of dns_ptodn(), equivalent to
dns_ptodn(name, 0, dn, dnlen, 0). extern const unsigned char dns_inaddr_arpa_dn[] int dns_a4todn(const struct in_addr *addr, const unsigned char *tdn, several variants of routines to convert IPv4 and IPv6
address addr into reverseDNS-like domain name in DN format, storing
result in dn of size dnsiz. tdn (or tname) is the
base zone name, like in-addr.arpa for IPv4 or in6.arpa for IPv6. If tdn
(or tname) is NULL, dns_inaddr_arpa_dn (or
dns_ip6_arpa_dn) will be used. The routines may be used to construct a
DN for a DNSBL lookup for example. All routines return length of the resulting
DN on success, -1 if resulting DN is invalid, or 0 if the dn buffer
(dnsiz) is too small. To hold standard rDNS DN, a buffer of size
DNS_A4RSIZE (30 bytes) for IPv4 address, or DNS_A6RSIZE (74
bytes) for IPv6 address, is sufficient.
int dns_dntop(dn, name, namesiz) convert domain name dn in DN format to asciiz
string, placing result into name buffer of size namesiz. Maximum
length of asciiz representation of domain name is DNS_MAXNAME (1024)
bytes. Root domain is represented as empty string. Return length of the
resulting name (including terminating character, i.e. strlen(name)+1) on
success, 0 if the name buffer is too small, or negative value if
dn is invalid (last case should never happen since all routines in this
library which produce domain names ensure the DNs generated are valid).
const char *dns_dntosp(const unsigned char *dn) convert domain name dn in DN format to asciiz
string using static buffer. Return the resulting asciiz string on success or
NULL on failure. Note since this routine uses static buffer, it is not
thread-safe.
unsigned dns_dntop_size(const unsigned char *dn) return the buffer size needed to convert the dn
domain name in DN format to asciiz string, for dns_dntop(). The routine
return either the size of buffer required, including the trailing zero byte,
or 0 if dn is invalid.
Working with DNS PacketsThe following routines are provided to encode and decode DNS on-wire packets. This is low-level interface. DNS response codes (returned by dns_rcode() routine) are defined as constants prefixed with DNS_R_. See udns.h header file for the complete list. In particular, constants DNS_R_NOERROR (0), DNS_R_SERVFAIL, DNS_R_NXDOMAIN may be of interest to an application. unsigned dns_get16(const unsigned char *p) unsigned dns_get32(const unsigned char *p) helper routines, convert 16-bit or 32-bit integer in
on-wire format pointed to by p to unsigned.
unsigned char *dns_put16(unsigned char *d, unsigned n) unsigned char *dns_put32(unsigned char *d, unsigned n) helper routine, convert unsigned 16-bit or 32-bit integer
n to on-wire format to buffer pointed to by d, return d+2
or d+4.
DNS_HSIZE (12) defines size of DNS header. Data section in the DNS
packet immediately follows the header. In the header, there are query
identifier (id), various flags and codes, and number of resource records in
various data sections. See udns.h header file for complete list of DNS header
definitions.
unsigned dns_qid(const unsigned char *pkt) int dns_rd(const unsigned char *pkt) int dns_tc(const unsigned char *pkt) int dns_aa(const unsigned char *pkt) int dns_qr(const unsigned char *pkt) int dns_ra(const unsigned char *pkt) unsigned dns_opcode(const unsigned char *pkt) unsigned dns_rcode(const unsigned char *pkt) unsigned dns_numqd(const unsigned char *pkt) unsigned dns_numan(const unsigned char *pkt) unsigned dns_numns(const unsigned char *pkt) unsigned dns_numar(const unsigned char *pkt) const unsigned char *dns_payload(const unsigned char *pkt) return various parts from the DNS packet header
pkt: query identifier (qid), recursion desired (rd) flag, truncation
occurred (tc) flag, authoritative answer (aa) flag, query response (qr) flag,
recursion available (ra) flag, operation code (opcode), result code (rcode),
number of entries in question section (numqd), number of answers (numan),
number of authority records (numns), number of additional records (numar), and
the pointer to the packet data (payload).
int dns_getdn(pkt, curp, pkte, dn, dnsiz) const unsigned char *dns_skipdn(cur, pkte) dns_getdn() extract DN from DNS packet pkt
which ends before pkte starting at position *curp into buffer
pointed to by dn of size dnsiz. Upon successeful completion,
*curp will point to the next byte in the packet after the extracted
domain name. It return positive number (length of the DN if dn) upon
successeful completion, negative value on error (when the packet contains
invalid data), or zero if the dnsiz is too small (maximum length of a
domain name is DNS_MAXDN). dns_skipdn() return pointer to the
next byte in DNS packet which ends up before pkte after a domain name
which starts at the cur byte, or NULL if the packet is invalid.
dns_skipdn() is more or less equivalent to what dns_getdn()
does, except it does not actually extract the domain name in question, and
uses simpler interface.
struct dns_rr { The dns_rr structure is used to hold information
about single DNS Resource Record (RR) in an easy to use form.
struct dns_parse { The dns_parse structure is used to parse DNS reply
packet. It holds information about the packet being parsed (dnsp_pkt, dnsp_end
and dnsp_cur fields), number of RRs in the current section left to do, and the
information about specific RR which we're looking for (dnsp_qdn, dnsp_qcls and
dnsp_qtyp fields).
int dns_initparse(struct dns_parse *p, initializes the RR parsing structure p. Arguments
pkt, cur and end should describe the received packet:
pkt is the start of the packet, end points to the next byte
after the end of the packet, and cur points past the query DN in query
section (to query class+type information). And qdn points to the query
DN. This is the arguments passed to dns_parse_fn() routine.
dns_initparse() initializes dnsp_pkt, dnsp_end and
dnsp_qdn fields to the corresponding arguments, extracts and
initializes dnsp_qcls and dnsp_qtyp fields to the values found
at cur pointer, initializes dnsp_cur and dnsp_ans fields
to be cur+4 (to the start of answer section), and initializes
dnsp_rrl field to be number of entries in answer section.
dnsp_ttl will be set to max TTL value, 0xffffffff, and dnsp_nrr
to 0.
int dns_nextrr(struct dns_parse *p, struct dns_rr *rr); searches for next RR in the packet based on the criteria
provided in the p structure, filling in the rr structure and
advancing p->dnsp_cur to the next RR in the packet. RR
selection is based on dnsp_qdn, dnsp_qcls and dnsp_qtyp fields in the
dns_parse structure. Any (or all) of the 3 fields may be 0, which means any
actual value from the packet is acceptable. In case the field isn't 0 (or NULL
for dnsp_qdn), only RRs with corresponding characteristics are acceptable.
Additionally, when dnsp_qdn is non-NULL, dns_nextrr() performs
automatic CNAME expansion. Routine will return positive value on success, 0 in
case it reached the end of current section in the packet
(p->dnsp_rrl is zero), or negative value if next RR can not
be decoded (packet format is invalid). The routine updates
p->dnsp_qdn automatically when this field is non-NULL and it
encounters appropriate CNAME RRs (saving CNAME target in
p->dnsp_dnbuf), so after end of the process,
p->dnsp_qdn will point to canonical name of the domain in
question. The routine updates p->dnsp_ttl value to be the
minimum TTL of all RRs found.
void dns_rewind(struct dns_parse *p, const unsigned char *qdn) this routine "rewinds" the packet parse state
structure to be at the same state as after a call to dns_initparse(),
i.e. reposition the parse structure p to the start of answer section
and initialize p->dnsp_rrl to the number of entries in answer
section.
int dns_stdrr_size(const struct dns_parse *p); return size to hold standard RRset structure information,
as shown in dns_rr_null structure (for the query and canonical names).
Used to calculate amount of memory to allocate for common part of
type-specific RR structures in parsing routines.
void *dns_stdrr_finish(struct dns_rr_null *ret, char *cp, initializes standard RRset fields in ret structure
using buffer pointed to by cp, which should have at least as many bytes
as dns_stdrr_size(p) returned. Used to finalize common part of
type-specific RR structures in parsing routines.
See library source for usage examples of all the above low-level routines, especially source of the parsing routines. Auxilary Routinesint dns_pton(int af, const char *src, void *dst); privides functionality similar to standard
inet_pton() routine, to convert printable representation of an IP
address of family af (either AF_INET or AF_INET6) pointed
to by src into binary form suitable for socket addresses and
transmission over network, in buffer pointed to by dst. The destination
buffer should be of size 4 for AF_INET family or 16 for
AF_INET6. The return value is positive on success, 0 if src is
not a valid text representation of an address of family af, or negative
if the given address family is not supported.
const char *dns_ntop(int af, const void *src, privides functionality similar to standard
inet_ntop() routine, to convert binary representation of an IP address
of family af (either AF_INET or AF_INET6) pointed to by
src (either 4 or 16 bytes) into printable form in buffer in buffer
pointed to by dst of size dstsize. The destination buffer should
be at least of size 16 bytes for AF_INET family or 46 bytes for
AF_INET6. The return value is either dst, or NULL pointer if
dstsize is too small to hold this address or if the given address
family is not supported.
AUTHORThe udns library has been written by Michael Tokarev, mjt+udns@tls.msk.ru. VERSIONThis manual page corresponds to udns version 0.6, released Jul-2024.
|