2 * Copyright (C) 2004, 2005, 2007-2009, 2012-2014 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: context.c,v 1.55 2009/09/02 23:48:03 tbox Exp $ */
21 lwres_context_create() creates a #lwres_context_t structure for use in
22 lightweight resolver operations. It holds a socket and other data
23 needed for communicating with a resolver daemon. The new
24 lwres_context_t is returned through contextp, a pointer to a
25 lwres_context_t pointer. This lwres_context_t pointer must initially
26 be NULL, and is modified to point to the newly created
29 When the lightweight resolver needs to perform dynamic memory
30 allocation, it will call malloc_function to allocate memory and
31 free_function to free it. If malloc_function and free_function are
32 NULL, memory is allocated using malloc and free. It is not
33 permitted to have a NULL malloc_function and a non-NULL free_function
34 or vice versa. arg is passed as the first parameter to the memory
35 allocation functions. If malloc_function and free_function are NULL,
36 arg is unused and should be passed as NULL.
38 Once memory for the structure has been allocated, it is initialized
39 using lwres_conf_init() and returned via *contextp.
41 lwres_context_destroy() destroys a #lwres_context_t, closing its
42 socket. contextp is a pointer to a pointer to the context that is to
43 be destroyed. The pointer will be set to NULL when the context has
46 The context holds a serial number that is used to identify resolver
47 request packets and associate responses with the corresponding
48 requests. This serial number is controlled using
49 lwres_context_initserial() and lwres_context_nextserial().
50 lwres_context_initserial() sets the serial number for context *ctx to
51 serial. lwres_context_nextserial() increments the serial number and
52 returns the previous value.
54 Memory for a lightweight resolver context is allocated and freed using
55 lwres_context_allocmem() and lwres_context_freemem(). These use
56 whatever allocations were defined when the context was created with
57 lwres_context_create(). lwres_context_allocmem() allocates len bytes
58 of memory and if successful returns a pointer to the allocated
59 storage. lwres_context_freemem() frees len bytes of space starting at
62 lwres_context_sendrecv() performs I/O for the context ctx. Data are
63 read and written from the context's socket. It writes data from
64 sendbase -- typically a lightweight resolver query packet -- and waits
65 for a reply which is copied to the receive buffer at recvbase. The
66 number of bytes that were written to this receive buffer is returned
69 \section context_return Return Values
71 lwres_context_create() returns #LWRES_R_NOMEMORY if memory for the
72 struct lwres_context could not be allocated, #LWRES_R_SUCCESS
75 Successful calls to the memory allocator lwres_context_allocmem()
76 return a pointer to the start of the allocated space. It returns NULL
77 if memory could not be allocated.
79 #LWRES_R_SUCCESS is returned when lwres_context_sendrecv() completes
80 successfully. #LWRES_R_IOERROR is returned if an I/O error occurs and
81 #LWRES_R_TIMEOUT is returned if lwres_context_sendrecv() times out
82 waiting for a response.
84 \section context_see See Also
86 lwres_conf_init(), malloc, free.
97 #include <lwres/lwres.h>
98 #include <lwres/net.h>
99 #include <lwres/platform.h>
101 #ifdef LWRES_PLATFORM_NEEDSYSSELECTH
102 #include <sys/select.h>
105 #include "context_p.h"
106 #include "assert_p.h"
109 * Some systems define the socket length argument as an int, some as size_t,
110 * some as socklen_t. The last is what the current POSIX standard mandates.
111 * This definition is here so it can be portable but easily changed if needed.
113 #ifndef LWRES_SOCKADDR_LEN_T
114 #define LWRES_SOCKADDR_LEN_T unsigned int
118 * Make a socket nonblocking.
120 #ifndef MAKE_NONBLOCKING
121 #define MAKE_NONBLOCKING(sd, retval) \
123 retval = fcntl(sd, F_GETFL, 0); \
124 if (retval != -1) { \
125 retval |= O_NONBLOCK; \
126 retval = fcntl(sd, F_SETFL, retval); \
131 LIBLWRES_EXTERNAL_DATA lwres_uint16_t lwres_udp_port = LWRES_UDP_PORT;
132 LIBLWRES_EXTERNAL_DATA const char *lwres_resolv_conf = LWRES_RESOLV_CONF;
135 lwres_malloc(void *, size_t);
138 lwres_free(void *, void *, size_t);
143 static lwres_result_t
144 context_connect(lwres_context_t *);
147 * Creates a #lwres_context_t structure for use in
148 * lightweight resolver operations.
151 lwres_context_create(lwres_context_t **contextp, void *arg,
152 lwres_malloc_t malloc_function,
153 lwres_free_t free_function,
156 lwres_context_t *ctx;
158 REQUIRE(contextp != NULL && *contextp == NULL);
161 * If we were not given anything special to use, use our own
162 * functions. These are just wrappers around malloc() and free().
164 if (malloc_function == NULL || free_function == NULL) {
165 REQUIRE(malloc_function == NULL);
166 REQUIRE(free_function == NULL);
167 malloc_function = lwres_malloc;
168 free_function = lwres_free;
171 ctx = malloc_function(arg, sizeof(lwres_context_t));
173 return (LWRES_R_NOMEMORY);
176 * Set up the context.
178 ctx->malloc = malloc_function;
179 ctx->free = free_function;
183 ctx->timeout = LWRES_DEFAULT_TIMEOUT;
185 ctx->serial = time(NULL); /* XXXMLG or BEW */
187 ctx->serial = _time32(NULL);
192 if ((flags & (LWRES_CONTEXT_USEIPV4 | LWRES_CONTEXT_USEIPV6)) ==
193 LWRES_CONTEXT_USEIPV6) {
196 if ((flags & (LWRES_CONTEXT_USEIPV4 | LWRES_CONTEXT_USEIPV6)) ==
197 LWRES_CONTEXT_USEIPV4) {
202 * Init resolv.conf bits.
204 lwres_conf_init(ctx);
207 return (LWRES_R_SUCCESS);
211 Destroys a #lwres_context_t, closing its socket.
212 contextp is a pointer to a pointer to the context that is
213 to be destroyed. The pointer will be set to NULL
214 when the context has been destroyed.
217 lwres_context_destroy(lwres_context_t **contextp) {
218 lwres_context_t *ctx;
220 REQUIRE(contextp != NULL && *contextp != NULL);
225 if (ctx->sock != -1) {
229 (void)close(ctx->sock);
233 CTXFREE(ctx, sizeof(lwres_context_t));
235 /*% Increments the serial number and returns the previous value. */
237 lwres_context_nextserial(lwres_context_t *ctx) {
238 REQUIRE(ctx != NULL);
240 return (ctx->serial++);
243 /*% Sets the serial number for context *ctx to serial. */
245 lwres_context_initserial(lwres_context_t *ctx, lwres_uint32_t serial) {
246 REQUIRE(ctx != NULL);
248 ctx->serial = serial;
251 /*% Frees len bytes of space starting at location mem. */
253 lwres_context_freemem(lwres_context_t *ctx, void *mem, size_t len) {
254 REQUIRE(mem != NULL);
260 /*% Allocates len bytes of memory and if successful returns a pointer to the allocated storage. */
262 lwres_context_allocmem(lwres_context_t *ctx, size_t len) {
265 return (CTXMALLOC(len));
269 lwres_malloc(void *arg, size_t len) {
278 memset(mem, 0xe5, len);
284 lwres_free(void *arg, void *mem, size_t len) {
287 memset(mem, 0xa9, len);
291 static lwres_result_t
292 context_connect(lwres_context_t *ctx) {
299 struct sockaddr_in sin;
300 struct sockaddr_in6 sin6;
302 LWRES_SOCKADDR_LEN_T salen;
305 if (ctx->confdata.lwnext != 0) {
306 memmove(&ctx->address, &ctx->confdata.lwservers[0],
307 sizeof(lwres_addr_t));
308 LWRES_LINK_INIT(&ctx->address, link);
310 /* The default is the IPv4 loopback address 127.0.0.1. */
311 memset(&ctx->address, 0, sizeof(ctx->address));
312 ctx->address.family = LWRES_ADDRTYPE_V4;
313 ctx->address.length = 4;
314 ctx->address.address[0] = 127;
315 ctx->address.address[1] = 0;
316 ctx->address.address[2] = 0;
317 ctx->address.address[3] = 1;
320 if (ctx->address.family == LWRES_ADDRTYPE_V4) {
321 memmove(&sin.sin_addr, ctx->address.address,
322 sizeof(sin.sin_addr));
323 sin.sin_port = htons(lwres_udp_port);
324 sin.sin_family = AF_INET;
325 sa = (struct sockaddr *)&sin;
328 } else if (ctx->address.family == LWRES_ADDRTYPE_V6) {
329 memmove(&sin6.sin6_addr, ctx->address.address,
330 sizeof(sin6.sin6_addr));
331 sin6.sin6_port = htons(lwres_udp_port);
332 sin6.sin6_family = AF_INET6;
333 sa = (struct sockaddr *)&sin6;
334 salen = sizeof(sin6);
337 return (LWRES_R_IOERROR);
342 s = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
345 return (LWRES_R_IOERROR);
348 if (s == INVALID_SOCKET) {
350 return (LWRES_R_IOERROR);
354 ret = connect(s, sa, salen);
360 return (LWRES_R_IOERROR);
363 MAKE_NONBLOCKING(s, ret);
369 return (LWRES_R_IOERROR);
374 return (LWRES_R_SUCCESS);
378 lwres_context_getsocket(lwres_context_t *ctx) {
383 lwres_context_send(lwres_context_t *ctx,
384 void *sendbase, int sendlen) {
386 lwres_result_t lwresult;
388 if (ctx->sock == -1) {
389 lwresult = context_connect(ctx);
390 if (lwresult != LWRES_R_SUCCESS)
392 INSIST(ctx->sock >= 0);
395 ret = sendto(ctx->sock, sendbase, sendlen, 0, NULL, 0);
397 return (LWRES_R_IOERROR);
399 return (LWRES_R_IOERROR);
401 return (LWRES_R_SUCCESS);
405 lwres_context_recv(lwres_context_t *ctx,
406 void *recvbase, int recvlen,
409 LWRES_SOCKADDR_LEN_T fromlen;
410 struct sockaddr_in sin;
411 struct sockaddr_in6 sin6;
415 if (ctx->address.family == LWRES_ADDRTYPE_V4) {
416 sa = (struct sockaddr *)&sin;
417 fromlen = sizeof(sin);
419 sa = (struct sockaddr *)&sin6;
420 fromlen = sizeof(sin6);
424 * The address of fromlen is cast to void * to shut up compiler
425 * warnings, namely on systems that have the sixth parameter
426 * prototyped as a signed int when LWRES_SOCKADDR_LEN_T is
427 * defined as unsigned.
429 ret = recvfrom(ctx->sock, recvbase, recvlen, 0, sa, (void *)&fromlen);
432 return (LWRES_R_IOERROR);
435 return (LWRES_R_TOOLARGE);
438 * If we got something other than what we expect, have the caller
439 * wait for another packet. This can happen if an old result
440 * comes in, or if someone is sending us random stuff.
442 if (ctx->address.family == LWRES_ADDRTYPE_V4) {
443 if (fromlen != sizeof(sin)
444 || memcmp(&sin.sin_addr, ctx->address.address,
445 sizeof(sin.sin_addr)) != 0
446 || sin.sin_port != htons(lwres_udp_port))
447 return (LWRES_R_RETRY);
449 if (fromlen != sizeof(sin6)
450 || memcmp(&sin6.sin6_addr, ctx->address.address,
451 sizeof(sin6.sin6_addr)) != 0
452 || sin6.sin6_port != htons(lwres_udp_port))
453 return (LWRES_R_RETRY);
456 if (recvd_len != NULL)
459 return (LWRES_R_SUCCESS);
462 /*% performs I/O for the context ctx. */
464 lwres_context_sendrecv(lwres_context_t *ctx,
465 void *sendbase, int sendlen,
466 void *recvbase, int recvlen,
469 lwres_result_t result;
472 struct timeval timeout;
475 * Type of tv_sec is 32 bits long.
477 if (ctx->timeout <= 0x7FFFFFFFU)
478 timeout.tv_sec = (int)ctx->timeout;
480 timeout.tv_sec = 0x7FFFFFFF;
484 result = lwres_context_send(ctx, sendbase, sendlen);
485 if (result != LWRES_R_SUCCESS)
489 * If this is not checked, select() can overflow,
490 * causing corruption elsewhere.
492 if (ctx->sock >= (int)FD_SETSIZE) {
495 return (LWRES_R_IOERROR);
500 FD_SET(ctx->sock, &readfds);
501 ret2 = select(ctx->sock + 1, &readfds, NULL, NULL, &timeout);
504 * What happened with select?
507 return (LWRES_R_IOERROR);
509 return (LWRES_R_TIMEOUT);
511 result = lwres_context_recv(ctx, recvbase, recvlen, recvd_len);
512 if (result == LWRES_R_RETRY)