diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2014-12-10 03:05:47 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2014-12-10 03:05:47 +0000 |
commit | 416ef5e2bf59bb2e45066a1d5d91ac677c0f48e5 (patch) | |
tree | 1c746d673dcec7a8488c6ac51db8245411034376 /doc/skadns | |
download | s6-dns-416ef5e2bf59bb2e45066a1d5d91ac677c0f48e5.tar.xz |
Initial commit
Diffstat (limited to 'doc/skadns')
-rw-r--r-- | doc/skadns/index.html | 262 | ||||
-rw-r--r-- | doc/skadns/skadnsd.html | 120 |
2 files changed, 382 insertions, 0 deletions
diff --git a/doc/skadns/index.html b/doc/skadns/index.html new file mode 100644 index 0000000..f02f2dd --- /dev/null +++ b/doc/skadns/index.html @@ -0,0 +1,262 @@ +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>s6-dns: the skadns library interface</title> + <meta name="Description" content="s6-dns: the skadns library interface" /> + <meta name="Keywords" content="s6-dns skadns library asynchronous resolution resolver client C interface" /> + <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="../index.html">s6-dns</a><br /> +<a href="http://skarnet.org/software/">Software</a><br /> +<a href="http://skarnet.org/">skarnet.org</a> +</p> + +<h1> The <tt>skadns</tt> library interface </h1> + +<p> + The <tt>skadns</tt> library provides an API for asynchronous DNS +resolution. +</p> + +<h2> Compiling </h2> + +<ul> +<ul> + <li> Make sure the s6-dns headers, as well as the skalibs headers, +are visible in your header search path. </li> + <li> Use <tt>#include <s6-dns/skadns.h></tt> </li> + <li> You might also want to include the <tt>s6-dns/s6dns.h</tt> header for +the definition of the <tt>s6dns_domain_t</tt> type and the various +qtype constants </li> +</ul> + +<h2> Linking </h2> + +<ul> + <li> Make sure the s6 libraries, as well as the skalibs libraries, +are visible in your library search path. </li> + <li> Link against <tt>-lskadns</tt> and <tt>-lskarnet</tt>. </li> + <li> If you're using a skadnsd service, also add `cat $SYSDEPS/socket.lib` +to the end of your linking command line, $SYSDEPS standing for your +skalibs sysdeps directory. </li> +</ul> + + +<h2> Programming </h2> + +<p> + Check the <tt>s6-dns/skadns.h</tt> header for the +exact function prototypes. +</p> + +<p> + Make sure your application is not disturbed by children it doesn't +know it has. This means paying some attention to the SIGCHLD handler, +if any, and to the way you perform <tt>waitpid()</tt>s. The best +practice is to use a +<a href="http://skarnet.org/software/skalibs/libstddjb/selfpipe.html">self-pipe</a> +to handle SIGCHLD (as well as other signals the application needs to trap), +and to <em>always</em> use <tt>wait_nohang()</tt> to reap children, +simply ignoring pids you don't know. +</p> + +<p> + If your (badly programmed) application has trouble handling unknown +children, consider using a skadnsd service. +</p> + +<h3> A programming example </h3> + +<p> + The <tt>src/clients/s6dns_generic_filter_main.c</tt> file in the s6-dns +package, used in the <tt>s6-dns*-filter</tt> programs, illustrates how to +use the skadns library. +</p> + +<h3> Starting and ending a session </h3> + +<pre> +skadns_t a = SKADNS_ZERO ; +tain_t deadline, stamp ; + +tain_now(&stamp) ; +tain_addsec(&deadline, &stamp, 2) + +// char const *path = SKADNS_IPCPATH ; +// skadns_start(&a, path, &deadline, &stamp) ; +skadns_startf(&a, &deadline, &stamp) ; +</pre> + +<p> +<tt>skadns_start</tt> starts a session with a skadnsd service, listening +on <em>path</em>. <br /> +<tt>skadns_startf</tt> starts a session with a skadnsd process as a child +(which is the simplest usage). <br /> +<tt>a</tt> is a skadns_t structure that must be declared and +initialized to SKADNS_ZERO. +<tt>stamp</tt> must be an accurate enough timestamp. <br /> +If the session initialization fails, the function returns 0 and errno is set; +else the function returns 1. +</p> +<p> +If the absolute time <tt>deadline</tt> is reached and the function +has not returned yet, it immediately returns 0 with errno set to ETIMEDOUT. + +Only local interprocess communications are involved; unless your system is +heavily overloaded, the function should return near-instantly. One or two +seconds of delay between <tt>stamp</tt> and <tt>deadline</tt> should be +enough: if the function takes more than that to return, then there is a +problem with the underlying processes. +</p> + +<p> + You can have more than one session open in parallel, by declaring +several distinct <tt>skadns_t</tt> structures and calling +<tt>skadns_startf</tt> (or <tt>skadns_start</tt>) more than once. +However, this is only useful if you need to perform more than +SKADNS_MAXCONCURRENCY, i.e. a thousand, concurrent requests. In +most situations, a single skadns session will be enough. +</p> + +<pre> +skadns_end(&a) ; +</pre> + +<p> +<tt>skadns_end</tt> frees all the resources used by the session. The +<tt>a</tt> structure is then reusable for another session. +</p> + +<h3> Sending a DNS query </h3> + +<pre> +s6dns_domain_t d ; +uint16 qtype ; +uint16 id ; +tain_t limit, deadline, stamp ; + +skadns_send(&a, &id, &d, qtype, &limit, &deadline, &stamp) ; +</pre> + +<p> +<tt>skadns_send</tt> starts the asynchronous resolution of domain <em>d</em> +with query type <em>qtype</em>. <em>d</em> must be encoded in packet form. +<em>stamp</em> must be an accurate enough timetamp. +If the resolution hasn't completed by deadline <em>limit</em>, it will +automatically fail with a status set to ETIMEDOUT. +</p> + +<p> + Like <tt>skadns_startf()</tt>, the <tt>skadns_send()</tt> call +is synchronous but should not be blocking; however, if it hasn't returned by +deadline <em>deadline</em>, it then returns 0 with errno set to ETIMEDOUT. +On failure, the call returns 0 and sets errno. On success, it returns 1 and +<em>id</em> is set to a 16-bit number identifying the query. +</p> + +<h3> Cancelling a query </h3> + +<pre> +skadns_cancel(&a, id, &deadline, &stamp) ; +</pre> + +<p> + <tt>skadns_cancel</tt> cancels the resolution identified by <em>id</em>. +<em>stamp</em> must be an accurate enough timestamp. +The call returns 1 on success, or 0 (and sets errno) on failure. It is +synchronous but should return almost-instantly; if it hasn't returned +by <em>deadline</em>, it then returns 0 ETIMEDOUT. +</p> + +<p> + After a query has been successfully canceled, its id can be discarded. +</p> + +<h3> Asynchronously waiting for answers </h3> + +<p> +<em> (from now on, the functions are listed with their prototypes instead +of usage examples.) </em> +</p> + +<pre> +int skadns_fd (skadns_t const *a) +</pre> + +<p> + Returns a file descriptor to select on for reading. Do not +<tt>read()</tt> it though. +</p> + +<pre> +int skadns_update (skadns_t *a) +</pre> + +<p> + Call this function whenever the fd checks readability: it will +update <em>a</em>'s internal structures with information from the +<a href="skadnsd.html">skadnsd</a> daemon. It returns -1 if an error +occurs; in case of success, it returns the number of identifiers for +which something happened. +</p> + +<p> + When <tt>skadns_update</tt> returns, +<tt>genalloc_s(uint16, &a->list)</tt> points to an array of +<tt>genalloc_len(uint16, &a->list)</tt> 16-bit unsigned +integers. Those integers are valid ids that can be used with the +following functions. +</p> + +<pre> +char const *skadns_packet (skadns_t *a, uint16 id) +int skadns_packetlen (skadns_t *a, uint16 id) +</pre> + +<p> + <tt>skadns_packet()</tt> returns a pointer to the DNS packet +containing the answer to the query identified by <em>id</em>, +and <tt>skadns_packetlen()</tt> returns its length. If an +error has occurred, <tt>skadns_packet()</tt> returns NULL and +<tt>skadns_packetlen()</tt> returns -1; either call sets errno +to a value identifying the error. Some errno values have a +special meaning: +</p> + +<ul> + <li> EAGAIN: the result has not arrived yet. </li> + <li> ECANCELED: the query has been canceled. </li> + <li> EINVAL: <em>id</em> does not identify a valid query. Note +that <strong>if</strong> you get EINVAL, <strong>then</strong> +<em>id</em> is invalid, but the reverse is not true: +using invalid ids is a programming error and may result in a crash. </li> +</ul> + +<pre> +int skadns_release (skadns_t *a, uint16 id) +</pre> + +<p> + <tt>skadns_release()</tt> frees the cell holding the result of +query <em>id</em>. It returns 1 on success, then <em>id</em> can +be discarded - further calls to <tt>skadns_send()</tt> may reuse +the same number. +</p> + +<p> + <tt>skadns_release()</tt> may fail, and return 0. This signals a +programming error and shouldn't be relied on - however, if it happens, +errno can help you identify the problem: +</p> + +<ul> + <li> EBUSY: the query is still pending, cancelled or not. </li> + <li> EINVAL: <em>id</em> is invalid. +</ul> + +</body> +</html> diff --git a/doc/skadns/skadnsd.html b/doc/skadns/skadnsd.html new file mode 100644 index 0000000..e8316b8 --- /dev/null +++ b/doc/skadns/skadnsd.html @@ -0,0 +1,120 @@ +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>s6-dns: the skadnsd internal program</title> + <meta name="Description" content="s6-dns: the skadnsd internal program" /> + <meta name="Keywords" content="s6-dns skadnsd asynchronous dns daemon" /> + <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> --> + </head> +<body> + +<a href="index.html">libskadns</a><br /> +<a href="../index.html">s6-dns</a><br /> +<a href="http://skarnet.org/software/">Software</a><br /> +<a href="http://skarnet.org/">skarnet.org</a><p /> + +<h1> The <tt>skadnsd</tt> program </h1> + +<p> +<tt>skadnsd</tt> is the skadns daemon. It reads a series of +queries from the client on stdin, resolves them asynchronously, +and writes +the answers to the client as soon as it gets them. It exits 0 +when its stdin closes. It exits 111 on any serious error, +writing the error message to stderr. +</p> + +<p> +<tt>skadnsd</tt> is a stub resolver. It reads <tt>/etc/resolv.conf</tt> +at start looking for a "nameserver" line containing +the address of a DNS cache (aka full resolver). It will exit 111 if it cannot +find any valid cache address in <tt>/etc/resolv.conf</tt>. If the +<tt>DNSCACHEIP</tt> environment variable is set, its value overrides +what <tt>/etc/resolv.conf</tt> says. +</p> + +<h2> Interface </h2> + +<p> +skadnsd does not fork, does not background itself automatically, +and does not use syslog. It is not meant to be run directly by the +user: it will be invoked and spawned by the skadns library calls. +</p> + +<p> + There are 2 ways to use skadnsd: +</p> +<ol> +<li> (preferred) Use the <tt>skadns_startf()</tt> library call. +A <tt>skadnsd</tt> child will then be spawned from your +calling process, and automatically reaped when you call +<tt>skadns_end()</tt>. It requires care with applications that +trap SIGCHLD. </li> +<li> Use the <tt>skadns_start()</tt> library call, together with +a <em>skadnsd service</em>. </li> +</ol> + +<h3> Running skadnsd as a child process </h3> + +<p> + This is the simplest and safest way of using <em>skadns</em>. Forget +about <tt>skadnsd</tt>: just start your library calls with +<tt>skadns_startf()</tt> and end them with <tt>skadns_end()</tt>. +Be careful though: if you're using SIGCHLD handlers, make sure they do +not interfere with the child processes your application has without +knowing. This is a general Unix programming rule. +</p> + +<h3> Running a skadnsd as a daemon: the skadnsd service </h3> + +<p> + In this mode, you set up a daemon listening on a Unix domain socket, +and clients connect to this socket to access the service. The +advantage of this setup is that it works even with badly written +clients that have trouble handling a child process; the drawback is +that it requires support from the system administrator. +</p> + +<p> +skadnsd has no "standalone" mode: it is designed to work with a Unix +domain superserver, like +<a href="http://skarnet.org/software/s6-networking/s6-ipcserver.html">s6-ipcserver</a>. +skadnsd follows the <a href="http://cr.yp.to/proto/ucspi.txt">UCSPI"</a> +interface, it can be directly executed from the superserver. +</p> + +<p> +You should run skadnsd (and its Unix superserver) under a specific user +and group, for elementary security reasons; and you should run its +dedicated logger as another specific user. Do NOT run skadnsd as root; +check your super-server documentation to find how +to run it under a specific account. +</p> + +<h2> Notes </h2> + +<ul> + <li> Users should never invoke <tt>skadnsd</tt> directly. It's an +internal program designed to be spawned by the skadns library. </li> + <li> If a poorly designed client sends a lot of queries and never reads the +answers, those will indefinitely queue up in the daemon, eating up +memory. You should run your process (or your Unix superserver, if you're +using a skadnsd service) under a program like +<a href="http://skarnet.org/software/s6/s6-softlimit.html">s6-softlimit</a> to +set a memory limit to every skadnsd instance. If skadnsd runs out of +allowed memory, it will simply die. </li> + <li> If you're using a skadnsd service: you should configure your +Unix superserver to set a maximum +number of concurrent skadnsd instances; most +Unix superserver implementations provide the +<tt>-c</tt> option for this. The s6-ipcserver program also +allows you to specify a maximum number of concurrent daemon +instances per client. </li> +<li> The only way to ensure absolute reliability of the skadnsd process is +to run it as a child, not as a daemon: use <tt>skadnsd_startf()</tt> when +possible. </li> +</ul> + +</body> +</html> |