Bug Summary

File:libsofia-sip-ua/sresolv/sres.c
Warning:line 3310, column 15
Although the value stored to 'origin' is used in the enclosing expression, the value is never actually read from 'origin'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name sres.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-11/lib/clang/11.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -I ./../url -I ../url -I ./../bnf -I ../bnf -I ./../su -I ../su -I ../../s2check -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-11/lib/clang/11.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/sresolv -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -o /drone/src/scan-build/2022-06-23-181620-12-1 -x c sres.c
1/*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2006 Nokia Corporation.
5 * Copyright (C) 2006 Dimitri E. Prado.
6 *
7 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 *
24 */
25
26/**@CFILE sres.c
27 * @brief Sofia DNS Resolver implementation.
28 *
29 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
30 * @author Teemu Jalava <Teemu.Jalava@nokia.com>
31 * @author Mikko Haataja
32 * @author Kai Vehmanen <kai.vehmanen@nokia.com>
33 * (work on the win32 nameserver discovery)
34 * @author Dimitri E. Prado
35 * (initial version of win32 nameserver discovery)
36 *
37 * @todo The resolver should allow handling arbitrary records, too.
38 */
39
40#include "config.h"
41
42#if HAVE_STDINT_H1
43#include <stdint.h>
44#elif HAVE_INTTYPES_H1
45#include <inttypes.h>
46#else
47#if defined(HAVE_WIN32)
48typedef _int8 int8_t;
49typedef unsigned _int8 uint8_t;
50typedef unsigned _int16 uint16_t;
51typedef unsigned _int32 uint32_t;
52#endif
53#endif
54
55#if HAVE_NETINET_IN_H1
56#include <sys/types.h>
57#include <sys/socket.h>
58#include <netinet/in.h>
59#endif
60
61#if HAVE_ARPA_INET_H1
62#include <arpa/inet.h>
63#endif
64
65#if HAVE_WINSOCK2_H
66#include <winsock2.h>
67#include <ws2tcpip.h>
68#ifndef IPPROTO_IPV6IPPROTO_IPV6 /* socklen_t is used with @RFC2133 API */
69typedef int socklen_t;
70#endif
71#endif
72
73#if HAVE_IPHLPAPI_H
74#include <iphlpapi.h>
75#endif
76
77#if HAVE_IP_RECVERR1 || HAVE_IPV6_RECVERR1
78#include <linux1/types.h>
79#include <linux1/errqueue.h>
80#include <sys/uio.h>
81#endif
82
83#include <time.h>
84
85#include "sofia-resolv/sres.h"
86#include "sofia-resolv/sres_cache.h"
87#include "sofia-resolv/sres_record.h"
88#include "sofia-resolv/sres_async.h"
89
90#include <sofia-sip/su_alloc.h>
91#include <sofia-sip/su_strlst.h>
92#include <sofia-sip/su_string.h>
93#include <sofia-sip/su_errno.h>
94
95#include "sofia-sip/htable.h"
96
97#include <sys/types.h>
98#include <sys/stat.h>
99#include <fcntl.h>
100#include <unistd.h>
101
102#include <stdlib.h>
103#include <stdarg.h>
104#include <stddef.h>
105#include <string.h>
106#include <stdio.h>
107#include <errno(*__errno_location ()).h>
108
109#include <limits.h>
110
111#include <assert.h>
112
113#if HAVE_WINSOCK2_H
114/* Posix send() */
115su_inlinestatic inline
116ssize_t sres_send(sres_socket_t s, void *b, size_t length, int flags)send((sres_socket_t s),(void *b),(size_t length),(int flags))
117{
118 if (length > INT_MAX2147483647)
119 length = INT_MAX2147483647;
120 return (ssize_t)send(s, b, (int)length, flags);
121}
122
123/* Posix recvfrom() */
124su_inlinestatic inline
125ssize_t sres_recvfrom(sres_socket_t s, void *buffer, size_t length, int flags,recvfrom((sres_socket_t s),(void *buffer),(size_t length),(int
flags),(struct sockaddr *from),(socklen_t *fromlen))
126 struct sockaddr *from, socklen_t *fromlen)recvfrom((sres_socket_t s),(void *buffer),(size_t length),(int
flags),(struct sockaddr *from),(socklen_t *fromlen))
127{
128 int retval, ilen = 0;
129
130 if (fromlen)
131 ilen = *fromlen;
132
133 if (length > INT_MAX2147483647)
134 length = INT_MAX2147483647;
135
136 retval = recvfrom(s, buffer, (int)length, flags,
137 (void *)from, fromlen ? &ilen : NULL((void*)0));
138
139 if (fromlen)
140 *fromlen = ilen;
141
142 return (ssize_t)retval;
143}
144
145su_inlinestatic inline
146int sres_close(sres_socket_t s)close((sres_socket_t s))
147{
148 return closesocket(s);
149}
150
151#if !defined(IPPROTO_IPV6IPPROTO_IPV6) && (_WIN32_WINNT < 0x0600)
152#if HAVE_SIN61
153#include <tpipv6.h>
154#else
155#if !defined(__MINGW32__)
156struct sockaddr_storage {
157 short ss_family;
158 char ss_pad[126];
159};
160#endif
161#endif
162#endif
163#else
164
165#define sres_send(s,b,len,flags)send((s),(b),(len),(flags)) send((s),(b),(len),(flags))
166#define sres_recvfrom(s,b,len,flags,a,alen)recvfrom((s),(b),(len),(flags),(a),(alen)) \
167 recvfrom((s),(b),(len),(flags),(a),(alen))
168#define sres_close(s)close((s)) close((s))
169#define SOCKET_ERROR(-1) (-1)
170#define INVALID_SOCKET((sres_socket_t)-1) ((sres_socket_t)-1)
171#endif
172
173#define SRES_TIME_MAX((time_t)9223372036854775807L) ((time_t)LONG_MAX9223372036854775807L)
174
175#if !HAVE_INET_PTON1
176int su_inet_ptoninet_pton(int af, char const *src, void *dst);
177#else
178#define su_inet_ptoninet_pton inet_pton
179#endif
180#if !HAVE_INET_NTOP1
181const char *su_inet_ntopinet_ntop(int af, void const *src, char *dst, size_t size);
182#else
183#define su_inet_ntopinet_ntop inet_ntop
184#endif
185
186#if defined(va_copy)
187#elif defined(__va_copy)
188#define va_copy(dst, src)__builtin_va_copy(dst, src) __va_copy((dst), (src))__builtin_va_copy((dst),(src))
189#else
190#define va_copy(dst, src)__builtin_va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))
191#endif
192
193/*
194 * 3571 is a prime =>
195 * we hash successive id values to different parts of hash tables
196 */
197#define Q_PRIME3571 3571
198#define SRES_QUERY_HASH(q)((q)->q_hash) ((q)->q_hash)
199
200/**
201 * How often to recheck nameserver information (seconds).
202 */
203#ifndef HAVE_WIN32
204#define SRES_UPDATE_INTERVAL_SECS5 5
205#else
206#define SRES_UPDATE_INTERVAL_SECS5 180
207#endif
208void sres_cache_clean(sres_cache_t *cache, time_t now);
209
210typedef struct sres_message sres_message_t;
211typedef struct sres_config sres_config_t;
212typedef struct sres_server sres_server_t;
213typedef struct sres_nameserver sres_nameserver_t;
214
215/** Default path to resolv.conf */
216static char const sres_conf_file_path[] = "/etc/resolv.conf";
217
218/** EDNS0 support. @internal */
219enum edns {
220 edns_not_tried = -1,
221 edns_not_supported = 0,
222 edns0_configured = 1,
223 edns0_supported = 2,
224};
225
226struct sres_server {
227 sres_socket_t dns_socket;
228
229 char dns_name[48]; /**< Server name */
230 struct sockaddr_storage dns_addr[1]; /**< Server node address */
231 ssize_t dns_addrlen; /**< Size of address */
232
233 enum edns dns_edns; /**< Server supports edns. */
234
235 /** ICMP/temporary error received, zero when successful. */
236 time_t dns_icmp;
237 /** Persistent error, zero when successful or timeout.
238 *
239 * Never selected if dns_error is SRES_TIME_MAX.
240 */
241 time_t dns_error;
242};
243
244HTABLE_DECLARE_WITH(sres_qtable, qt, sres_query_t, unsigned, size_t)typedef struct sres_qtable_s { unsigned qt_size; unsigned qt_used
; sres_query_t**qt_table; } sres_qtable_t
;
245
246struct sres_resolver_s {
247 su_home_t res_home[1];
248
249 void *res_userdata;
250 sres_cache_t *res_cache;
251
252 time_t res_now;
253 sres_qtable_t res_queries[1]; /**< Table of active queries */
254
255 char const *res_cnffile; /**< Configuration file name */
256 char const **res_options; /**< Option strings */
257
258 sres_config_t const *res_config;
259 time_t res_checked;
260
261 unsigned long res_updated;
262 sres_update_f *res_updcb;
263 sres_async_t *res_async;
264 sres_schedule_f *res_schedulecb;
265 short res_update_all;
266
267 uint16_t res_id;
268 short res_i_server; /**< Current server to try
269 (when doing round-robin) */
270 short res_n_servers; /**< Number of servers */
271 sres_server_t **res_servers;
272};
273
274/* Parsed configuration. @internal */
275struct sres_config {
276 su_home_t c_home[1];
277
278 time_t c_modified;
279 char const *c_filename;
280
281 /* domain and search */
282 char const *c_search[SRES_MAX_SEARCH(SRES_MAX_SEARCH) + 1];
283
284 /* nameserver */
285 struct sres_nameserver {
286 struct sockaddr_storage ns_addr[1];
287 ssize_t ns_addrlen;
288 } *c_nameservers[SRES_MAX_NAMESERVERS(SRES_MAX_NAMESERVERS) + 1];
289
290 /* sortlist */
291 struct sres_sortlist {
292 struct sockaddr_storage addr[1];
293 ssize_t addrlen;
294 char const *name;
295 } *c_sortlist[SRES_MAX_SORTLIST(SRES_MAX_SORTLIST) + 1];
296
297 uint16_t c_port; /**< Server port to use */
298
299 /* options */
300 struct sres_options {
301 uint16_t timeout;
302 uint16_t attempts;
303 uint16_t ndots;
304 enum edns edns;
305 unsigned debug:1;
306 unsigned rotate:1;
307 unsigned check_names:1;
308 unsigned inet6:1;
309 unsigned ip6int:1;
310 unsigned ip6bytestring:1;
311 } c_opt;
312};
313
314struct sres_query_s {
315 unsigned q_hash;
316 sres_resolver_t*q_res;
317 sres_answer_f *q_callback;
318 sres_context_t *q_context;
319 char *q_name;
320 time_t q_timestamp;
321 uint16_t q_type;
322 uint16_t q_class;
323 uint16_t q_id; /**< If nonzero, not answered */
324 uint16_t q_retry_count;
325 uint8_t q_n_servers;
326 uint8_t q_i_server;
327 int8_t q_edns;
328 uint8_t q_n_subs;
329 sres_query_t *q_subqueries[1 + SRES_MAX_SEARCH(SRES_MAX_SEARCH)];
330 sres_record_t **q_subanswers[1 + SRES_MAX_SEARCH(SRES_MAX_SEARCH)];
331};
332
333
334struct sres_message {
335 uint16_t m_offset;
336 uint16_t m_size;
337 char const *m_error;
338 union {
339 struct {
340 /* Header defined in RFC 1035 section 4.1.1 (page 26) */
341 uint16_t mh_id; /* Query ID */
342 uint16_t mh_flags; /* Flags */
343 uint16_t mh_qdcount; /* Question record count */
344 uint16_t mh_ancount; /* Answer record count */
345 uint16_t mh_nscount; /* Authority records count */
346 uint16_t mh_arcount; /* Additional records count */
347 } mp_header;
348 uint8_t mp_data[1500 - 40]; /**< IPv6 datagram */
349 } m_packet;
350#define m_idm_packet.mp_header.mh_id m_packet.mp_header.mh_id
351#define m_flagsm_packet.mp_header.mh_flags m_packet.mp_header.mh_flags
352#define m_qdcountm_packet.mp_header.mh_qdcount m_packet.mp_header.mh_qdcount
353#define m_ancountm_packet.mp_header.mh_ancount m_packet.mp_header.mh_ancount
354#define m_nscountm_packet.mp_header.mh_nscount m_packet.mp_header.mh_nscount
355#define m_arcountm_packet.mp_header.mh_arcount m_packet.mp_header.mh_arcount
356#define m_datam_packet.mp_data m_packet.mp_data
357};
358
359#define sr_refcountsr_record->r_refcount sr_record->r_refcount
360#define sr_namesr_record->r_name sr_record->r_name
361#define sr_statussr_record->r_status sr_record->r_status
362#define sr_sizesr_record->r_size sr_record->r_size
363#define sr_typesr_record->r_type sr_record->r_type
364#define sr_classsr_record->r_class sr_record->r_class
365#define sr_ttlsr_record->r_ttl sr_record->r_ttl
366#define sr_rdlensr_record->r_rdlen sr_record->r_rdlen
367#define sr_parsedsr_record->r_parsed sr_record->r_parsed
368#define sr_rdatasr_generic->g_data sr_generic->g_data
369
370enum {
371 SRES_HDR_QR = (1 << 15),
372 SRES_HDR_QUERY = (0 << 11),
373 SRES_HDR_IQUERY = (1 << 11),
374 SRES_HDR_STATUS = (2 << 11),
375 SRES_HDR_OPCODE = (15 << 11), /* mask */
376 SRES_HDR_AA = (1 << 10),
377 SRES_HDR_TC = (1 << 9),
378 SRES_HDR_RD = (1 << 8),
379 SRES_HDR_RA = (1 << 7),
380 SRES_HDR_RCODE = (15 << 0) /* mask of return code */
381};
382
383HTABLE_PROTOS_WITH(sres_qtable, qt, sres_query_t, unsigned, size_t)static inline int sres_qtable_resize(su_home_t *, sres_qtable_t
qt[1], unsigned); static inline int sres_qtable_is_full(sres_qtable_t
const *); static inline sres_query_t **sres_qtable_hash(sres_qtable_t
const *, size_t hv); static inline sres_query_t **sres_qtable_next
(sres_qtable_t const *, sres_query_t * const *ee); static inline
void sres_qtable_append(sres_qtable_t *qt, sres_query_t const
*e); static inline void sres_qtable_insert(sres_qtable_t *qt
, sres_query_t const *e); static inline int sres_qtable_remove
(sres_qtable_t *, sres_query_t const *e)
;
384
385#define CHOME(cache)((su_home_t *)(cache)) ((su_home_t *)(cache))
386
387/** Get address from sockaddr storage. */
388#if HAVE_SIN61
389#define SS_ADDR(ss)((ss)->ss_family == 2 ? (void *)&((struct sockaddr_in *
)ss)->sin_addr : ((ss)->ss_family == 10 ? (void *)&
((struct sockaddr_in6 *)ss)->sin6_addr : (void *)&((struct
sockaddr *)ss)->sa_data))
\
390 ((ss)->ss_family == AF_INET2 ? \
391 (void *)&((struct sockaddr_in *)ss)->sin_addr : \
392 ((ss)->ss_family == AF_INET610 ? \
393 (void *)&((struct sockaddr_in6 *)ss)->sin6_addr : \
394 (void *)&((struct sockaddr *)ss)->sa_data))
395#else
396#define SS_ADDR(ss)((ss)->ss_family == 2 ? (void *)&((struct sockaddr_in *
)ss)->sin_addr : ((ss)->ss_family == 10 ? (void *)&
((struct sockaddr_in6 *)ss)->sin6_addr : (void *)&((struct
sockaddr *)ss)->sa_data))
\
397 ((ss)->ss_family == AF_INET2 ? \
398 (void *)&((struct sockaddr_in *)ss)->sin_addr : \
399 (void *)&((struct sockaddr *)ss)->sa_data)
400#endif
401
402static int sres_config_changed_servers(sres_config_t const *new_c,
403 sres_config_t const *old_c);
404static sres_server_t **sres_servers_new(sres_resolver_t *res,
405 sres_config_t const *c);
406static sres_answer_f sres_resolving_cname;
407
408/** Generate new 16-bit identifier for DNS query. */
409static void
410sres_gen_id(sres_resolver_t *res, sres_query_t *query)
411{
412 if (res->res_id == 0) {
413 res->res_id = 1;
414 }
415 query->q_id = res->res_id++;
416 query->q_hash = query->q_id * Q_PRIME3571;
417}
418
419/** Return true if we have a search list or a local domain name. */
420static int
421sres_has_search_domain(sres_resolver_t *res)
422{
423 return res->res_config->c_search[0] != NULL((void*)0);
424}
425
426static void sres_resolver_destructor(void *);
427
428sres_resolver_t *
429sres_resolver_new_with_cache_va(char const *conf_file_path,
430 sres_cache_t *cache,
431 char const *options,
432 va_list va);
433static
434sres_resolver_t *
435sres_resolver_new_internal(sres_cache_t *cache,
436 sres_config_t const *config,
437 char const *conf_file_path,
438 char const **options);
439
440static void sres_servers_close(sres_resolver_t *res,
441 sres_server_t **servers);
442
443static int sres_servers_count(sres_server_t * const *servers);
444
445static sres_socket_t sres_server_socket(sres_resolver_t *res,
446 sres_server_t *dns);
447
448static sres_query_t * sres_query_alloc(sres_resolver_t *res,
449 sres_answer_f *callback,
450 sres_context_t *context,
451 uint16_t type,
452 char const * domain);
453
454static void sres_free_query(sres_resolver_t *res, sres_query_t *q);
455
456static
457int sres_sockaddr2string(sres_resolver_t *,
458 char name[], size_t namelen,
459 struct sockaddr const *);
460
461static
462sres_config_t *sres_parse_resolv_conf(sres_resolver_t *res,
463 char const **options);
464
465static
466sres_server_t *sres_next_server(sres_resolver_t *res,
467 uint8_t *in_out_i,
468 int always);
469
470static
471int sres_send_dns_query(sres_resolver_t *res, sres_query_t *q);
472
473static
474void sres_answer_subquery(sres_context_t *context,
475 sres_query_t *query,
476 sres_record_t **answers);
477
478static
479sres_record_t **
480sres_combine_results(sres_resolver_t *res,
481 sres_record_t **search_results[SRES_MAX_SEARCH(SRES_MAX_SEARCH) + 1]);
482
483static
484void sres_query_report_error(sres_query_t *q,
485 sres_record_t **answers);
486
487static void
488sres_resend_dns_query(sres_resolver_t *res, sres_query_t *q, int timeout);
489
490static
491sres_server_t *sres_server_by_socket(sres_resolver_t const *ts,
492 sres_socket_t socket);
493
494static
495int sres_resolver_report_error(sres_resolver_t *res,
496 sres_socket_t socket,
497 int errcode,
498 struct sockaddr_storage *remote,
499 socklen_t remotelen,
500 char const *info);
501
502static
503void sres_log_response(sres_resolver_t const *res,
504 sres_message_t const *m,
505 struct sockaddr_storage const *from,
506 sres_query_t const *query,
507 sres_record_t * const *reply);
508
509static int sres_decode_msg(sres_resolver_t *res,
510 sres_message_t *m,
511 sres_query_t **,
512 sres_record_t ***aanswers);
513
514static char const *sres_toplevel(char buf[], size_t bsize, char const *domain);
515
516static sres_record_t *sres_create_record(sres_resolver_t *,
517 sres_message_t *m,
518 int nth);
519
520static sres_record_t *sres_init_rr_soa(sres_cache_t *cache,
521 sres_soa_record_t *,
522 sres_message_t *m);
523static sres_record_t *sres_init_rr_a(sres_cache_t *cache,
524 sres_a_record_t *,
525 sres_message_t *m);
526static sres_record_t *sres_init_rr_a6(sres_cache_t *cache,
527 sres_a6_record_t *,
528 sres_message_t *m);
529static sres_record_t *sres_init_rr_aaaa(sres_cache_t *cache,
530 sres_aaaa_record_t *,
531 sres_message_t *m);
532static sres_record_t *sres_init_rr_cname(sres_cache_t *cache,
533 sres_cname_record_t *,
534 sres_message_t *m);
535static sres_record_t *sres_init_rr_ptr(sres_cache_t *cache,
536 sres_ptr_record_t *,
537 sres_message_t *m);
538static sres_record_t *sres_init_rr_srv(sres_cache_t *cache,
539 sres_srv_record_t *,
540 sres_message_t *m);
541static sres_record_t *sres_init_rr_naptr(sres_cache_t *cache,
542 sres_naptr_record_t *,
543 sres_message_t *m);
544static sres_record_t *sres_init_rr_unknown(sres_cache_t *cache,
545 sres_common_t *r,
546 sres_message_t *m);
547
548static sres_record_t *sres_create_error_rr(sres_cache_t *cache,
549 sres_query_t const *q,
550 uint16_t errcode);
551
552static void m_put_uint16(sres_message_t *m, uint16_t h);
553static void m_put_uint32(sres_message_t *m, uint32_t w);
554
555static uint16_t m_put_domain(sres_message_t *m,
556 char const *domain,
557 uint16_t top,
558 char const *topdomain);
559
560static uint32_t m_get_uint32(sres_message_t *m);
561static uint16_t m_get_uint16(sres_message_t *m);
562static uint8_t m_get_uint8(sres_message_t *m);
563
564static unsigned m_get_string(char *d, unsigned n, sres_message_t *m, uint16_t offset);
565static unsigned m_get_domain(char *d, unsigned n, sres_message_t *m, uint16_t offset);
566
567/* ---------------------------------------------------------------------- */
568
569#define SU_LOGsresolv_log sresolv_log
570
571#include <sofia-sip/su_debug.h>
572
573#ifdef HAVE_WIN32
574#include <winreg.h>
575#endif
576
577/**@ingroup sresolv_env
578 *
579 * Environment variable determining the debug log level for @b sresolv
580 * module.
581 *
582 * The SRESOLV_DEBUG environment variable is used to determine the debug
583 * logging level for @b sresolv module. The default level is 3.
584 *
585 * @sa <sofia-sip/su_debug.h>, sresolv_log, SOFIA_DEBUG
586 */
587#ifdef DOXYGEN
588extern char const SRESOLV_DEBUG[]; /* dummy declaration for Doxygen */
589#endif
590
591#ifndef SU_DEBUG0
592#define SU_DEBUG0 3
593#endif
594
595/**Debug log for @b sresolv module.
596 *
597 * The sresolv_log is the log object used by @b sresolv module. The level of
598 * #sresolv_log is set using #SRESOLV_DEBUG environment variable.
599 */
600su_log_t sresolv_log[] = { SU_LOG_INIT("sresolv", "SRESOLV_DEBUG", SU_DEBUG){ sizeof(su_log_t), "sresolv", "SRESOLV_DEBUG", 0, SU_LOG_MAX
, 0, ((void*)0), ((void*)0), }
};
601
602/** Internal errors */
603enum {
604 SRES_EDNS0_ERR = 255 /**< Server did not support EDNS. */
605};
606
607/* ---------------------------------------------------------------------- */
608
609/**Create a resolver.
610 *
611 * Allocate and initialize a new sres resolver object. The resolver object
612 * contains the parsed resolv.conf file, a cache object containing past
613 * answers from DNS, and a list of active queries. The default resolv.conf
614 * file can be overriden by giving the name of the configuration file as @a
615 * conf_file_path.
616 *
617 * @param conf_file_path name of the resolv.conf configuration file
618 *
619 * @return A pointer to a newly created sres resolver object, or NULL upon
620 * an error.
621 */
622sres_resolver_t *
623sres_resolver_new(char const *conf_file_path)
624{
625 return sres_resolver_new_internal(NULL((void*)0), NULL((void*)0), conf_file_path, NULL((void*)0));
626}
627
628/** Copy a resolver.
629 *
630 * Make a copy of resolver sharing the configuration and cache with old
631 * resolver.
632 */
633sres_resolver_t *sres_resolver_copy(sres_resolver_t *res)
634{
635 char const *cnffile;
636 sres_config_t *config;
637 sres_cache_t *cache;
638 char const **options;
639
640 if (!res)
641 return NULL((void*)0);
642
643 cnffile = res->res_cnffile;
644 config = su_home_ref(res->res_config->c_home);
645 cache = res->res_cache;
646 options = res->res_options;
647
648 return sres_resolver_new_internal(cache, config, cnffile, options);
649}
650
651/**New resolver object.
652 *
653 * Allocate and initialize a new sres resolver object. The resolver object
654 * contains the parsed resolv.conf file, a cache object containing past
655 * answers from DNS, and a list of active queries. The default resolv.conf
656 * file can be overriden by giving the name of the configuration file as @a
657 * conf_file_path.
658 *
659 * It is also possible to override the values in the resolv.conf and
660 * RES_OPTIONS by giving the directives in the NULL-terminated list.
661 *
662 * @param conf_file_path name of the resolv.conf configuration file
663 * @param cache optional pointer to a resolver cache (may be NULL)
664 * @param option, ... list of resolv.conf options directives
665 * (overriding options in conf_file)
666 *
667 * @par Environment Variables
668 * - #LOCALDOMAIN overrides @c domain or @c search directives
669 * - #RES_OPTIONS overrides values of @a options in resolv.conf
670 * - #SRES_OPTIONS overrides values of @a options in resolv.conf, #RES_OPTIONS,
671 * and @a options, ... list given as argument for this function
672 *
673 * @return A pointer to a newly created sres resolver object, or NULL upon
674 * an error.
675 */
676sres_resolver_t *
677sres_resolver_new_with_cache(char const *conf_file_path,
678 sres_cache_t *cache,
679 char const *option, ...)
680{
681 sres_resolver_t *retval;
682 va_list va;
683 va_start(va, option)__builtin_va_start(va, option);
684 retval = sres_resolver_new_with_cache_va(conf_file_path, cache, option, va);
685 va_end(va)__builtin_va_end(va);
686 return retval;
687}
688
689/**Create a resolver.
690 *
691 * Allocate and initialize a new sres resolver object.
692 *
693 * This is a stdarg version of sres_resolver_new_with_cache().
694 */
695sres_resolver_t *
696sres_resolver_new_with_cache_va(char const *conf_file_path,
697 sres_cache_t *cache,
698 char const *option,
699 va_list va)
700{
701 va_list va0;
702 size_t i;
703 char const *o, *oarray[16], **olist = oarray;
704 sres_resolver_t *res;
705
706 va_copy(va0, va)__builtin_va_copy(va0, va);
707
708 for (i = 0, o = option; o; o = va_arg(va0, char const *)__builtin_va_arg(va0, char const *)) {
709 if (i < 16)
710 olist[i] = o;
711 i++;
712 }
713
714 if (i >= 16) {
715 olist = malloc((i + 1) * sizeof *olist);
716 if (!olist)
717 return NULL((void*)0);
718 for (i = 0, o = option; o; o = va_arg(va, char const *)__builtin_va_arg(va, char const *)) {
719 olist[i++] = o;
720 i++;
721 }
722 }
723 olist[i] = NULL((void*)0);
724 res = sres_resolver_new_internal(cache, NULL((void*)0), conf_file_path, olist);
725 if (olist != oarray)
726 free(olist);
727
728 va_end(va0)__builtin_va_end(va0);
729
730 return res;
731}
732
733sres_resolver_t *
734sres_resolver_new_internal(sres_cache_t *cache,
735 sres_config_t const *config,
736 char const *conf_file_path,
737 char const **options)
738{
739 sres_resolver_t *res;
740 size_t i, n, len;
741 char **array, *o, *end;
742
743 for (n = 0, len = 0; options && options[n]; n++)
744 len += strlen(options[n]) + 1;
745
746 res = su_home_new(sizeof(*res) + (n + 1) * (sizeof *options) + len);
747
748 if (res == NULL((void*)0))
749 return NULL((void*)0);
750
751 array = (void *)(res + 1);
752 o = (void *)(array + n + 1);
753 end = o + len;
754
755 for (i = 0; options && options[i]; i++)
756 o = memccpy(array[i] = o, options[i], '\0', len - (end - o));
757 assert(o == end)((void) sizeof ((o == end) ? 1 : 0), __extension__ ({ if (o ==
end) ; else __assert_fail ("o == end", "sres.c", 757, __extension__
__PRETTY_FUNCTION__); }))
;
758
759 su_home_destructor(res->res_home, sres_resolver_destructor);
760
761 while (res->res_id == 0) {
762#if HAVE_DEV_URANDOM1
763 int fd;
764 if ((fd = open("/dev/urandom", O_RDONLY00, 0)) != -1) {
765 size_t len = read(fd, &res->res_id, (sizeof res->res_id)); (void)len;
766 close(fd);
767 }
768 else
769#endif
770 res->res_id = time(NULL((void*)0));
771 }
772
773 time(&res->res_now);
774
775 if (cache)
776 res->res_cache = sres_cache_ref(cache);
777 else
778 res->res_cache = sres_cache_new(0);
779
780 res->res_config = config;
781
782 if (conf_file_path && conf_file_path != sres_conf_file_path)
783 res->res_cnffile = su_strdup(res->res_home, conf_file_path);
784 else
785 res->res_cnffile = conf_file_path = sres_conf_file_path;
786
787 if (!res->res_cache || !res->res_cnffile) {
788 perror("sres: malloc");
789 }
790 else if (sres_qtable_resize(res->res_home, res->res_queries, 0) < 0) {
791 perror("sres: res_qtable_resize");
792 }
793 else if (sres_resolver_update(res, config == NULL((void*)0)) < 0) {
794 perror("sres: sres_resolver_update");
795 }
796 else {
797 return res;
798 }
799
800 sres_resolver_unref(res);
801
802 return NULL((void*)0);
803}
804
805/** Increase reference count on a resolver object. */
806sres_resolver_t *
807sres_resolver_ref(sres_resolver_t *res)
808{
809 return su_home_ref(res->res_home);
810}
811
812/** Decrease the reference count on a resolver object. */
813void
814sres_resolver_unref(sres_resolver_t *res)
815{
816 su_home_unref(res->res_home);
817}
818
819/** Set userdata pointer.
820 *
821 * @return New userdata pointer.
822 *
823 * @ERRORS
824 * @ERROR EFAULT @a res points outside the address space
825 */
826void *
827sres_resolver_set_userdata(sres_resolver_t *res,
828 void *userdata)
829{
830 void *old;
831
832 if (!res)
833 return su_seterrno(EFAULT14), (void *)NULL((void*)0);
834
835 old = res->res_userdata, res->res_userdata = userdata;
836
837 return old;
838}
839
840/**Get userdata pointer.
841 *
842 * @return Userdata pointer.
843 *
844 * @ERRORS
845 * @ERROR EFAULT @a res points outside the address space
846 */
847void *
848sres_resolver_get_userdata(sres_resolver_t const *res)
849{
850 if (res == NULL((void*)0))
851 return su_seterrno(EFAULT14), (void *)NULL((void*)0);
852 else
853 return res->res_userdata;
854}
855
856/** Set async object.
857 *
858 * @return Set async object.
859 *
860 * @ERRORS
861 * @ERROR EFAULT @a res points outside the address space
862 * @ERROR EALREADY different async callback already set
863 */
864sres_async_t *
865sres_resolver_set_async(sres_resolver_t *res,
866 sres_update_f *callback,
867 sres_async_t *async,
868 int update_all)
869{
870 if (!res)
871 return su_seterrno(EFAULT14), (void *)NULL((void*)0);
872
873 if (res->res_updcb && res->res_updcb != callback)
874 return su_seterrno(EALREADY114), (void *)NULL((void*)0);
875
876 res->res_async = async;
877 res->res_updcb = callback;
878 res->res_update_all = callback && update_all != 0;
879
880 return async;
881}
882
883/** Get async object */
884sres_async_t *
885sres_resolver_get_async(sres_resolver_t const *res,
886 sres_update_f *callback)
887{
888 if (res == NULL((void*)0))
889 return su_seterrno(EFAULT14), (void *)NULL((void*)0);
890 else if (callback == NULL((void*)0))
891 return res->res_async ? (sres_async_t *)-1 : 0;
892 else if (res->res_updcb != callback)
893 return NULL((void*)0);
894 else
895 return res->res_async;
896}
897
898/** Register resolver timer callback. */
899int sres_resolver_set_timer_cb(sres_resolver_t *res,
900 sres_schedule_f *callback,
901 sres_async_t *async)
902{
903 if (res == NULL((void*)0))
904 return su_seterrno(EFAULT14);
905 if (res->res_async != async)
906 return su_seterrno(EALREADY114);
907
908 res->res_schedulecb = callback;
909 return 0;
910}
911
912/**Send a DNS query.
913 *
914 * Sends a DNS query with specified @a type and @a domain to the DNS server.
915 * When an answer is received, the @a callback function is called with
916 * @a context and returned records as arguments.
917 *
918 * The sres resolver takes care of retransmitting the query if a root object
919 * is associate with the resolver or if sres_resolver_timer() is called in
920 * regular intervals. It generates an error record with nonzero status if no
921 * response is received.
922 *
923 * @param res pointer to resolver
924 * @param callback function called when query is answered or times out
925 * @param context pointer given as an extra argument to @a callback function
926 * @param type record type to query (see #sres_qtypes)
927 * @param domain name to query
928 *
929 * Query types also indicate the record type of the result.
930 * Any record can be queried with #sres_qtype_any.
931 * Well-known query types understood and decoded by @b sres include
932 * #sres_type_a,
933 * #sres_type_aaaa,
934 * #sres_type_cname,
935 * #sres_type_ptr
936 * #sres_type_soa,
937 * #sres_type_aaaa,
938 * #sres_type_srv, and
939 * #sres_type_naptr.
940 *
941 * Deprecated query type #sres_type_a6 is also decoded.
942 *
943 * @note The domain name is @b not concatenated with the domains from seach
944 * path or with the local domain. Use sres_search() in order to try domains
945 * in search path.
946 *
947 * @sa sres_search(), sres_blocking_query(), sres_cached_answers(),
948 * sres_query_sockaddr()
949 *
950 * @ERRORS
951 * @ERROR EFAULT @a res or @a domain point outside the address space
952 * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
953 * @ERROR ENETDOWN no DNS servers configured
954 * @ERROR ENOMEM memory exhausted
955 */
956sres_query_t *
957sres_query(sres_resolver_t *res,
958 sres_answer_f *callback,
959 sres_context_t *context,
960 uint16_t type,
961 char const *domain)
962{
963 sres_query_t *query = NULL((void*)0);
964 size_t dlen;
965
966 char b[8];
967 SU_DEBUG_9(("sres_query(%p, %p, %s, \"%s\") called\n",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 968, "sres_query(%p, %p, %s, \"%s\") called\n"
, (void *)res, (void *)context, sres_record_type(type, b), domain
)) : (void)0)
968 (void *)res, (void *)context, sres_record_type(type, b), domain))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 968, "sres_query(%p, %p, %s, \"%s\") called\n"
, (void *)res, (void *)context, sres_record_type(type, b), domain
)) : (void)0)
;
969
970 if (res == NULL((void*)0) || domain == NULL((void*)0))
971 return su_seterrno(EFAULT14), (void *)NULL((void*)0);
972
973 dlen = strlen(domain);
974 if (dlen > SRES_MAXDNAME(SRES_MAXDNAME) ||
975 (dlen == SRES_MAXDNAME(SRES_MAXDNAME) && domain[dlen - 1] != '.')) {
976 su_seterrno(ENAMETOOLONG36);
977 return NULL((void*)0);
978 }
979
980 /* Reread resolv.conf if needed */
981 sres_resolver_update(res, 0);
982
983 if (res->res_n_servers == 0)
984 return (void)su_seterrno(ENETDOWN100), (sres_query_t *)NULL((void*)0);
985
986 query = sres_query_alloc(res, callback, context, type, domain);
987
988 if (query && sres_send_dns_query(res, query) != 0)
989 sres_free_query(res, query), query = NULL((void*)0);
990
991 return query;
992}
993
994/**Search DNS.
995 *
996 * Sends DNS queries with specified @a type and @a name to the DNS server.
997 * If the @a name does not contain enought dots, the search domains are
998 * appended to the name and resulting domain name are also queried. When
999 * answer to all the search domains is received, the @a callback function
1000 * is called with @a context and combined records from answers as arguments.
1001 *
1002 * The sres resolver takes care of retransmitting the queries if a root
1003 * object is associate with the resolver or if sres_resolver_timer() is
1004 * called in regular intervals. It generates an error record with nonzero
1005 * status if no response is received.
1006 *
1007 * @param res pointer to resolver object
1008 * @param callback pointer to completion function
1009 * @param context argument given to the completion function
1010 * @param type record type to search (or sres_qtype_any for any record)
1011 * @param name host or domain name to search from DNS
1012 *
1013 * @ERRORS
1014 * @ERROR EFAULT @a res or @a domain point outside the address space
1015 * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
1016 * @ERROR ENETDOWN no DNS servers configured
1017 * @ERROR ENOMEM memory exhausted
1018 *
1019 * @sa sres_query(), sres_blocking_search(), sres_search_cached_answers().
1020 */
1021sres_query_t *
1022sres_search(sres_resolver_t *res,
1023 sres_answer_f *callback,
1024 sres_context_t *context,
1025 uint16_t type,
1026 char const *name)
1027{
1028 char const *domain = name;
1029 sres_query_t *query = NULL((void*)0);
1030 size_t dlen;
1031 unsigned dots; char const *dot;
1032 char b[8];
1033
1034 SU_DEBUG_9(("sres_search(%p, %p, %s, \"%s\") called\n",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 1035, "sres_search(%p, %p, %s, \"%s\") called\n"
, (void *)res, (void *)context, sres_record_type(type, b), domain
)) : (void)0)
1035 (void *)res, (void *)context, sres_record_type(type, b), domain))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 1035, "sres_search(%p, %p, %s, \"%s\") called\n"
, (void *)res, (void *)context, sres_record_type(type, b), domain
)) : (void)0)
;
1036
1037 if (res == NULL((void*)0) || domain == NULL((void*)0))
1038 return su_seterrno(EFAULT14), (void *)NULL((void*)0);
1039
1040 dlen = strlen(domain);
1041 if (dlen > SRES_MAXDNAME(SRES_MAXDNAME) ||
1042 (dlen == SRES_MAXDNAME(SRES_MAXDNAME) && domain[dlen - 1] != '.')) {
1043 su_seterrno(ENAMETOOLONG36);
1044 return NULL((void*)0);
1045 }
1046
1047 sres_resolver_update(res, 0);
1048
1049 if (res->res_n_servers == 0)
1050 return (void)su_seterrno(ENETDOWN100), (sres_query_t *)NULL((void*)0);
1051
1052 if (domain[dlen - 1] == '.')
1053 /* Domain ends with dot - do not search */
1054 dots = res->res_config->c_opt.ndots;
1055 else if (sres_has_search_domain(res))
1056 for (dots = 0, dot = strchr(domain, '.');
1057 dots < res->res_config->c_opt.ndots && dot;
1058 dots++, dot = strchr(dot + 1, '.'))
1059 ;
1060 else
1061 dots = 0;
1062
1063 query = sres_query_alloc(res, callback, context, type, domain);
1064
1065 if (query) {
1066 /* Create sub-query for each search domain */
1067 if (dots < res->res_config->c_opt.ndots) {
1068 sres_query_t *sub;
1069 int i, subs;
1070 size_t len;
1071 char const *const *domains = res->res_config->c_search;
1072 char search[SRES_MAXDNAME(SRES_MAXDNAME) + 1];
1073
1074 assert(dlen < SRES_MAXDNAME)((void) sizeof ((dlen < (SRES_MAXDNAME)) ? 1 : 0), __extension__
({ if (dlen < (SRES_MAXDNAME)) ; else __assert_fail ("dlen < SRES_MAXDNAME"
, "sres.c", 1074, __extension__ __PRETTY_FUNCTION__); }))
;
1075
1076 memcpy(search, domain, dlen);
1077 search[dlen++] = '.';
1078 search[dlen] = '\0';
1079
1080 for (i = 0, subs = 0; i <= SRES_MAX_SEARCH(SRES_MAX_SEARCH); i++) {
1081 if (domains[i]) {
1082 len = strlen(domains[i]);
1083
1084 if (dlen + len + 1 > SRES_MAXDNAME(SRES_MAXDNAME))
1085 continue;
1086
1087 memcpy(search + dlen, domains[i], len);
1088 search[dlen + len] = '.';
1089 search[dlen + len + 1] = '\0';
1090 sub = sres_query_alloc(res, sres_answer_subquery, (void *)query,
1091 type, search);
1092
1093 if (sub == NULL((void*)0)) {
1094 }
1095 else if (sres_send_dns_query(res, sub) == 0) {
1096 query->q_subqueries[i] = sub;
1097 }
1098 else {
1099 sres_free_query(res, sub), sub = NULL((void*)0);
1100 }
1101 subs += sub != NULL((void*)0);
1102 }
1103 }
1104
1105 query->q_n_subs = subs;
1106 }
1107
1108 if (sres_send_dns_query(res, query) != 0) {
1109 if (!query->q_n_subs)
1110 sres_free_query(res, query), query = NULL((void*)0);
1111 else
1112 query->q_id = 0;
1113 }
1114 }
1115
1116 return query;
1117}
1118
1119/** Make a reverse DNS query.
1120 *
1121 * Send a query to DNS server with specified @a type and domain name formed
1122 * from the socket address @a addr. The sres resolver takes care of
1123 * retransmitting the query if a root object is associate with the resolver or
1124 * if sres_resolver_timer() is called in regular intervals. It generates an
1125 * error record with nonzero status if no response is received.
1126 *
1127 * @param res pointer to resolver
1128 * @param callback function called when query is answered or times out
1129 * @param context pointer given as an extra argument to @a callback function
1130 * @param type record type to query (or sres_qtype_any for any record)
1131 * @param addr socket address structure
1132 *
1133 * The @a type should be #sres_type_ptr. The @a addr should contain either
1134 * IPv4 (AF_INET) or IPv6 (AF_INET6) address.
1135 *
1136 * If the #SRES_OPTIONS environment variable, #RES_OPTIONS environment
1137 * variable, or an "options" entry in resolv.conf file contains an option
1138 * "ip6-dotint", the IPv6 addresses are resolved using suffix ".ip6.int"
1139 * instead of the standard ".ip6.arpa" suffix.
1140 *
1141 * @ERRORS
1142 * @ERROR EAFNOSUPPORT address family specified in @a addr is not supported
1143 * @ERROR ENETDOWN no DNS servers configured
1144 * @ERROR EFAULT @a res or @a addr point outside the address space
1145 * @ERROR ENOMEM memory exhausted
1146 *
1147 * @sa sres_query(), sres_blocking_query_sockaddr(),
1148 * sres_cached_answers_sockaddr()
1149 *
1150 */
1151sres_query_t *
1152sres_query_sockaddr(sres_resolver_t *res,
1153 sres_answer_f *callback,
1154 sres_context_t *context,
1155 uint16_t type,
1156 struct sockaddr const *addr)
1157{
1158 char name[80];
1159
1160 if (!res || !addr)
1161 return su_seterrno(EFAULT14), (void *)NULL((void*)0);
1162
1163 if (!sres_sockaddr2string(res, name, sizeof(name), addr))
1164 return NULL((void*)0);
1165
1166 return sres_query(res, callback, context, type, name);
1167}
1168
1169
1170/** Make a DNS query.
1171 *
1172 * @deprecated Use sres_query() instead.
1173 */
1174sres_query_t *
1175sres_query_make(sres_resolver_t *res,
1176 sres_answer_f *callback,
1177 sres_context_t *context,
1178 int dummy,
1179 uint16_t type,
1180 char const *domain)
1181{
1182 return sres_query(res, callback, context, type, domain);
1183}
1184
1185/** Make a reverse DNS query.
1186 *
1187 * @deprecated Use sres_query_sockaddr() instead.
1188 */
1189sres_query_t *
1190sres_query_make_sockaddr(sres_resolver_t *res,
1191 sres_answer_f *callback,
1192 sres_context_t *context,
1193 int dummy,
1194 uint16_t type,
1195 struct sockaddr const *addr)
1196{
1197 char name[80];
1198
1199 if (!res || !addr)
1200 return su_seterrno(EFAULT14), (void *)NULL((void*)0);
1201
1202 if (!sres_sockaddr2string(res, name, sizeof(name), addr))
1203 return NULL((void*)0);
1204
1205 return sres_query_make(res, callback, context, dummy, type, name);
1206}
1207
1208
1209/** Bind a query with another callback and context pointer.
1210 *
1211 * @param query pointer to a query object to bind
1212 * @param callback pointer to new callback function (may be NULL)
1213 * @param context pointer to callback context (may be NULL)
1214*/
1215void sres_query_bind(sres_query_t *query,
1216 sres_answer_f *callback,
1217 sres_context_t *context)
1218{
1219 if (query) {
1220 query->q_callback = callback;
1221 query->q_context = context;
1222 }
1223}
1224
1225/**Get a list of matching (type/domain) records from cache.
1226 *
1227 * @return
1228 * pointer to an array of pointers to cached records, or
1229 * NULL if no entry was found.
1230 *
1231 * @ERRORS
1232 * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME
1233 * @ERROR ENOENT no cached records were found
1234 * @ERROR EFAULT @a res or @a domain point outside the address space
1235 * @ERROR ENOMEM memory exhausted
1236 */
1237sres_record_t **
1238sres_cached_answers(sres_resolver_t *res,
1239 uint16_t type,
1240 char const *domain)
1241{
1242 sres_record_t **result;
1243 char rooted_domain[SRES_MAXDNAME(SRES_MAXDNAME)];
1244
1245 if (!res)
1246 return su_seterrno(EFAULT14), (void *)NULL((void*)0);
1247
1248 domain = sres_toplevel(rooted_domain, sizeof rooted_domain, domain);
1249
1250 if (!domain)
1251 return NULL((void*)0);
1252
1253 if (!sres_cache_get(res->res_cache, type, domain, &result))
1254 return su_seterrno(ENOENT2), (void *)NULL((void*)0);
1255
1256 return result;
1257}
1258
1259/**Search for a list of matching (type/name) records from cache.
1260 *
1261 * @return
1262 * pointer to an array of pointers to cached records, or
1263 * NULL if no entry was found.
1264 *
1265 * @ERRORS
1266 * @ERROR ENAMETOOLONG @a name or resulting domain is longer than SRES_MAXDNAME
1267 * @ERROR ENOENT no cached records were found
1268 * @ERROR EFAULT @a res or @a domain point outside the address space
1269 * @ERROR ENOMEM memory exhausted
1270 *
1271 * @sa sres_search(), sres_cached_answers()
1272 */
1273sres_record_t **
1274sres_search_cached_answers(sres_resolver_t *res,
1275 uint16_t type,
1276 char const *name)
1277{
1278 char const *domain = name;
1279 sres_record_t **search_results[SRES_MAX_SEARCH(SRES_MAX_SEARCH) + 1] = { NULL((void*)0) };
1280 char rooted_domain[SRES_MAXDNAME(SRES_MAXDNAME)];
1281 unsigned dots; char const *dot;
1282 size_t found = 0;
1283 int i;
1284
1285 SU_DEBUG_9(("sres_search_cached_answers(%p, %s, \"%s\") called\n",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 1286, "sres_search_cached_answers(%p, %s, \"%s\") called\n"
, (void *)res, sres_record_type(type, rooted_domain), domain)
) : (void)0)
1286 (void *)res, sres_record_type(type, rooted_domain), domain))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 1286, "sres_search_cached_answers(%p, %s, \"%s\") called\n"
, (void *)res, sres_record_type(type, rooted_domain), domain)
) : (void)0)
;
1287
1288 if (!res || !name)
1289 return su_seterrno(EFAULT14), (void *)NULL((void*)0);
1290
1291 if (sres_has_search_domain(res))
1292 for (dots = 0, dot = strchr(domain, '.');
1293 dots < res->res_config->c_opt.ndots && dot;
1294 dots++, dot = strchr(dot + 1, '.'))
1295 ;
1296 else
1297 dots = 0;
1298
1299 domain = sres_toplevel(rooted_domain, sizeof rooted_domain, domain);
1300
1301 if (!domain)
1302 return NULL((void*)0);
1303
1304 if (sres_cache_get(res->res_cache, type, domain, &search_results[0]))
1305 found = 1;
1306
1307 if (dots < res->res_config->c_opt.ndots) {
1308 char const *const *domains = res->res_config->c_search;
1309 size_t dlen = strlen(domain);
1310
1311 for (i = 0; domains[i] && i < SRES_MAX_SEARCH(SRES_MAX_SEARCH); i++) {
1312 size_t len = strlen(domains[i]);
1313 if (dlen + len + 1 >= SRES_MAXDNAME(SRES_MAXDNAME))
1314 continue;
1315 if (domain != rooted_domain)
1316 domain = memcpy(rooted_domain, domain, dlen);
1317 memcpy(rooted_domain + dlen, domains[i], len);
1318 strcpy(rooted_domain + dlen + len, ".");
1319 if (sres_cache_get(res->res_cache, type, domain, search_results + i + 1))
1320 found++;
1321 }
1322 }
1323
1324 if (found == 0)
1325 return su_seterrno(ENOENT2), (void *)NULL((void*)0);
1326
1327 if (found == 1) {
1328 for (i = 0; i <= SRES_MAX_SEARCH(SRES_MAX_SEARCH); i++)
1329 if (search_results[i])
1330 return search_results[i];
1331 }
1332
1333 return sres_combine_results(res, search_results);
1334}
1335
1336/**Get a list of matching (type/domain) reverse records from cache.
1337 *
1338 * @param res pointer to resolver
1339 * @param type record type to query (or sres_qtype_any for any record)
1340 * @param addr socket address structure
1341 *
1342 * The @a type should be #sres_type_ptr. The @a addr should contain either
1343 * IPv4 (AF_INET) or IPv6 (AF_INET6) address.
1344 *
1345 * If the #SRES_OPTIONS environment variable, #RES_OPTIONS environment
1346 * variable or an "options" entry in resolv.conf file contains an option
1347 * "ip6-dotint", the IPv6 addresses are resolved using suffix ".ip6.int"
1348 * instead of default ".ip6.arpa".
1349 *
1350 * @retval
1351 * pointer to an array of pointers to cached records, or
1352 * NULL if no entry was found.
1353 *
1354 * @ERRORS
1355 * @ERROR EAFNOSUPPORT address family specified in @a addr is not supported
1356 * @ERROR ENOENT no cached records were found
1357 * @ERROR EFAULT @a res or @a addr point outside the address space
1358 * @ERROR ENOMEM memory exhausted
1359 */
1360sres_record_t **
1361sres_cached_answers_sockaddr(sres_resolver_t *res,
1362 uint16_t type,
1363 struct sockaddr const *addr)
1364{
1365 sres_record_t **result;
1366 char name[80];
1367
1368 if (!res || !addr)
1369 return su_seterrno(EFAULT14), (void *)NULL((void*)0);
1370
1371 if (!sres_sockaddr2string(res, name, sizeof name, addr))
1372 return NULL((void*)0);
1373
1374 if (!sres_cache_get(res->res_cache, type, name, &result))
1375 return su_seterrno(ENOENT2), (void *)NULL((void*)0);
1376
1377 return result;
1378}
1379
1380/** Set the priority of the matching cached SRV record.
1381 *
1382 * The SRV records with the domain name, target and port are matched and
1383 * their priority value is adjusted. This function is used to implement
1384 * greylisting of SIP servers.
1385 *
1386 * @param res pointer to resolver
1387 * @param domain domain name of the SRV record(s) to modify
1388 * @param target SRV target of the SRV record(s) to modify
1389 * @param port port number of SRV record(s) to modify
1390 * (in host byte order)
1391 * @param ttl new ttl for SRV records of the domain
1392 * @param priority new priority value (0=highest, 65535=lowest)
1393 *
1394 * @sa sres_cache_set_srv_priority()
1395 *
1396 * @NEW_1_12_8
1397 */
1398int sres_set_cached_srv_priority(sres_resolver_t *res,
1399 char const *domain,
1400 char const *target,
1401 uint16_t port,
1402 uint32_t ttl,
1403 uint16_t priority)
1404{
1405 char rooted_domain[SRES_MAXDNAME(SRES_MAXDNAME)];
1406
1407 if (res == NULL((void*)0) || res->res_cache == NULL((void*)0))
1408 return su_seterrno(EFAULT14);
1409
1410 domain = sres_toplevel(rooted_domain, sizeof rooted_domain, domain);
1411
1412 if (!domain)
1413 return -1;
1414
1415 return sres_cache_set_srv_priority(res->res_cache,
1416 domain, target, port,
1417 ttl, priority);
1418}
1419
1420
1421/** Sort answers. */
1422int
1423sres_sort_answers(sres_resolver_t *res, sres_record_t **answers)
1424{
1425 int i, j;
1426
1427 if (res == NULL((void*)0) || answers == NULL((void*)0))
1428 return su_seterrno(EFAULT14);
1429
1430 if (answers[0] == NULL((void*)0) || answers[1] == NULL((void*)0))
1431 return 0;
1432
1433 /* Simple insertion sorting */
1434 /*
1435 * We do not use qsort because we want later extend this to sort
1436 * local A records first etc.
1437 */
1438 for (i = 1; answers[i]; i++) {
1439 for (j = 0; j < i; j++) {
1440 if (sres_record_compare(answers[i], answers[j]) < 0)
1441 break;
1442 }
1443 if (j < i) {
1444 sres_record_t *r = answers[i];
1445 for (; j < i; i--) {
1446 answers[i] = answers[i - 1];
1447 }
1448 answers[j] = r;
1449 }
1450 }
1451
1452 return 0;
1453}
1454
1455/** Sort and filter query results */
1456int
1457sres_filter_answers(sres_resolver_t *res,
1458 sres_record_t **answers,
1459 uint16_t type)
1460{
1461 int i, n;
1462
1463 if (res == NULL((void*)0) || answers == NULL((void*)0))
1464 return su_seterrno(EFAULT14);
1465
1466 for (n = 0, i = 0; answers[i]; i++) {
1467 if (answers[i]->sr_record->r_status ||
1468 answers[i]->sr_record->r_class != sres_class_in ||
1469 (type != 0 && answers[i]->sr_record->r_type != type)) {
1470 sres_free_answer(res, answers[i]);
1471 continue;
1472 }
1473 answers[n++] = answers[i];
1474 }
1475 answers[n] = NULL((void*)0);
1476
1477 sres_sort_answers(res, answers);
1478
1479 return n;
1480}
1481
1482
1483/** Free and zero one record. */
1484void sres_free_answer(sres_resolver_t *res, sres_record_t *answer)
1485{
1486 if (res && answer)
1487 sres_cache_free_one(res->res_cache, answer);
1488}
1489
1490/** Free and zero an array of records.
1491 *
1492 * The array of records can be returned by sres_cached_answers() or
1493 * given by callback function.
1494 */
1495void
1496sres_free_answers(sres_resolver_t *res,
1497 sres_record_t **answers)
1498{
1499 if (res && answers)
1500 sres_cache_free_answers(res->res_cache, answers);
1501}
1502
1503/** Convert type to its name. */
1504char const *sres_record_type(int type, char buffer[8])
1505{
1506 switch (type) {
1507 case sres_type_a: return "A";
1508 case sres_type_ns: return "NS";
1509 case sres_type_mf: return "MF";
1510 case sres_type_cname: return "CNAME";
1511 case sres_type_soa: return "SOA";
1512 case sres_type_mb: return "MB";
1513 case sres_type_mg: return "MG";
1514 case sres_type_mr: return "MR";
1515 case sres_type_null: return "NULL";
1516 case sres_type_wks: return "WKS";
1517 case sres_type_ptr: return "PTR";
1518 case sres_type_hinfo: return "HINFO";
1519 case sres_type_minfo: return "MINFO";
1520 case sres_type_mx: return "MX";
1521 case sres_type_txt: return "TXT";
1522 case sres_type_rp: return "RP";
1523 case sres_type_afsdb: return "AFSDB";
1524 case sres_type_x25: return "X25";
1525 case sres_type_isdn: return "ISDN";
1526 case sres_type_rt: return "RT";
1527 case sres_type_nsap: return "NSAP";
1528 case sres_type_nsap_ptr: return "NSAP_PTR";
1529 case sres_type_sig: return "SIG";
1530 case sres_type_key: return "KEY";
1531 case sres_type_px: return "PX";
1532 case sres_type_gpos: return "GPOS";
1533 case sres_type_aaaa: return "AAAA";
1534 case sres_type_loc: return "LOC";
1535 case sres_type_nxt: return "NXT";
1536 case sres_type_eid: return "EID";
1537 case sres_type_nimloc: return "NIMLOC";
1538 case sres_type_srv: return "SRV";
1539 case sres_type_atma: return "ATMA";
1540 case sres_type_naptr: return "NAPTR";
1541 case sres_type_kx: return "KX";
1542 case sres_type_cert: return "CERT";
1543 case sres_type_a6: return "A6";
1544 case sres_type_dname: return "DNAME";
1545 case sres_type_sink: return "SINK";
1546 case sres_type_opt: return "OPT";
1547
1548 case sres_qtype_tsig: return "TSIG";
1549 case sres_qtype_ixfr: return "IXFR";
1550 case sres_qtype_axfr: return "AXFR";
1551 case sres_qtype_mailb: return "MAILB";
1552 case sres_qtype_maila: return "MAILA";
1553 case sres_qtype_any: return "ANY";
1554
1555 default:
1556 if (buffer)
1557 sprintf(buffer, "%u?", type & 65535);
1558 return buffer;
1559 }
1560}
1561
1562/** Convert record status to its name */
1563char const *sres_record_status(int status, char buffer[8])
1564{
1565 switch (status) {
1566 case SRES_OK: return "OK";
1567 case SRES_FORMAT_ERR: return "FORMAT_ERR";
1568 case SRES_SERVER_ERR: return "SERVER_ERR";
1569 case SRES_NAME_ERR: return "NAME_ERR";
1570 case SRES_UNIMPL_ERR: return "UNIMPL_ERR";
1571 case SRES_AUTH_ERR: return "AUTH_ERR";
1572
1573 /* Errors generated by sresolv */
1574 case SRES_TIMEOUT_ERR: return "TIMEOUT_ERR";
1575 case SRES_RECORD_ERR: return "RECORD_ERR";
1576 case SRES_INTERNAL_ERR: return "INTERNAL_ERR";
1577 case SRES_NETWORK_ERR: return "NETWORK_ERR";
1578
1579 default:
1580 if (buffer)
1581 sprintf(buffer, "%u?", status & 255);
1582 return buffer;
1583 }
1584}
1585
1586
1587/** Convert class to its name. */
1588static char const *
1589sres_record_class(int rclass, char buffer[8])
1590{
1591 switch (rclass) {
1592 case 1: return "IN";
1593 case 2: return "2?";
1594 case 3: return "CHAOS";
1595 case 4: return "HS";
1596 case 254: return "NONE";
1597 case 255: return "ANY";
1598
1599 default:
1600 sprintf(buffer, "%u?", rclass & 65535);
1601 return buffer;
1602 }
1603}
1604
1605/** Compare two records. */
1606int
1607sres_record_compare(sres_record_t const *aa, sres_record_t const *bb)
1608{
1609 int D;
1610 sres_common_t const *a = aa->sr_record, *b = bb->sr_record;
1611
1612 D = a->r_status - b->r_status; if (D) return D;
1613 D = a->r_class - b->r_class; if (D) return D;
1614 D = a->r_type - b->r_type; if (D) return D;
1615
1616 if (a->r_status)
1617 return 0;
1618
1619 switch (a->r_type) {
1620 case sres_type_soa:
1621 {
1622 sres_soa_record_t const *A = aa->sr_soa, *B = bb->sr_soa;
1623 D = A->soa_serial - B->soa_serial; if (D) return D;
1624 D = su_strcasecmp(A->soa_mname, B->soa_mname); if (D) return D;
1625 D = su_strcasecmp(A->soa_rname, B->soa_rname); if (D) return D;
1626 D = A->soa_refresh - B->soa_refresh; if (D) return D;
1627 D = A->soa_retry - B->soa_retry; if (D) return D;
1628 D = A->soa_expire - B->soa_expire; if (D) return D;
1629 D = A->soa_minimum - B->soa_minimum; if (D) return D;
1630 return 0;
1631 }
1632 case sres_type_a:
1633 {
1634 sres_a_record_t const *A = aa->sr_a, *B = bb->sr_a;
1635 return memcmp(&A->a_addr, &B->a_addr, sizeof A->a_addr);
1636 }
1637 case sres_type_a6:
1638 {
1639 sres_a6_record_t const *A = aa->sr_a6, *B = bb->sr_a6;
1640 D = A->a6_prelen - B->a6_prelen; if (D) return D;
1641 D = !A->a6_prename - !B->a6_prename;
1642 if (D == 0 && A->a6_prename && B->a6_prename)
1643 D = su_strcasecmp(A->a6_prename, B->a6_prename);
1644 if (D) return D;
1645 return memcmp(&A->a6_suffix, &B->a6_suffix, sizeof A->a6_suffix);
1646 }
1647 case sres_type_aaaa:
1648 {
1649 sres_aaaa_record_t const *A = aa->sr_aaaa, *B = bb->sr_aaaa;
1650 return memcmp(&A->aaaa_addr, &B->aaaa_addr, sizeof A->aaaa_addr);
1651 }
1652 case sres_type_cname:
1653 {
1654 sres_cname_record_t const *A = aa->sr_cname, *B = bb->sr_cname;
1655 return strcmp(A->cn_cname, B->cn_cname);
1656 }
1657 case sres_type_ptr:
1658 {
1659 sres_ptr_record_t const *A = aa->sr_ptr, *B = bb->sr_ptr;
1660 return strcmp(A->ptr_domain, B->ptr_domain);
1661 }
1662 case sres_type_srv:
1663 {
1664 sres_srv_record_t const *A = aa->sr_srv, *B = bb->sr_srv;
1665 D = A->srv_priority - B->srv_priority; if (D) return D;
1666 /* Record with larger weight first */
1667 D = B->srv_weight - A->srv_weight; if (D) return D;
1668 D = strcmp(A->srv_target, B->srv_target); if (D) return D;
1669 return A->srv_port - B->srv_port;
1670 }
1671 case sres_type_naptr:
1672 {
1673 sres_naptr_record_t const *A = aa->sr_naptr, *B = bb->sr_naptr;
1674 D = A->na_order - B->na_order; if (D) return D;
1675 D = A->na_prefer - B->na_prefer; if (D) return D;
1676 D = strcmp(A->na_flags, B->na_flags); if (D) return D;
1677 D = strcmp(A->na_services, B->na_services); if (D) return D;
1678 D = strcmp(A->na_regexp, B->na_regexp); if (D) return D;
1679 return strcmp(A->na_replace, B->na_replace);
1680 }
1681 default:
1682 return 0;
1683 }
1684}
1685
1686/* ---------------------------------------------------------------------- */
1687/* Private functions */
1688
1689/** Destruct */
1690static
1691void
1692sres_resolver_destructor(void *arg)
1693{
1694 sres_resolver_t *res = arg;
1695
1696 assert(res)((void) sizeof ((res) ? 1 : 0), __extension__ ({ if (res) ; else
__assert_fail ("res", "sres.c", 1696, __extension__ __PRETTY_FUNCTION__
); }))
;
1697 sres_cache_unref(res->res_cache);
1698 res->res_cache = NULL((void*)0);
1699
1700 sres_servers_close(res, res->res_servers);
1701
1702 if (res->res_config)
1703 su_home_unref((su_home_t *)res->res_config->c_home);
1704
1705 if (res->res_updcb)
1706 res->res_updcb(res->res_async, INVALID_SOCKET((sres_socket_t)-1), INVALID_SOCKET((sres_socket_t)-1));
1707}
1708
1709#ifdef __clang__1
1710#pragma clang diagnostic push
1711#pragma clang diagnostic ignored "-Wunused-function"
1712#endif
1713
1714HTABLE_BODIES_WITH(sres_qtable, qt, sres_query_t, SRES_QUERY_HASH,static inline int sres_qtable_resize(su_home_t *home, sres_qtable_t
qt[], unsigned new_size) { sres_query_t **new_hash; sres_query_t
**old_hash = qt->qt_table; unsigned old_size; unsigned i,
j, i0; unsigned again = 0; unsigned used = 0, collisions = 0
; if (new_size == 0) new_size = 2 * qt->qt_size + 1; if (new_size
< 31) new_size = 31; if (new_size < 5 * qt->qt_used
/ 4) new_size = 5 * qt->qt_used / 4; if (!(new_hash = su_zalloc
(home, sizeof(*new_hash) * new_size))) return -1; old_size = qt
->qt_size; do for (j = 0; j < old_size; j++) { if (!old_hash
[j]) continue; if (again < 2 && ((old_hash[j])->
q_hash) % old_size > j) { again = 1; continue; } i0 = ((old_hash
[j])->q_hash) % new_size; for (i = i0; new_hash[i]; i = (i
+ 1) % new_size, ((void) sizeof ((i != i0) ? 1 : 0), __extension__
({ if (i != i0) ; else __assert_fail ("i != i0", "sres.c", 1715
, __extension__ __PRETTY_FUNCTION__); }))) collisions++; new_hash
[i] = old_hash[j], old_hash[j] = ((void*)0); used++; } while (
again++ == 1); qt->qt_table = new_hash, qt->qt_size = new_size
; ((void) sizeof ((qt->qt_used == used) ? 1 : 0), __extension__
({ if (qt->qt_used == used) ; else __assert_fail ("qt->qt_used == used"
, "sres.c", 1715, __extension__ __PRETTY_FUNCTION__); })); su_free
(home, old_hash); return 0; } static inline int sres_qtable_is_full
(sres_qtable_t const *qt) { return qt->qt_table == ((void*
)0) || 3 * qt->qt_used > 2 * qt->qt_size; } static inline
sres_query_t **sres_qtable_hash(sres_qtable_t const *qt, size_t
hv) { return qt->qt_table + hv % qt->qt_size; } static
inline sres_query_t **sres_qtable_next(sres_qtable_t const *
qt, sres_query_t * const *ee) { if (++ee < qt->qt_table
+ qt->qt_size && ee >= qt->qt_table) return
(sres_query_t **)ee; else return qt->qt_table; } static inline
void sres_qtable_append(sres_qtable_t *qt, sres_query_t const
*e) { sres_query_t **ee; qt->qt_used++; for (ee = sres_qtable_hash
(qt, ((e)->q_hash)); *ee; ee = sres_qtable_next(qt, ee)) ;
*ee = (sres_query_t *)e; } static inline void sres_qtable_insert
(sres_qtable_t *qt, sres_query_t const *e) { sres_query_t *e0
, **ee; qt->qt_used++; for (ee = sres_qtable_hash(qt, ((e)
->q_hash)); (e0 = *ee); ee = sres_qtable_next(qt, ee)) *ee
= (sres_query_t *)e, e = e0; *ee = (sres_query_t *)e; } static
inline int sres_qtable_remove(sres_qtable_t *qt, sres_query_t
const *e) { unsigned i, j, k; unsigned size = qt->qt_size
; sres_query_t **htable = qt->qt_table; if (!e) return -1;
for (i = ((e)->q_hash) % size; htable[i]; i = (i + 1) % size
) if (e == htable[i]) break; if (!htable[i]) return -1; for (
j = (i + 1) % size; htable[j]; j = (j + 1) % size) { k = ((htable
[j])->q_hash) % size; if (k == j) continue; if (j > i ?
(i < k && k < j) : (i < k || k < j)) continue
; htable[i] = htable[j], i = j; } qt->qt_used--; htable[i]
= ((void*)0); return 0; } extern int sres_qtable_dummy
1715 unsigned, size_t)static inline int sres_qtable_resize(su_home_t *home, sres_qtable_t
qt[], unsigned new_size) { sres_query_t **new_hash; sres_query_t
**old_hash = qt->qt_table; unsigned old_size; unsigned i,
j, i0; unsigned again = 0; unsigned used = 0, collisions = 0
; if (new_size == 0) new_size = 2 * qt->qt_size + 1; if (new_size
< 31) new_size = 31; if (new_size < 5 * qt->qt_used
/ 4) new_size = 5 * qt->qt_used / 4; if (!(new_hash = su_zalloc
(home, sizeof(*new_hash) * new_size))) return -1; old_size = qt
->qt_size; do for (j = 0; j < old_size; j++) { if (!old_hash
[j]) continue; if (again < 2 && ((old_hash[j])->
q_hash) % old_size > j) { again = 1; continue; } i0 = ((old_hash
[j])->q_hash) % new_size; for (i = i0; new_hash[i]; i = (i
+ 1) % new_size, ((void) sizeof ((i != i0) ? 1 : 0), __extension__
({ if (i != i0) ; else __assert_fail ("i != i0", "sres.c", 1715
, __extension__ __PRETTY_FUNCTION__); }))) collisions++; new_hash
[i] = old_hash[j], old_hash[j] = ((void*)0); used++; } while (
again++ == 1); qt->qt_table = new_hash, qt->qt_size = new_size
; ((void) sizeof ((qt->qt_used == used) ? 1 : 0), __extension__
({ if (qt->qt_used == used) ; else __assert_fail ("qt->qt_used == used"
, "sres.c", 1715, __extension__ __PRETTY_FUNCTION__); })); su_free
(home, old_hash); return 0; } static inline int sres_qtable_is_full
(sres_qtable_t const *qt) { return qt->qt_table == ((void*
)0) || 3 * qt->qt_used > 2 * qt->qt_size; } static inline
sres_query_t **sres_qtable_hash(sres_qtable_t const *qt, size_t
hv) { return qt->qt_table + hv % qt->qt_size; } static
inline sres_query_t **sres_qtable_next(sres_qtable_t const *
qt, sres_query_t * const *ee) { if (++ee < qt->qt_table
+ qt->qt_size && ee >= qt->qt_table) return
(sres_query_t **)ee; else return qt->qt_table; } static inline
void sres_qtable_append(sres_qtable_t *qt, sres_query_t const
*e) { sres_query_t **ee; qt->qt_used++; for (ee = sres_qtable_hash
(qt, ((e)->q_hash)); *ee; ee = sres_qtable_next(qt, ee)) ;
*ee = (sres_query_t *)e; } static inline void sres_qtable_insert
(sres_qtable_t *qt, sres_query_t const *e) { sres_query_t *e0
, **ee; qt->qt_used++; for (ee = sres_qtable_hash(qt, ((e)
->q_hash)); (e0 = *ee); ee = sres_qtable_next(qt, ee)) *ee
= (sres_query_t *)e, e = e0; *ee = (sres_query_t *)e; } static
inline int sres_qtable_remove(sres_qtable_t *qt, sres_query_t
const *e) { unsigned i, j, k; unsigned size = qt->qt_size
; sres_query_t **htable = qt->qt_table; if (!e) return -1;
for (i = ((e)->q_hash) % size; htable[i]; i = (i + 1) % size
) if (e == htable[i]) break; if (!htable[i]) return -1; for (
j = (i + 1) % size; htable[j]; j = (j + 1) % size) { k = ((htable
[j])->q_hash) % size; if (k == j) continue; if (j > i ?
(i < k && k < j) : (i < k || k < j)) continue
; htable[i] = htable[j], i = j; } qt->qt_used--; htable[i]
= ((void*)0); return 0; } extern int sres_qtable_dummy
;
1716
1717#ifdef __clang__1
1718#pragma clang diagnostic pop
1719#endif
1720
1721/** Allocate a query structure */
1722static
1723sres_query_t *
1724sres_query_alloc(sres_resolver_t *res,
1725 sres_answer_f *callback,
1726 sres_context_t *context,
1727 uint16_t type,
1728 char const *domain)
1729{
1730 sres_query_t *query;
1731 size_t dlen = strlen(domain);
1732
1733 if (sres_qtable_is_full(res->res_queries))
1734 if (sres_qtable_resize(res->res_home, res->res_queries, 0) < 0)
1735 return NULL((void*)0);
1736
1737 query = su_alloc(res->res_home, sizeof(*query) + dlen + 1);
1738
1739 if (query) {
1740 memset(query, 0, sizeof *query);
1741 query->q_res = res;
1742 query->q_callback = callback;
1743 query->q_context = context;
1744 query->q_type = type;
1745 query->q_class = sres_class_in;
1746 query->q_timestamp = res->res_now;
1747 query->q_name = strcpy((char *)(query + 1), domain);
1748
1749 sres_gen_id(res, query);
1750 assert(query->q_id)((void) sizeof ((query->q_id) ? 1 : 0), __extension__ ({ if
(query->q_id) ; else __assert_fail ("query->q_id", "sres.c"
, 1750, __extension__ __PRETTY_FUNCTION__); }))
;
1751
1752 query->q_i_server = res->res_i_server;
1753 query->q_n_servers = res->res_n_servers;
1754
1755 sres_qtable_append(res->res_queries, query);
1756
1757 if (res->res_schedulecb && res->res_queries->qt_used == 1)
1758 res->res_schedulecb(res->res_async, 2 * SRES_RETRANSMIT_INTERVAL(SRES_RETRANSMIT_INTERVAL));
1759 }
1760
1761 return query;
1762}
1763
1764su_inlinestatic inline
1765void
1766sres_remove_query(sres_resolver_t *res, sres_query_t *q, int all)
1767{
1768 int i;
1769
1770 if (q->q_hash) {
1771 sres_qtable_remove(res->res_queries, q), q->q_hash = 0;
1772
1773 if (all)
1774 for (i = 0; i <= SRES_MAX_SEARCH(SRES_MAX_SEARCH); i++) {
1775 if (q->q_subqueries[i] && q->q_subqueries[i]->q_hash) {
1776 sres_qtable_remove(res->res_queries, q->q_subqueries[i]);
1777 q->q_subqueries[i]->q_hash = 0;
1778 }
1779 }
1780 }
1781}
1782
1783/** Remove a query from hash table and free it. */
1784static
1785void sres_free_query(sres_resolver_t *res, sres_query_t *q)
1786{
1787 int i;
1788
1789 if (q == NULL((void*)0))
1790 return;
1791
1792 if (q->q_hash)
1793 sres_qtable_remove(res->res_queries, q), q->q_hash = 0;
1794
1795 for (i = 0; i <= SRES_MAX_SEARCH(SRES_MAX_SEARCH); i++) {
1796 sres_query_t *sq;
1797
1798 sq = q->q_subqueries[i];
1799 q->q_subqueries[i] = NULL((void*)0);
1800 if (sq)
1801 sres_free_query(res, sq);
1802 if (q->q_subanswers[i])
1803 sres_cache_free_answers(res->res_cache, q->q_subanswers[i]);
1804 q->q_subanswers[i] = NULL((void*)0);
1805 }
1806
1807 su_free(res->res_home, q);
1808}
1809
1810static
1811sres_record_t **
1812sres_combine_results(sres_resolver_t *res,
1813 sres_record_t **search_results[SRES_MAX_SEARCH(SRES_MAX_SEARCH) + 1])
1814{
1815 sres_record_t **combined_result;
1816 int i, j, found;
1817
1818 /* Combine the results into a single list. */
1819 for (i = 0, found = 0; i <= SRES_MAX_SEARCH(SRES_MAX_SEARCH); i++)
1820 if (search_results[i])
1821 for (j = 0; search_results[i][j]; j++)
1822 found++;
1823
1824 combined_result = su_alloc((su_home_t *)res->res_cache,
1825 (found + 1) * (sizeof combined_result[0]));
1826 if (combined_result) {
1827 for (i = 0, found = 0; i <= SRES_MAX_SEARCH(SRES_MAX_SEARCH); i++)
1828 if (search_results[i])
1829 for (j = 0; search_results[i][j]; j++) {
1830 combined_result[found++] = search_results[i][j];
1831 search_results[i][j] = NULL((void*)0);
1832 }
1833
1834 combined_result[found] = NULL((void*)0);
1835 sres_sort_answers(res, combined_result);
1836 }
1837
1838 for (i = 0; i <= SRES_MAX_SEARCH(SRES_MAX_SEARCH); i++)
1839 if (search_results[i])
1840 sres_free_answers(res, search_results[i]), search_results[i] = NULL((void*)0);
1841
1842 return combined_result;
1843}
1844
1845static
1846int
1847sres_sockaddr2string(sres_resolver_t *res,
1848 char name[],
1849 size_t namelen,
1850 struct sockaddr const *addr)
1851{
1852 name[0] = '\0';
1853
1854 if (addr->sa_family == AF_INET2) {
1855 struct sockaddr_in const *sin = (struct sockaddr_in *)addr;
1856 uint8_t const *in_addr = (uint8_t*)&sin->sin_addr;
1857 return snprintf(name, namelen, "%u.%u.%u.%u.in-addr.arpa.",
1858 in_addr[3], in_addr[2], in_addr[1], in_addr[0]);
1859 }
1860#if HAVE_SIN61
1861 else if (addr->sa_family == AF_INET610) {
1862 struct sockaddr_in6 const *sin6 = (struct sockaddr_in6 *)addr;
1863 size_t addrsize = sizeof(sin6->sin6_addr.s6_addr__in6_u.__u6_addr8);
1864 char *postfix;
1865 size_t required;
1866 size_t i;
1867
1868 if (res->res_config->c_opt.ip6int)
1869 postfix = "ip6.int.";
1870 else
1871 postfix = "ip6.arpa.";
1872
1873 required = addrsize * 4 + strlen(postfix);
1874
1875 if (namelen <= required)
1876 return (int)required;
1877
1878 for (i = 0; i < addrsize; i++) {
1879 uint8_t byte = sin6->sin6_addr.s6_addr__in6_u.__u6_addr8[addrsize - i - 1];
1880 uint8_t hex;
1881
1882 hex = byte & 0xf;
1883 name[4 * i] = hex > 9 ? hex + 'a' - 10 : hex + '0';
1884 name[4 * i + 1] = '.';
1885 hex = (byte >> 4) & 0xf;
1886 name[4 * i + 2] = hex > 9 ? hex + 'a' - 10 : hex + '0';
1887 name[4 * i + 3] = '.';
1888 }
1889
1890 strcpy(name + 4 * i, postfix);
1891
1892 return (int)required;
1893 }
1894#endif /* HAVE_SIN6 */
1895 else {
1896 su_seterrno(EAFNOSUPPORT97);
1897 SU_DEBUG_3(("%s: %s\n", "sres_sockaddr2string",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 1898, "%s: %s\n", "sres_sockaddr2string"
, su_strerror(97))) : (void)0)
1898 su_strerror(EAFNOSUPPORT)))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 1898, "%s: %s\n", "sres_sockaddr2string"
, su_strerror(97))) : (void)0)
;
1899 return 0;
1900 }
1901}
1902
1903/** Make a domain name a top level domain name.
1904 *
1905 * The function sres_toplevel() returns a copies string @a domain and
1906 * terminates it with a dot if it is not already terminated.
1907 */
1908static
1909char const *
1910sres_toplevel(char buf[], size_t blen, char const *domain)
1911{
1912 size_t len;
1913 int already;
1914
1915 if (!domain)
1916 return su_seterrno(EFAULT14), (void *)NULL((void*)0);
1917
1918 len = strlen(domain);
1919
1920 if (len >= blen)
1921 return su_seterrno(ENAMETOOLONG36), (void *)NULL((void*)0);
1922
1923 already = len > 0 && domain[len - 1] == '.';
1924
1925 if (already)
1926 return domain;
1927
1928 if (len + 1 >= blen)
1929 return su_seterrno(ENAMETOOLONG36), (void *)NULL((void*)0);
1930
1931 strcpy(buf, domain);
1932 buf[len] = '.'; buf[len + 1] = '\0';
1933
1934 return buf;
1935}
1936
1937/* ---------------------------------------------------------------------- */
1938
1939static int sres_update_config(sres_resolver_t *res, int always, time_t now);
1940static int sres_parse_config(sres_config_t *, FILE *);
1941static int sres_parse_options(sres_config_t *c, char const *value);
1942static int sres_parse_nameserver(sres_config_t *c, char const *server);
1943static time_t sres_config_timestamp(sres_config_t const *c);
1944
1945/** Update configuration
1946 *
1947 * @retval 0 when successful
1948 * @retval -1 upon an error
1949 */
1950int sres_resolver_update(sres_resolver_t *res, int always)
1951{
1952 sres_server_t **servers, **old_servers;
1953 int updated;
1954
1955 updated = sres_update_config(res, always, time(&res->res_now));
1956 if (updated < 0)
1957 return -1;
1958
1959 if (!res->res_servers || always || updated) {
1960 servers = sres_servers_new(res, res->res_config);
1961 old_servers = res->res_servers;
1962
1963 res->res_i_server = 0;
1964 res->res_n_servers = sres_servers_count(servers);
1965 res->res_servers = servers;
1966
1967 sres_servers_close(res, old_servers);
1968 su_free(res->res_home, old_servers);
1969
1970 if (!servers)
1971 return -1;
1972 }
1973
1974 return 0;
1975}
1976
1977/** Update config file.
1978 *
1979 * @retval 1 if DNS server list is different from old one.
1980 * @retval 0 when otherwise successful
1981 * @retval -1 upon an error
1982 */
1983static
1984int sres_update_config(sres_resolver_t *res, int always, time_t now)
1985{
1986 sres_config_t *c = NULL((void*)0);
1987 sres_config_t const *previous;
1988 int retval;
1989
1990 previous = res->res_config;
1991
1992 if (!always && previous && now < res->res_checked)
1993 return 0;
1994 /* Try avoid checking for changes too often. */
1995 res->res_checked = now + SRES_UPDATE_INTERVAL_SECS5;
1996
1997 if (!always && previous &&
1998 sres_config_timestamp(previous) == previous->c_modified)
1999 return 0;
2000
2001 c = sres_parse_resolv_conf(res, res->res_options);
2002 if (!c)
2003 return -1;
2004
2005 res->res_config = c;
2006
2007 retval = sres_config_changed_servers(c, previous);
2008
2009 su_home_unref((su_home_t *)previous->c_home);
2010
2011 return retval;
2012}
2013
2014#if HAVE_WIN32
2015
2016/** Number of octets to read from a registry key at a time */
2017#define QUERY_DATALEN 1024
2018#define MAX_DATALEN 65535
2019
2020/**
2021 * Uses IP Helper IP to get DNS servers list.
2022 */
2023static int sres_parse_win32_ip(sres_config_t *c)
2024{
2025 int ret = -1;
2026
2027#if HAVE_IPHLPAPI_H
2028 DWORD dw;
2029 su_home_t *home = c->c_home;
2030 ULONG size = sizeof(FIXED_INFO);
2031
2032 do {
2033 FIXED_INFO *info = (FIXED_INFO *)su_alloc(home, size);
2034 dw = GetNetworkParams(info, &size);
2035 if (dw == ERROR_SUCCESS) {
2036 IP_ADDR_STRING* addr = &info->DnsServerList;
2037 for (; addr; addr = addr->Next) {
2038 SU_DEBUG_3(("Adding nameserver: %s\n", addr->IpAddress.String))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 2038, "Adding nameserver: %s\n", addr
->IpAddress.String)) : (void)0)
;
2039 sres_parse_nameserver(c, addr->IpAddress.String);
2040 }
2041 ret = 0;
2042 }
2043 su_free(home, info);
2044 } while (dw == ERROR_BUFFER_OVERFLOW);
2045#endif
2046
2047 return ret;
2048}
2049
2050/**
2051 * Parses name servers listed in registry key 'key+lpValueName'. The
2052 * key is expected to contain a whitespace separate list of
2053 * name server IP addresses.
2054 *
2055 * @return number of server addresses added
2056 */
2057static int sres_parse_win32_reg_parse_dnsserver(sres_config_t *c, HKEY key, LPCTSTR lpValueName)
2058{
2059 su_home_t *home = c->c_home;
2060 su_strlst_t *reg_dns_list;
2061 BYTE *name_servers = su_alloc(home, QUERY_DATALEN);
2062 DWORD name_servers_length = QUERY_DATALEN;
2063 int ret, servers_added = 0;
2064
2065 /* get name servers and ... */
2066 while((ret = RegQueryValueEx(key,
2067 lpValueName,
2068 NULL((void*)0), NULL((void*)0),
2069 name_servers,
2070 &name_servers_length)) == ERROR_MORE_DATA) {
2071 name_servers_length += QUERY_DATALEN;
2072
2073 /* sanity check, upper limit for memallocs */
2074 if (name_servers_length > MAX_DATALEN) break;
2075
2076 name_servers = su_realloc(home, name_servers, name_servers_length);
2077 if (name_servers == NULL((void*)0)) {
2078 ret = ERROR_BUFFER_OVERFLOW;
2079 break;
2080 }
2081 }
2082
2083 /* if reading the key was succesful, continue */
2084 if (ret == ERROR_SUCCESS) {
2085 if (name_servers[0]){
2086 int i;
2087
2088 /* add to list */
2089 reg_dns_list = su_strlst_split(home, (char *)name_servers, " ");
2090
2091 for(i = 0 ; i < su_strlst_len(reg_dns_list); i++) {
2092 const char *item = su_strlst_item(reg_dns_list, i);
2093 SU_DEBUG_3(("Adding nameserver: %s (key=%s)\n", item, (char*)lpValueName))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 2093, "Adding nameserver: %s (key=%s)\n"
, item, (char*)lpValueName)) : (void)0)
;
2094 sres_parse_nameserver(c, item);
2095 ++servers_added;
2096 }
2097
2098 su_strlst_destroy(reg_dns_list);
2099
2100 }
2101 }
2102
2103 su_free(home, name_servers);
2104
2105 return servers_added;
2106}
2107
2108/**
2109 * Discover system nameservers from Windows registry.
2110 *
2111 * Refs:
2112 * - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/regqueryvalueex.asp
2113 * - http://support.microsoft.com/default.aspx?scid=kb;en-us;120642
2114 * - http://support.microsoft.com/kb/314053/EN-US/
2115 * - IP Helper API (possibly better way than current registry-based impl.)
2116 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/iphlp/iphlp/ip_helper_start_page.asp
2117 */
2118static int sres_parse_win32_reg(sres_config_t *c)
2119{
2120 int ret = -1;
2121
2122#define MAX_KEY_LEN 255
2123#define MAX_VALUE_NAME_LEN 16383
2124
2125 su_home_t *home = c->c_home;
2126 HKEY key_handle;
2127#if 0
2128 HKEY interface_key_handle;
2129 FILETIME ftime;
2130 int index, i;
2131#endif
2132 int found = 0;
2133 char *interface_guid = su_alloc(home, MAX_VALUE_NAME_LEN);
2134
2135#if 0
2136#if __MINGW32__
2137 DWORD guid_size = QUERY_DATALEN;
2138#else
2139 int guid_size = MAX_VALUE_NAME_LEN;
2140#endif
2141
2142 /* step: find interface specific nameservers
2143 * - this is currently disabled 2006/Jun (the current check might insert
2144 * multiple unnecessary nameservers to the search list)
2145 */
2146 /* open the 'Interfaces' registry Key */
2147 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2148 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces",
2149 0, KEY_READ, &key_handle)) {
2150 SU_DEBUG_2(("RegOpenKeyEx failed\n"))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 2 ? (_su_llog(sresolv_log, 2, "sres.c"
, (const char *)__func__, 2150, "RegOpenKeyEx failed\n", )) :
(void)0)
;
2151 } else {
2152 index = 0;
2153 /* for each interface listed ... */
2154 while (RegEnumKeyEx(key_handle, index,
2155 interface_guid, &guid_size,
2156 NULL((void*)0),NULL((void*)0),0,&ftime) == ERROR_SUCCESS){
2157 if (RegOpenKeyEx(key_handle, interface_guid,
2158 0, KEY_READ,
2159 &interface_key_handle) == ERROR_SUCCESS) {
2160
2161 /* note: 'NameServer' is preferred over 'DhcpNameServer' */
2162 found += sres_parse_win32_reg_parse_dnsserver(c, interface_key_handle, "NameServer");
2163 if (found == 0)
2164 found += sres_parse_win32_reg_parse_dnsserver(c, interface_key_handle, "DhcpNameServer");
2165
2166 RegCloseKey(interface_key_handle);
2167 } else{
2168 SU_DEBUG_2(("interface RegOpenKeyEx failed\n"))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 2 ? (_su_llog(sresolv_log, 2, "sres.c"
, (const char *)__func__, 2168, "interface RegOpenKeyEx failed\n"
, )) : (void)0)
;
2169 }
2170 index++;
2171 guid_size = 64;
2172 }
2173 RegCloseKey(key_handle);
2174 }
2175#endif /* #if 0: interface-specific nameservers */
2176
2177 /* step: if no interface-specific nameservers are found,
2178 * check for system-wide nameservers */
2179 if (found == 0) {
2180 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2181 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
2182 0, KEY_READ, &key_handle)) {
2183 SU_DEBUG_2(("RegOpenKeyEx failed (2)\n"))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 2 ? (_su_llog(sresolv_log, 2, "sres.c"
, (const char *)__func__, 2183, "RegOpenKeyEx failed (2)\n", )
) : (void)0)
;
2184 } else {
2185 found += sres_parse_win32_reg_parse_dnsserver(c, key_handle, "NameServer");
2186 if (found == 0)
2187 found += sres_parse_win32_reg_parse_dnsserver(c, key_handle, "DhcpNameServer");
2188 RegCloseKey(key_handle);
2189 }
2190 }
2191
2192 SU_DEBUG_3(("Total of %d name servers found from win32 registry.\n", found))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 2192, "Total of %d name servers found from win32 registry.\n"
, found)) : (void)0)
;
2193
2194 /* return success if servers found */
2195 if (found) ret = 0;
2196
2197 su_free(home, interface_guid);
2198
2199 return ret;
2200}
2201
2202#endif /* HAVE_WIN32 */
2203
2204/** Parse /etc/resolv.conf file.
2205 *
2206 * @retval #sres_config_t structure when successful
2207 * @retval NULL upon an error
2208 *
2209 * @todo The resolv.conf directives @b sortlist and most of the options
2210 * are currently ignored.
2211 */
2212static
2213sres_config_t *sres_parse_resolv_conf(sres_resolver_t *res,
2214 char const **options)
2215{
2216 sres_config_t *c = su_home_new(sizeof *c);
2217
2218 if (c) {
2219 FILE *f;
2220 int i;
2221
2222 f = fopen(c->c_filename = res->res_cnffile, "r");
2223
2224 sres_parse_config(c, f);
2225
2226 if (f)
2227 fclose(f);
2228
2229#if HAVE_WIN32
2230 /* note: no 127.0.0.1 on win32 systems */
2231 /* on win32, query the registry for nameservers */
2232 if (sres_parse_win32_ip(c) == 0 || sres_parse_win32_reg(c) == 0)
2233 /* success */;
2234 else
2235 /* now what? */;
2236#else
2237 /* Use local nameserver by default */
2238 if (c->c_nameservers[0] == NULL((void*)0))
2239 sres_parse_nameserver(c, "127.0.0.1");
2240#endif
2241
2242 for (i = 0; c->c_nameservers[i] && i < SRES_MAX_NAMESERVERS(SRES_MAX_NAMESERVERS); i++) {
2243 struct sockaddr_in *sin = (void *)c->c_nameservers[i]->ns_addr;
2244 sin->sin_port = htons(c->c_port);
2245 }
2246
2247 sres_parse_options(c, getenv("RES_OPTIONS"));
2248
2249 if (options)
2250 for (i = 0; options[i]; i++)
2251 sres_parse_options(c, options[i]);
2252
2253 sres_parse_options(c, getenv("SRES_OPTIONS"));
2254
2255 su_home_threadsafe(c->c_home);
2256 }
2257
2258 return c;
2259}
2260
2261uint16_t _sres_default_port = 53;
2262
2263/** Parse config file.
2264 *
2265 * @return Number of search domains, if successful.
2266 * @retval -1 upon an error (never happens).
2267 */
2268static
2269int sres_parse_config(sres_config_t *c, FILE *f)
2270{
2271 su_home_t *home = c->c_home;
2272 int line;
2273 char const *localdomain;
2274 char *search = NULL((void*)0), *domain = NULL((void*)0);
2275 char buf[1025];
2276 int i = 0;
2277
2278 localdomain = getenv("LOCALDOMAIN");
2279
2280 /* Default values */
2281 c->c_opt.ndots = 1;
2282 c->c_opt.check_names = 1;
2283 c->c_opt.timeout = SRES_RETRY_INTERVAL(SRES_RETRY_INTERVAL);
2284 c->c_opt.attempts = SRES_MAX_RETRY_COUNT(SRES_MAX_RETRY_COUNT);
2285 c->c_port = _sres_default_port;
2286
2287 if (f != NULL((void*)0)) {
2288 for (line = 1; fgets(buf, sizeof(buf), f); line++) {
2289 size_t len;
2290 char *value, *b;
2291
2292 /* Skip whitespace at the beginning ...*/
2293 b = buf + strspn(buf, " \t");
2294
2295 /* ... and comments + whitespace at the end */
2296 for (len = strcspn(b, "#;"); len > 0 && strchr(" \t\r\n", b[len - 1]); len--)
2297 ;
2298
2299 if (len == 0) /* Empty line or comment */
2300 continue;
2301
2302 b[len] = '\0';
2303
2304 len = strcspn(b, " \t");
2305 value = b + len; value += strspn(value, " \t");
2306
2307#define MATCH(token)(len == strlen(token) && su_casenmatch(token, b, len)
)
(len == strlen(token) && su_casenmatch(token, b, len))
2308
2309 if (MATCH("nameserver")(len == strlen("nameserver") && su_casenmatch("nameserver"
, b, len))
) {
2310 if (sres_parse_nameserver(c, value) < 0)
2311 return -1;
2312 }
2313 else if (MATCH("domain")(len == strlen("domain") && su_casenmatch("domain", b
, len))
) {
2314 if (localdomain) /* LOCALDOMAIN overrides */
2315 continue;
2316 if (search)
2317 su_free(home, search), search = NULL((void*)0);
2318 if (domain)
2319 su_free(home, domain), domain = NULL((void*)0);
2320 domain = su_strdup(home, value);
2321 if (!domain)
2322 return -1;
2323 }
2324 else if (MATCH("search")(len == strlen("search") && su_casenmatch("search", b
, len))
) {
2325 if (localdomain) /* LOCALDOMAIN overrides */
2326 continue;
2327 if (search) su_free(home, search), search = NULL((void*)0);
2328 if (domain) su_free(home, domain), domain = NULL((void*)0);
2329 search = su_strdup(home, value);
2330 if (!search)
2331 return -1;
2332 }
2333 else if (MATCH("port")(len == strlen("port") && su_casenmatch("port", b, len
))
) {
2334 unsigned long port = strtoul(value, NULL((void*)0), 10);
2335 if (port < 65536)
2336 c->c_port = port;
2337 }
2338 else if (MATCH("options")(len == strlen("options") && su_casenmatch("options",
b, len))
) {
2339 sres_parse_options(c, value);
2340 }
2341 }
2342 }
2343
2344 if (f)
2345 c->c_modified = sres_config_timestamp(c);
2346
2347 if (localdomain)
2348 c->c_search[0] = localdomain;
2349 else if (domain)
2350 c->c_search[0] = domain;
2351 else if (search) {
2352 for (i = 0; search[0] && i < SRES_MAX_SEARCH(SRES_MAX_SEARCH); i++) {
2353 c->c_search[i] = search;
2354 search += strcspn(search, " \t");
2355 if (*search) {
2356 *search++ = '\0';
2357 search += strspn(search, " \t");
2358 }
2359 }
2360 }
2361
2362 return i;
2363}
2364
2365#if DOXYGEN_ONLY
2366/**@ingroup sresolv_env
2367 *
2368 * Environment variable containing options for Sofia resolver. The options
2369 * recognized by Sofia resolver are as follows:
2370 * - @b debug turn on debugging (no effect)
2371 * - @b ndots:<i>n</i> when searching, try first to query name as absolute
2372 * domain if it contains at least <i>n</i> dots
2373 * - @b timeout:<i>secs</i> timeout in seconds
2374 * - @b attempts:<i>n</i> fail after <i>n</i> retries
2375 * - @b rotate use round robin selection of nameservers
2376 * - @b no-check-names do not check names for invalid characters
2377 * - @b inet6 (no effect)
2378 * - @b ip6-dotint IPv6 addresses are resolved using suffix ".ip6.int"
2379 * instead of the standard ".ip6.arpa" suffix
2380 * - @b ip6-bytestring (no effect)
2381 * The following option is a Sofia-specific extension:
2382 * - @b no-edns0 do not try to use EDNS0 extension (@RFC2671)
2383 *
2384 * The same options can be listed in @b options directive in resolv.conf, or
2385 * in #RES_OPTIONS environment variable. Note that options given in
2386 * #SRES_OPTIONS override those specified in #RES_OPTIONS which in turn
2387 * override options specified in the @b options directive of resolve.conf.
2388 *
2389 * The meaning of an option can be reversed with prefix "no-".
2390 *
2391 * @sa Manual page for resolv.conf, #RES_OPTIONS.
2392 */
2393extern SRES_OPTIONS;
2394
2395/**@ingroup sresolv_env
2396 *
2397 * Environment variable containing resolver options. This environment
2398 * variable is also used by standard BIND resolver.
2399 *
2400 * @sa Manual page for resolv.conf, #SRES_OPTIONS.
2401 */
2402extern RES_OPTIONS;
2403
2404/**@ingroup sresolv_env
2405 *
2406 * Environment variable containing search domain. This environment
2407 * variable is also used by standard BIND resolver.
2408 *
2409 * @sa Manual page for resolv.conf, #RES_OPTIONS, #SRES_OPTIONS.
2410 */
2411extern LOCALDOMAIN;
2412#endif
2413
2414/* Parse options line or #SRES_OPTIONS or #RES_OPTIONS environment variable. */
2415static int
2416sres_parse_options(sres_config_t *c, char const *value)
2417{
2418 if (!value)
2419 return -1;
2420
2421 while (value[0]) {
2422 char const *b;
2423 size_t len, extra = 0;
2424 unsigned long n = 0;
2425
2426 b = value; len = strcspn(value, " \t:");
2427 value += len;
2428
2429 if (value[0] == ':') {
2430 len++;
2431 n = strtoul(++value, NULL((void*)0), 10);
2432 value += extra = strcspn(value, " \t");
2433 }
2434
2435 if (*value)
2436 value += strspn(value, " \t");
2437
2438 if (n > 65536) {
2439 SU_DEBUG_3(("sres: %s: invalid %*.0s\n", c->c_filename,(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 2440, "sres: %s: invalid %*.0s\n", c
->c_filename, (int)(len + extra), b)) : (void)0)
2440 (int)(len + extra), b))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 2440, "sres: %s: invalid %*.0s\n", c
->c_filename, (int)(len + extra), b)) : (void)0)
;
2441 continue;
2442 }
2443
2444 /* Documented by BIND9 resolv.conf */
2445 if (MATCH("no-debug")(len == strlen("no-debug") && su_casenmatch("no-debug"
, b, len))
) c->c_opt.debug = 0;
2446 else if (MATCH("debug")(len == strlen("debug") && su_casenmatch("debug", b, len
))
) c->c_opt.debug = 1;
2447 else if (MATCH("ndots:")(len == strlen("ndots:") && su_casenmatch("ndots:", b
, len))
) c->c_opt.ndots = n;
2448 else if (MATCH("timeout:")(len == strlen("timeout:") && su_casenmatch("timeout:"
, b, len))
) c->c_opt.timeout = n;
2449 else if (MATCH("attempts:")(len == strlen("attempts:") && su_casenmatch("attempts:"
, b, len))
) c->c_opt.attempts = n;
2450 else if (MATCH("no-rotate")(len == strlen("no-rotate") && su_casenmatch("no-rotate"
, b, len))
) c->c_opt.rotate = 0;
2451 else if (MATCH("rotate")(len == strlen("rotate") && su_casenmatch("rotate", b
, len))
) c->c_opt.rotate = 1;
2452 else if (MATCH("no-check-names")(len == strlen("no-check-names") && su_casenmatch("no-check-names"
, b, len))
) c->c_opt.check_names = 0;
2453 else if (MATCH("check-names")(len == strlen("check-names") && su_casenmatch("check-names"
, b, len))
) c->c_opt.check_names = 1;
2454 else if (MATCH("no-inet6")(len == strlen("no-inet6") && su_casenmatch("no-inet6"
, b, len))
) c->c_opt.ip6int = 0;
2455 else if (MATCH("inet6")(len == strlen("inet6") && su_casenmatch("inet6", b, len
))
) c->c_opt.inet6 = 1;
2456 else if (MATCH("no-ip6-dotint")(len == strlen("no-ip6-dotint") && su_casenmatch("no-ip6-dotint"
, b, len))
) c->c_opt.ip6int = 0;
2457 else if (MATCH("ip6-dotint")(len == strlen("ip6-dotint") && su_casenmatch("ip6-dotint"
, b, len))
) c->c_opt.ip6int = 1;
2458 else if (MATCH("no-ip6-bytestring")(len == strlen("no-ip6-bytestring") && su_casenmatch(
"no-ip6-bytestring", b, len))
) c->c_opt.ip6bytestring = 0;
2459 else if (MATCH("ip6-bytestring")(len == strlen("ip6-bytestring") && su_casenmatch("ip6-bytestring"
, b, len))
) c->c_opt.ip6bytestring = 1;
2460 /* Sofia-specific extensions: */
2461 else if (MATCH("no-edns0")(len == strlen("no-edns0") && su_casenmatch("no-edns0"
, b, len))
) c->c_opt.edns = edns_not_supported;
2462 else if (MATCH("edns0")(len == strlen("edns0") && su_casenmatch("edns0", b, len
))
) c->c_opt.edns = edns0_configured;
2463 else {
2464 SU_DEBUG_3(("sres: %s: unknown option %*.0s\n",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 2465, "sres: %s: unknown option %*.0s\n"
, c->c_filename, (int)(len + extra), b)) : (void)0)
2465 c->c_filename, (int)(len + extra), b))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 2465, "sres: %s: unknown option %*.0s\n"
, c->c_filename, (int)(len + extra), b)) : (void)0)
;
2466 }
2467 }
2468
2469 return 0;
2470}
2471
2472static
2473int sres_parse_nameserver(sres_config_t *c, char const *server)
2474{
2475 sres_nameserver_t *ns;
2476 struct sockaddr *sa;
2477 int err, i;
2478
2479 for (i = 0; i < SRES_MAX_NAMESERVERS(SRES_MAX_NAMESERVERS); i++)
2480 if (c->c_nameservers[i] == NULL((void*)0))
2481 break;
2482
2483 if (i >= SRES_MAX_NAMESERVERS(SRES_MAX_NAMESERVERS))
2484 return 0 /* Silently discard extra nameservers */;
2485
2486 ns = su_zalloc(c->c_home, (sizeof *ns) + strlen(server) + 1);
2487 if (!ns)
2488 return -1;
2489
2490 sa = (void *)ns->ns_addr;
2491
2492#if HAVE_SIN61
2493 if (strchr(server, ':')) {
2494 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
2495 memset(sa, 0, ns->ns_addrlen = sizeof *sin6);
2496 err = su_inet_ptoninet_pton(sa->sa_family = AF_INET610, server, &sin6->sin6_addr);
2497 }
2498 else
2499#endif
2500 {
2501 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
2502 memset(sa, 0, ns->ns_addrlen = sizeof *sin);
2503 err = su_inet_ptoninet_pton(sa->sa_family = AF_INET2, server, &sin->sin_addr);
2504 }
2505
2506 if (err <= 0) {
2507 SU_DEBUG_3(("sres: nameserver %s: invalid address\n", server))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 2507, "sres: nameserver %s: invalid address\n"
, server)) : (void)0)
;
2508 su_free(c->c_home, ns);
2509 return 0;
2510 }
2511
2512#if HAVE_SA_LEN
2513 sa->sa_len = ns->ns_addrlen;
2514#endif
2515
2516 c->c_nameservers[i] = ns;
2517
2518 return 1;
2519}
2520
2521/** Get current timestamp of resolv.conf file */
2522static
2523time_t sres_config_timestamp(sres_config_t const *c)
2524{
2525#ifndef HAVE_WIN32
2526 struct stat st;
2527
2528 if (stat(c->c_filename, &st) == 0)
2529 return st.st_mtimest_mtim.tv_sec;
2530
2531 /** @return If the resolv.conf file does not exists, return old timestamp. */
2532 return c->c_modified;
2533#else
2534 /** On WIN32, return always different timestamp */
2535 return c->c_modified + SRES_UPDATE_INTERVAL_SECS5;
2536#endif
2537}
2538
2539
2540/* ---------------------------------------------------------------------- */
2541
2542/** Check if the new configuration has different servers than the old */
2543static
2544int sres_config_changed_servers(sres_config_t const *new_c,
2545 sres_config_t const *old_c)
2546{
2547 int i;
2548 sres_nameserver_t const *new_ns, *old_ns;
2549
2550 if (old_c == NULL((void*)0))
2551 return 1;
2552
2553 for (i = 0; i < SRES_MAX_NAMESERVERS(SRES_MAX_NAMESERVERS); i++) {
2554 new_ns = new_c->c_nameservers[i];
2555 old_ns = old_c->c_nameservers[i];
2556
2557 if (!new_ns != !old_ns)
2558 return 1;
2559 if (!new_ns)
2560 return 0;
2561 if (new_ns->ns_addrlen != old_ns->ns_addrlen)
2562 return 1;
2563 if (memcmp(new_ns->ns_addr, old_ns->ns_addr, new_ns->ns_addrlen))
2564 return 1;
2565 }
2566
2567 return 0;
2568}
2569
2570/** Allocate new servers structure */
2571static
2572sres_server_t **sres_servers_new(sres_resolver_t *res,
2573 sres_config_t const *c)
2574{
2575 sres_server_t **servers, *dns;
2576 sres_nameserver_t *ns;
2577 int N, i;
2578 size_t size;
2579
2580 for (N = 0; c->c_nameservers[N] && N < SRES_MAX_NAMESERVERS(SRES_MAX_NAMESERVERS); N++)
2581 ;
2582
2583 size = (N + 1) * (sizeof *servers) + N * (sizeof **servers);
2584
2585 servers = su_zalloc(res->res_home, size); if (!servers) return servers;
2586 dns = (void *)(servers + N + 1);
2587 for (i = 0; i < N; i++) {
2588 dns->dns_socket = INVALID_SOCKET((sres_socket_t)-1);
2589 ns = c->c_nameservers[i];
2590 memcpy(dns->dns_addr, ns->ns_addr, dns->dns_addrlen = ns->ns_addrlen);
2591 su_inet_ntopinet_ntop(dns->dns_addr->ss_family, SS_ADDR(dns->dns_addr)((dns->dns_addr)->ss_family == 2 ? (void *)&((struct
sockaddr_in *)dns->dns_addr)->sin_addr : ((dns->dns_addr
)->ss_family == 10 ? (void *)&((struct sockaddr_in6 *)
dns->dns_addr)->sin6_addr : (void *)&((struct sockaddr
*)dns->dns_addr)->sa_data))
,
2592 dns->dns_name, sizeof dns->dns_name);
2593 dns->dns_edns = c->c_opt.edns;
2594 servers[i] = dns++;
2595 }
2596
2597 return servers;
2598}
2599
2600static
2601void sres_servers_close(sres_resolver_t *res,
2602 sres_server_t **servers)
2603{
2604 int i;
2605
2606 if (res == NULL((void*)0) || servers == NULL((void*)0))
2607 return;
2608
2609 for (i = 0; i < SRES_MAX_NAMESERVERS(SRES_MAX_NAMESERVERS); i++) {
2610 if (!servers[i])
2611 break;
2612
2613 if (servers[i]->dns_socket != INVALID_SOCKET((sres_socket_t)-1)) {
2614 if (res->res_updcb)
2615 res->res_updcb(res->res_async, INVALID_SOCKET((sres_socket_t)-1), servers[i]->dns_socket);
2616 sres_close(servers[i]->dns_socket)close((servers[i]->dns_socket));
2617 }
2618 }
2619}
2620
2621static
2622int sres_servers_count(sres_server_t *const *servers)
2623{
2624 int i;
2625
2626 if (!servers)
2627 return 0;
2628
2629 for (i = 0; i < SRES_MAX_NAMESERVERS(SRES_MAX_NAMESERVERS); i++) {
2630 if (!servers[i])
2631 break;
2632 }
2633
2634 return i;
2635}
2636
2637static
2638sres_socket_t sres_server_socket(sres_resolver_t *res, sres_server_t *dns)
2639{
2640 int family = dns->dns_addr->ss_family;
2641 sres_socket_t s;
2642
2643 if (dns->dns_socket != INVALID_SOCKET((sres_socket_t)-1))
2644 return dns->dns_socket;
2645
2646 s = socket(family, SOCK_DGRAMSOCK_DGRAM, IPPROTO_UDPIPPROTO_UDP);
2647 if (s == -1) {
2648 SU_DEBUG_1(("%s: %s: %s\n", "sres_server_socket", "socket",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 1 ? (_su_llog(sresolv_log, 1, "sres.c"
, (const char *)__func__, 2649, "%s: %s: %s\n", "sres_server_socket"
, "socket", su_strerror(su_errno()))) : (void)0)
2649 su_strerror(su_errno())))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 1 ? (_su_llog(sresolv_log, 1, "sres.c"
, (const char *)__func__, 2649, "%s: %s: %s\n", "sres_server_socket"
, "socket", su_strerror(su_errno()))) : (void)0)
;
2650 return s;
2651 }
2652
2653#if HAVE_IP_RECVERR1
2654 if (family == AF_INET2 || family == AF_INET610) {
2655 int const one = 1;
2656 if (setsockopt(s, SOL_IP0, IP_RECVERR11, &one, sizeof(one)) < 0) {
2657 if (family == AF_INET2)
2658 SU_DEBUG_3(("setsockopt(IPVRECVERR): %s\n", su_strerror(su_errno())))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 2658, "setsockopt(IPVRECVERR): %s\n"
, su_strerror(su_errno()))) : (void)0)
;
2659 }
2660 }
2661#endif
2662#if HAVE_IPV6_RECVERR1
2663 if (family == AF_INET610) {
2664 int const one = 1;
2665 if (setsockopt(s, SOL_IPV641, IPV6_RECVERR25, &one, sizeof(one)) < 0)
2666 SU_DEBUG_3(("setsockopt(IPV6_RECVERR): %s\n", su_strerror(su_errno())))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 2666, "setsockopt(IPV6_RECVERR): %s\n"
, su_strerror(su_errno()))) : (void)0)
;
2667 }
2668#endif
2669
2670 if (connect(s, (void *)dns->dns_addr, dns->dns_addrlen) < 0) {
2671 char ipaddr[64];
2672 char const *lb = "", *rb = "";
2673
2674 if (family == AF_INET2) {
2675 void *addr = &((struct sockaddr_in *)dns->dns_addr)->sin_addr;
2676 su_inet_ntopinet_ntop(family, addr, ipaddr, sizeof ipaddr);
2677 }
2678#if HAVE_SIN61
2679 else if (family == AF_INET610) {
2680 void *addr = &((struct sockaddr_in6 *)dns->dns_addr)->sin6_addr;
2681 su_inet_ntopinet_ntop(family, addr, ipaddr, sizeof ipaddr);
2682 lb = "[", rb = "]";
2683 }
2684#endif
2685 else
2686 snprintf(ipaddr, sizeof ipaddr, "<af=%u>", family);
2687
2688 SU_DEBUG_1(("%s: %s: %s: %s%s%s:%u\n", "sres_server_socket", "connect",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 1 ? (_su_llog(sresolv_log, 1, "sres.c"
, (const char *)__func__, 2690, "%s: %s: %s: %s%s%s:%u\n", "sres_server_socket"
, "connect", su_strerror(su_errno()), lb, ipaddr, rb, ntohs((
(struct sockaddr_in *)dns->dns_addr)->sin_port))) : (void
)0)
2689 su_strerror(su_errno()), lb, ipaddr, rb,(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 1 ? (_su_llog(sresolv_log, 1, "sres.c"
, (const char *)__func__, 2690, "%s: %s: %s: %s%s%s:%u\n", "sres_server_socket"
, "connect", su_strerror(su_errno()), lb, ipaddr, rb, ntohs((
(struct sockaddr_in *)dns->dns_addr)->sin_port))) : (void
)0)
2690 ntohs(((struct sockaddr_in *)dns->dns_addr)->sin_port)))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 1 ? (_su_llog(sresolv_log, 1, "sres.c"
, (const char *)__func__, 2690, "%s: %s: %s: %s%s%s:%u\n", "sres_server_socket"
, "connect", su_strerror(su_errno()), lb, ipaddr, rb, ntohs((
(struct sockaddr_in *)dns->dns_addr)->sin_port))) : (void
)0)
;
2691 sres_close(s)close((s));
2692 return INVALID_SOCKET((sres_socket_t)-1);
2693 }
2694
2695 if (res->res_updcb) {
2696 if (res->res_updcb(res->res_async, s, INVALID_SOCKET((sres_socket_t)-1)) < 0) {
2697 SU_DEBUG_1(("%s: %s: %s\n", "sres_server_socket", "update callback",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 1 ? (_su_llog(sresolv_log, 1, "sres.c"
, (const char *)__func__, 2698, "%s: %s: %s\n", "sres_server_socket"
, "update callback", su_strerror(su_errno()))) : (void)0)
2698 su_strerror(su_errno())))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 1 ? (_su_llog(sresolv_log, 1, "sres.c"
, (const char *)__func__, 2698, "%s: %s: %s\n", "sres_server_socket"
, "update callback", su_strerror(su_errno()))) : (void)0)
;
2699 sres_close(s)close((s));
2700 return INVALID_SOCKET((sres_socket_t)-1);
2701 }
2702 }
2703
2704 dns->dns_socket = s;
2705
2706 return s;
2707}
2708
2709/* ---------------------------------------------------------------------- */
2710
2711/** Send a query packet */
2712static
2713int
2714sres_send_dns_query(sres_resolver_t *res,
2715 sres_query_t *q)
2716{
2717 sres_message_t m[1];
2718 uint8_t i, i0, N = res->res_n_servers;
2719 sres_socket_t s;
2720 int error = 0;
2721 ssize_t size, no_edns_size, edns_size;
2722 uint16_t id = q->q_id;
2723 uint16_t type = q->q_type;
2724 char const *domain = q->q_name;
2725 time_t now = res->res_now;
2726 sres_server_t **servers = res->res_servers, *dns;
2727 char b[8];
2728
2729 if (now == 0) time(&now);
2730
2731 SU_DEBUG_9(("sres_send_dns_query(%p, %p) called\n", (void *)res, (void *)q))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 2731, "sres_send_dns_query(%p, %p) called\n"
, (void *)res, (void *)q)) : (void)0)
;
2732
2733 if (domain == NULL((void*)0))
2734 return -1;
2735 if (servers == NULL((void*)0))
2736 return -1;
2737 if (N == 0)
2738 return -1;
2739
2740 memset(m, 0, offsetof(sres_message_t, m_data[sizeof m->m_packet.mp_header])__builtin_offsetof(sres_message_t, m_packet.mp_data[sizeof m->
m_packet.mp_header])
);
2741
2742 /* Create a DNS message */
2743 size = sizeof(m->m_packet.mp_header);
2744 m->m_size = (uint16_t)sizeof(m->m_datam_packet.mp_data);
2745 m->m_offset = (uint16_t)size;
2746
2747 m->m_idm_packet.mp_header.mh_id = id;
2748 m->m_flagsm_packet.mp_header.mh_flags = htons(SRES_HDR_QUERY | SRES_HDR_RD);
2749
2750 /* Query record */
2751 m->m_qdcountm_packet.mp_header.mh_qdcount = htons(1);
2752 m_put_domain(m, domain, 0, NULL((void*)0));
2753 m_put_uint16(m, type);
2754 m_put_uint16(m, sres_class_in);
2755
2756 no_edns_size = m->m_offset;
2757
2758 /* EDNS0 record (optional) */
2759 m_put_domain(m, ".", 0, NULL((void*)0));
2760 m_put_uint16(m, sres_type_opt);
2761 m_put_uint16(m, sizeof(m->m_packet)); /* Class: our UDP payload size */
2762 m_put_uint32(m, 0); /* TTL: extended RCODE & flags */
2763 m_put_uint16(m, 0);
2764
2765 edns_size = m->m_offset;
2766
2767 if (m->m_error) {
2768 SU_DEBUG_3(("%s(): encoding: %s\n", "sres_send_dns_query", m->m_error))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 3 ? (_su_llog(sresolv_log, 3, "sres.c"
, (const char *)__func__, 2768, "%s(): encoding: %s\n", "sres_send_dns_query"
, m->m_error)) : (void)0)
;
2769 su_seterrno(EIO5);
2770 return -1;
2771 }
2772
2773 i0 = q->q_i_server;
2774 if (i0 > N) i0 = 0; /* Number of DNS servers reduced */
2775 dns = servers[i = i0];
2776
2777 error = EIO5;
2778
2779 if (res->res_config->c_opt.rotate || dns->dns_error || dns->dns_icmp)
2780 dns = sres_next_server(res, &q->q_i_server, 1), i = q->q_i_server;
2781
2782 for (; dns; dns = sres_next_server(res, &i, 1)) {
2783 /* If server supports EDNS, include EDNS0 record */
2784 q->q_edns = dns->dns_edns;
2785 /* 0 (no EDNS) or 1 (EDNS supported) additional data records */
2786 m->m_arcountm_packet.mp_header.mh_arcount = htons(q->q_edns != 0);
2787 /* Size with or without EDNS record */
2788 size = q->q_edns ? edns_size : no_edns_size;
2789
2790 s = sres_server_socket(res, dns);
2791
2792 if (s == INVALID_SOCKET((sres_socket_t)-1)) {
2793 dns->dns_icmp = now;
2794 dns->dns_error = SRES_TIME_MAX((time_t)9223372036854775807L);
2795 continue;
2796 }
2797
2798 /* Send the DNS message via the UDP socket */
2799 if (sres_send(s, m->m_data, size, 0)send((s),(m->m_packet.mp_data),(size),(0)) == size)
2800 break;
2801 error = su_errno();
2802
2803 dns->dns_icmp = now;
2804 dns->dns_error = now; /* Mark as a bad destination */
2805 }
2806
2807 if (!dns) {
2808 /* All servers have reported errors */
2809 SU_DEBUG_5(("%s(): sendto: %s\n", "sres_send_dns_query",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 2810, "%s(): sendto: %s\n", "sres_send_dns_query"
, su_strerror(error))) : (void)0)
2810 su_strerror(error)))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 2810, "%s(): sendto: %s\n", "sres_send_dns_query"
, su_strerror(error))) : (void)0)
;
2811 return su_seterrno(error);
2812 }
2813
2814 q->q_i_server = i;
2815
2816 SU_DEBUG_5(("%s(%p, %p) id=%u %s %s (to [%s]:%u)\n",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 2820, "%s(%p, %p) id=%u %s %s (to [%s]:%u)\n"
, "sres_send_dns_query", (void *)res, (void *)q, id, sres_record_type
(type, b), domain, dns->dns_name, htons(((struct sockaddr_in
*)dns->dns_addr)->sin_port))) : (void)0)
2817 "sres_send_dns_query",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 2820, "%s(%p, %p) id=%u %s %s (to [%s]:%u)\n"
, "sres_send_dns_query", (void *)res, (void *)q, id, sres_record_type
(type, b), domain, dns->dns_name, htons(((struct sockaddr_in
*)dns->dns_addr)->sin_port))) : (void)0)
2818 (void *)res, (void *)q, id, sres_record_type(type, b), domain,(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 2820, "%s(%p, %p) id=%u %s %s (to [%s]:%u)\n"
, "sres_send_dns_query", (void *)res, (void *)q, id, sres_record_type
(type, b), domain, dns->dns_name, htons(((struct sockaddr_in
*)dns->dns_addr)->sin_port))) : (void)0)
2819 dns->dns_name,(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 2820, "%s(%p, %p) id=%u %s %s (to [%s]:%u)\n"
, "sres_send_dns_query", (void *)res, (void *)q, id, sres_record_type
(type, b), domain, dns->dns_name, htons(((struct sockaddr_in
*)dns->dns_addr)->sin_port))) : (void)0)
2820 htons(((struct sockaddr_in *)dns->dns_addr)->sin_port)))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 2820, "%s(%p, %p) id=%u %s %s (to [%s]:%u)\n"
, "sres_send_dns_query", (void *)res, (void *)q, id, sres_record_type
(type, b), domain, dns->dns_name, htons(((struct sockaddr_in
*)dns->dns_addr)->sin_port))) : (void)0)
;
2821
2822 return 0;
2823}
2824
2825/** Retry time after ICMP error */
2826#define DNS_ICMP_TIMEOUT60 60
2827
2828/** Retry time after immediate error */
2829#define DNS_ERROR_TIMEOUT10 10
2830
2831/** Select next server.
2832 *
2833 * @param res resolver object
2834 * @param[in,out] in_out_i index to DNS server table
2835 * @param always return always a server
2836 */
2837static
2838sres_server_t *sres_next_server(sres_resolver_t *res,
2839 uint8_t *in_out_i,
2840 int always)
2841{
2842 int i, j, N;
2843 sres_server_t *dns, **servers;
2844 time_t now = res->res_now;
2845
2846 N = res->res_n_servers;
2847 servers = res->res_servers;
2848 i = *in_out_i;
2849
2850 assert(res->res_servers && res->res_servers[i])((void) sizeof ((res->res_servers && res->res_servers
[i]) ? 1 : 0), __extension__ ({ if (res->res_servers &&
res->res_servers[i]) ; else __assert_fail ("res->res_servers && res->res_servers[i]"
, "sres.c", 2850, __extension__ __PRETTY_FUNCTION__); }))
;
2851
2852 for (j=0; j < N; j++) {
2853 dns = servers[j]; if (!dns) continue;
2854 if (dns->dns_icmp + DNS_ICMP_TIMEOUT60 < now)
2855 dns->dns_icmp = 0;
2856 if (dns->dns_error + DNS_ERROR_TIMEOUT10 < now &&
2857 dns->dns_error != SRES_TIME_MAX((time_t)9223372036854775807L))
2858 dns->dns_error = 0;
2859 }
2860
2861 /* Retry using another server? */
2862 for (j = (i + 1) % N; (j != i); j = (j + 1) % N) {
2863 dns = servers[j]; if (!dns) continue;
2864 if (dns->dns_icmp == 0) {
2865 return *in_out_i = j, dns;
2866 }
2867 }
2868
2869 for (j = (i + 1) % N; (j != i); j = (j + 1) % N) {
2870 dns = servers[j]; if (!dns) continue;
2871 if (dns->dns_error == 0) {
2872 return *in_out_i = j, dns;
2873 }
2874 }
2875
2876 if (!always)
2877 return NULL((void*)0);
2878
2879 dns = servers[i];
2880 if (dns && dns->dns_error < now && dns->dns_error != SRES_TIME_MAX((time_t)9223372036854775807L))
2881 return dns;
2882
2883 for (j = (i + 1) % N; j != i; j = (j + 1) % N) {
2884 dns = servers[j]; if (!dns) continue;
2885 if (dns->dns_error < now && dns->dns_error != SRES_TIME_MAX((time_t)9223372036854775807L))
2886 return *in_out_i = j, dns;
2887 }
2888
2889 return NULL((void*)0);
2890}
2891
2892/**
2893 * Callback function for subqueries
2894 */
2895static
2896void sres_answer_subquery(sres_context_t *context,
2897 sres_query_t *query,
2898 sres_record_t **answers)
2899{
2900 sres_resolver_t *res;
2901 sres_query_t *top = (sres_query_t *)context;
2902 int i;
2903 assert(top)((void) sizeof ((top) ? 1 : 0), __extension__ ({ if (top) ; else
__assert_fail ("top", "sres.c", 2903, __extension__ __PRETTY_FUNCTION__
); }))
; assert(top->q_n_subs > 0)((void) sizeof ((top->q_n_subs > 0) ? 1 : 0), __extension__
({ if (top->q_n_subs > 0) ; else __assert_fail ("top->q_n_subs > 0"
, "sres.c", 2903, __extension__ __PRETTY_FUNCTION__); }))
; assert(query)((void) sizeof ((query) ? 1 : 0), __extension__ ({ if (query)
; else __assert_fail ("query", "sres.c", 2903, __extension__
__PRETTY_FUNCTION__); }))
;
2904
2905 res = query->q_res;
2906
2907 for (i = 0; i <= SRES_MAX_SEARCH(SRES_MAX_SEARCH); i++) {
2908 if (top->q_subqueries[i] == query)
2909 break;
2910 }
2911 assert(i <= SRES_MAX_SEARCH)((void) sizeof ((i <= (SRES_MAX_SEARCH)) ? 1 : 0), __extension__
({ if (i <= (SRES_MAX_SEARCH)) ; else __assert_fail ("i <= SRES_MAX_SEARCH"
, "sres.c", 2911, __extension__ __PRETTY_FUNCTION__); }))
;
2912 if (i > SRES_MAX_SEARCH(SRES_MAX_SEARCH) || top->q_n_subs == 0) {
2913 sres_free_answers(res, answers);
2914 return;
2915 }
2916
2917 if (answers) {
2918 int j, k;
2919 for (j = 0, k = 0; answers[j]; j++) {
2920 if (answers[j]->sr_statussr_record->r_status)
2921 sres_free_answer(query->q_res, answers[j]);
2922 else
2923 answers[k++] = answers[j];
2924 }
2925 answers[k] = NULL((void*)0);
2926 if (!answers[0])
2927 sres_free_answers(query->q_res, answers), answers = NULL((void*)0);
2928 }
2929
2930 top->q_subqueries[i] = NULL((void*)0);
2931 top->q_subanswers[i] = answers;
2932 top->q_n_subs--;
2933
2934 if (answers && top->q_callback) {
2935 sres_answer_f *callback = top->q_callback;
2936
2937 top->q_callback = NULL((void*)0);
2938 sres_remove_query(top->q_res, top, 1);
2939 callback(top->q_context, top, answers);
2940 }
2941 else if (top->q_n_subs == 0 && top->q_id == 0) {
2942 sres_query_report_error(top, NULL((void*)0));
2943 };
2944}
2945
2946/** Report sres error */
2947static void
2948sres_query_report_error(sres_query_t *q,
2949 sres_record_t **answers)
2950{
2951 int i;
2952
2953 if (q->q_callback) {
2954 char sbuf[8], tbuf[8];
2955 int status = 0;
2956
2957 for (i = 0; i <= SRES_MAX_SEARCH(SRES_MAX_SEARCH); i++) {
2958 if (q->q_subqueries[i]) /* a pending query... */
2959 return;
2960
2961 if (q->q_subanswers[i]) {
2962 answers = q->q_subanswers[i];
2963 q->q_subanswers[i] = NULL((void*)0);
2964 break;
2965 }
2966 }
2967
2968 if (answers == NULL((void*)0)) {
2969 sres_cache_t *cache = q->q_res->res_cache;
2970
2971 status = q->q_retry_count ? SRES_TIMEOUT_ERR : SRES_NETWORK_ERR;
2972
2973 answers = su_zalloc(CHOME(cache)((su_home_t *)(cache)), 2 * sizeof *answers);
2974 if (answers)
2975 answers[0] = sres_create_error_rr(cache, q, status);
2976 }
2977 else {
2978 for (i = 0; answers[i]; i++) {
2979 status = answers[i]->sr_record->r_status;
2980 if (status)
2981 break;
2982 }
2983 }
2984
2985 SU_DEBUG_5(("sres(q=%p): reporting error %s for %s %s\n",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 2988, "sres(q=%p): reporting error %s for %s %s\n"
, (void *)q, sres_record_status(status, sbuf), sres_record_type
(q->q_type, tbuf), q->q_name)) : (void)0)
2986 (void *)q,(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 2988, "sres(q=%p): reporting error %s for %s %s\n"
, (void *)q, sres_record_status(status, sbuf), sres_record_type
(q->q_type, tbuf), q->q_name)) : (void)0)
2987 sres_record_status(status, sbuf),(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 2988, "sres(q=%p): reporting error %s for %s %s\n"
, (void *)q, sres_record_status(status, sbuf), sres_record_type
(q->q_type, tbuf), q->q_name)) : (void)0)
2988 sres_record_type(q->q_type, tbuf), q->q_name))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 2988, "sres(q=%p): reporting error %s for %s %s\n"
, (void *)q, sres_record_status(status, sbuf), sres_record_type
(q->q_type, tbuf), q->q_name)) : (void)0)
;
2989
2990 sres_remove_query(q->q_res, q, 1);
2991 (q->q_callback)(q->q_context, q, answers);
2992 }
2993
2994 sres_free_query(q->q_res, q);
2995}
2996
2997/** Resolver timer function.
2998 *
2999 * The function sresolver_timer() should be called in regular intervals. We
3000 * recommend calling it in 500 ms intervals.
3001 *
3002 * @param res pointer to resolver object
3003 * @param dummy argument for compatibility
3004 */
3005void sres_resolver_timer(sres_resolver_t *res, int dummy)
3006{
3007 size_t i;
3008 sres_query_t *q;
3009 time_t now, retry_time;
3010
3011 if (res == NULL((void*)0))
3012 return;
3013
3014 now = time(&res->res_now);
3015
3016 if (res->res_queries->qt_used) {
3017 SU_DEBUG_9(("sres_resolver_timer() called at %lu\n", (long) now))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3017, "sres_resolver_timer() called at %lu\n"
, (long) now)) : (void)0)
;
3018
3019 /** Every time it is called it goes through all query structures, and
3020 * retransmits all the query messages, which have not been answered yet.
3021 */
3022 for (i = 0; i < res->res_queries->qt_size; i++) {
3023 q = res->res_queries->qt_table[i];
3024
3025 if (!q)
3026 continue;
3027
3028 /* Exponential backoff */
3029 retry_time = q->q_timestamp + ((time_t)1 << q->q_retry_count);
3030
3031 if (now < retry_time)
3032 continue;
3033
3034 sres_resend_dns_query(res, q, 1);
3035
3036 if (q != res->res_queries->qt_table[i])
3037 i--;
3038 }
3039
3040 if (res->res_schedulecb && res->res_queries->qt_used)
3041 res->res_schedulecb(res->res_async, SRES_RETRANSMIT_INTERVAL(SRES_RETRANSMIT_INTERVAL));
3042 }
3043
3044 sres_cache_clean(res->res_cache, res->res_now);
3045}
3046
3047/** Resend DNS query, report error if cannot resend any more.
3048 *
3049 * @param res resolver object
3050 * @param q query object
3051 * @param timeout true if resent because of timeout
3052 * (false if because icmp error report)
3053 */
3054static void
3055sres_resend_dns_query(sres_resolver_t *res, sres_query_t *q, int timeout)
3056{
3057 uint8_t i, N;
3058 sres_server_t *dns;
3059
3060 SU_DEBUG_9(("sres_resend_dns_query(%p, %p, %s) called\n",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3061, "sres_resend_dns_query(%p, %p, %s) called\n"
, (void *)res, (void *)q, timeout ? "timeout" : "error")) : (
void)0)
3061 (void *)res, (void *)q, timeout ? "timeout" : "error"))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3061, "sres_resend_dns_query(%p, %p, %s) called\n"
, (void *)res, (void *)q, timeout ? "timeout" : "error")) : (
void)0)
;
3062
3063 N = res->res_n_servers;
3064
3065 if (N > 0 && q->q_retry_count < SRES_MAX_RETRY_COUNT(SRES_MAX_RETRY_COUNT)) {
3066 i = q->q_i_server;
3067 dns = sres_next_server(res, &i, timeout);
3068
3069 if (dns) {
3070 res->res_i_server = q->q_i_server = i;
3071
3072 if (q->q_retry_count > res->res_n_servers + 1 &&
3073 dns->dns_edns == edns_not_tried)
3074 q->q_edns = edns_not_supported;
3075
3076 sres_send_dns_query(res, q);
3077
3078 if (timeout)
3079 q->q_retry_count++;
3080
3081 return;
3082 }
3083 }
3084
3085 /* report timeout/network error */
3086 q->q_id = 0;
3087
3088 if (q->q_n_subs)
3089 return; /* let subqueries also timeout */
3090
3091 sres_query_report_error(q, NULL((void*)0));
3092}
3093
3094static void
3095sres_resolve_cname(sres_resolver_t *res,
3096 sres_query_t *orig_query,
3097 char const *cname)
3098{
3099 sres_query_t *query;
3100
3101 query = sres_query_alloc(res,
3102 sres_resolving_cname,
3103 (sres_context_t *)orig_query,
3104 orig_query->q_type,
3105 cname);
3106
3107 if (query)
3108 sres_send_dns_query(res, query);
3109 else
3110 sres_query_report_error(orig_query, NULL((void*)0));
3111}
3112
3113static void
3114sres_resolving_cname(sres_context_t *original_query,
3115 sres_query_t *query,
3116 sres_record_t **answers)
3117{
3118 sres_query_t *orig = (sres_query_t *)original_query;
3119
3120 /* Notify the listener */
3121 if (orig->q_callback != NULL((void*)0))
3122 (orig->q_callback)(orig->q_context, orig, answers);
3123
3124 sres_free_query(orig->q_res, orig);
3125}
3126
3127/** Get a server by socket */
3128static
3129sres_server_t *
3130sres_server_by_socket(sres_resolver_t const *res, sres_socket_t socket)
3131{
3132 int i;
3133
3134 if (socket == -1)
3135 return NULL((void*)0);
3136
3137 for (i = 0; i < res->res_n_servers; i++) {
3138 if (socket == res->res_servers[i]->dns_socket)
3139 return res->res_servers[i];
3140 }
3141
3142 return NULL((void*)0);
3143}
3144
3145static
3146void
3147sres_canonize_sockaddr(struct sockaddr_storage *from, socklen_t *fromlen)
3148{
3149#if HAVE_SIN61
3150 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)from;
3151
3152 size_t sin6_addrsize =
3153 offsetof(struct sockaddr_in6, sin6_addr)__builtin_offsetof(struct sockaddr_in6, sin6_addr) +
3154 (sizeof sin6->sin6_addr);
3155
3156 if (from->ss_family == AF_INET610) {
3157 struct in6_addr const *ip6 = &sin6->sin6_addr;
3158
3159 if (IN6_IS_ADDR_V4MAPPED(ip6)(__extension__ ({ const struct in6_addr *__a = (const struct in6_addr
*) (ip6); __a->__in6_u.__u6_addr32[0] == 0 && __a
->__in6_u.__u6_addr32[1] == 0 && __a->__in6_u.__u6_addr32
[2] == htonl (0xffff); }))
|| IN6_IS_ADDR_V4COMPAT(ip6)(__extension__ ({ const struct in6_addr *__a = (const struct in6_addr
*) (ip6); __a->__in6_u.__u6_addr32[0] == 0 && __a
->__in6_u.__u6_addr32[1] == 0 && __a->__in6_u.__u6_addr32
[2] == 0 && ntohl (__a->__in6_u.__u6_addr32[3]) >
1; }))
) {
3160 /* Convert to a IPv4 address */
3161 struct sockaddr_in *sin = (struct sockaddr_in *)from;
3162 memcpy(&sin->sin_addr, ip6->s6_addr__in6_u.__u6_addr8 + 12, sizeof sin->sin_addr);
3163 sin->sin_family = AF_INET2;
3164 *fromlen = sizeof (*sin);
3165#if HAVE_SA_LEN
3166 sin->sin_len = sizeof (*sin);
3167#endif
3168 }
3169 else if (sin6_addrsize < *fromlen) {
3170 /* Zero extra sin6 members like sin6_flowinfo or sin6_scope_id */
3171 memset((char *)from + sin6_addrsize, 0, *fromlen - sin6_addrsize);
3172 }
3173 }
3174#endif
3175
3176 if (from->ss_family == AF_INET2) {
3177 struct sockaddr_in *sin = (struct sockaddr_in *)from;
3178 memset(sin->sin_zero, 0, sizeof (sin->sin_zero));
3179 }
3180}
3181
3182static
3183int sres_no_update(sres_async_t *async,
3184 sres_socket_t new_socket,
3185 sres_socket_t old_socket)
3186{
3187 return 0;
3188}
3189
3190/** Create connected sockets for resolver.
3191 */
3192int sres_resolver_sockets(sres_resolver_t *res,
3193 sres_socket_t *return_sockets,
3194 int n)
3195{
3196 sres_socket_t s = INVALID_SOCKET((sres_socket_t)-1);
3197 int i, retval;
3198
3199 if (!sres_resolver_set_async(res, sres_no_update,
3200 (sres_async_t *)-1, 1))
3201 return -1;
3202
3203 retval = res->res_n_servers; assert(retval <= SRES_MAX_NAMESERVERS)((void) sizeof ((retval <= (SRES_MAX_NAMESERVERS)) ? 1 : 0
), __extension__ ({ if (retval <= (SRES_MAX_NAMESERVERS)) ;
else __assert_fail ("retval <= SRES_MAX_NAMESERVERS", "sres.c"
, 3203, __extension__ __PRETTY_FUNCTION__); }))
;
3204
3205 if (!return_sockets || n == 0)
3206 return retval;
3207
3208 for (i = 0; i < retval && i < n;) {
3209 sres_server_t *dns = res->res_servers[i];
3210
3211 s = sres_server_socket(res, dns);
3212
3213 if (s == INVALID_SOCKET((sres_socket_t)-1)) { /* Mark as a bad destination */
3214 dns->dns_icmp = SRES_TIME_MAX((time_t)9223372036854775807L);
3215 dns->dns_error = SRES_TIME_MAX((time_t)9223372036854775807L);
3216 }
3217
3218 return_sockets[i++] = s;
3219 }
3220
3221 return retval;
3222}
3223
3224#if 0
3225/** Get a server by socket address */
3226static
3227sres_server_t *
3228sres_server_by_sockaddr(sres_resolver_t const *res,
3229 void const *from, socklen_t fromlen)
3230{
3231 int i;
3232
3233 for (i = 0; i < res->res_n_servers; i++) {
3234 sres_server_t *dns = res->res_servers[i];
3235 if (dns->dns_addrlen == fromlen &&
3236 memcmp(dns->dns_addr, from, fromlen) == 0)
3237 return dns;
3238 }
3239
3240 return NULL((void*)0);
3241}
3242#endif
3243
3244/** Receive error message from socket. */
3245#if HAVE_IP_RECVERR1 || HAVE_IPV6_RECVERR1
3246int sres_resolver_error(sres_resolver_t *res, int socket)
3247{
3248 int errcode = 0;
3249 struct cmsghdr *c;
3250 struct sock_extended_err *ee;
3251 struct sockaddr_storage *from;
3252 char control[512];
3253 char errmsg[64 + 768];
3254 struct iovec iov[1];
3255 struct msghdr msg[1] = {{ 0 }};
3256 struct sockaddr_storage name[1] = {{ 0 }};
3257 int n;
3258 char info[128] = "";
3259
3260 SU_DEBUG_9(("%s(%p, %u) called\n", "sres_resolver_error",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3261, "%s(%p, %u) called\n", "sres_resolver_error"
, (void *)res, socket)) : (void)0)
3261 (void *)res, socket))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3261, "%s(%p, %u) called\n", "sres_resolver_error"
, (void *)res, socket)) : (void)0)
;
3262
3263 msg->msg_name = name, msg->msg_namelen = sizeof(name);
3264 msg->msg_iov = iov, msg->msg_iovlen = 1;
3265 iov->iov_base = errmsg, iov->iov_len = sizeof(errmsg);
3266 msg->msg_control = control, msg->msg_controllen = sizeof(control);
3267
3268 n = recvmsg(socket, msg, MSG_ERRQUEUEMSG_ERRQUEUE);
3269
3270 if (n < 0) {
3271 int error = su_errno();
3272 if (error != EAGAIN11 && error != EWOULDBLOCK11)
3273 SU_DEBUG_1(("%s: recvmsg: %s\n", __func__, su_strerror(error)))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 1 ? (_su_llog(sresolv_log, 1, "sres.c"
, (const char *)__func__, 3273, "%s: recvmsg: %s\n", __func__
, su_strerror(error))) : (void)0)
;
3274 return n;
3275 }
3276
3277 if ((msg->msg_flags & MSG_ERRQUEUEMSG_ERRQUEUE) != MSG_ERRQUEUEMSG_ERRQUEUE) {
3278 SU_DEBUG_1(("%s: recvmsg: no errqueue\n", __func__))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 1 ? (_su_llog(sresolv_log, 1, "sres.c"
, (const char *)__func__, 3278, "%s: recvmsg: no errqueue\n",
__func__)) : (void)0)
;
3279 return su_seterrno(EIO5);
3280 }
3281
3282 if (msg->msg_flags & MSG_CTRUNCMSG_CTRUNC) {
3283 SU_DEBUG_1(("%s: extended error was truncated\n", __func__))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 1 ? (_su_llog(sresolv_log, 1, "sres.c"
, (const char *)__func__, 3283, "%s: extended error was truncated\n"
, __func__)) : (void)0)
;
3284 return su_seterrno(EIO5);
3285 }
3286
3287 if (msg->msg_flags & MSG_TRUNCMSG_TRUNC) {
3288 /* ICMP message may contain original message... */
3289 SU_DEBUG_5(("%s: icmp(6) message was truncated (at %d)\n", __func__, n))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3289, "%s: icmp(6) message was truncated (at %d)\n"
, __func__, n)) : (void)0)
;
3290 }
3291
3292 /* Go through the ancillary data */
3293 for (c = CMSG_FIRSTHDR(msg)((size_t) (msg)->msg_controllen >= sizeof (struct cmsghdr
) ? (struct cmsghdr *) (msg)->msg_control : (struct cmsghdr
*) 0)
; c; c = CMSG_NXTHDR(msg, c)__cmsg_nxthdr (msg, c)) {
3294 if (0
3295#if HAVE_IP_RECVERR1
3296 || (c->cmsg_level == SOL_IP0 && c->cmsg_type == IP_RECVERR11)
3297#endif
3298#if HAVE_IPV6_RECVERR1
3299 || (c->cmsg_level == SOL_IPV641 && c->cmsg_type == IPV6_RECVERR25)
3300#endif
3301 ) {
3302 char const *origin;
3303
3304 ee = (struct sock_extended_err *)CMSG_DATA(c)((c)->__cmsg_data);
3305 from = (void *)SO_EE_OFFENDER(ee)((struct sockaddr*)((ee)+1));
3306 info[0] = '\0';
3307
3308 switch (ee->ee_origin) {
3309 case SO_EE_ORIGIN_LOCAL1:
3310 strcpy(info, origin = "local");
Although the value stored to 'origin' is used in the enclosing expression, the value is never actually read from 'origin'
3311 break;
3312 case SO_EE_ORIGIN_ICMP2:
3313 snprintf(info, sizeof(info), "%s type=%u code=%u",
3314 origin = "icmp", ee->ee_type, ee->ee_code);
3315 break;
3316 case SO_EE_ORIGIN_ICMP63:
3317 snprintf(info, sizeof(info), "%s type=%u code=%u",
3318 origin = "icmp6", ee->ee_type, ee->ee_code);
3319 break;
3320 case SO_EE_ORIGIN_NONE0:
3321 strcpy(info, origin = "none");
3322 break;
3323 default:
3324 strcpy(info, origin = "unknown");
3325 break;
3326 }
3327
3328 if (ee->ee_info)
3329 snprintf(info + strlen(info), sizeof(info) - strlen(info),
3330 " info=%08x", ee->ee_info);
3331 errcode = ee->ee_errno;
3332
3333 if (from->ss_family != AF_UNSPEC0) {
3334 socklen_t fromlen = ((char *)c + c->cmsg_len) - (char *)from;
3335
3336 sres_canonize_sockaddr(from, &fromlen);
3337
3338 snprintf(info + strlen(info), sizeof(info) - strlen(info),
3339 " reported by ");
3340 su_inet_ntopinet_ntop(from->ss_family, SS_ADDR(from)((from)->ss_family == 2 ? (void *)&((struct sockaddr_in
*)from)->sin_addr : ((from)->ss_family == 10 ? (void *
)&((struct sockaddr_in6 *)from)->sin6_addr : (void *)&
((struct sockaddr *)from)->sa_data))
,
3341 info + strlen(info), sizeof(info) - strlen(info));
3342 }
3343
3344 if (msg->msg_namelen <= 0)
3345 break;
3346
3347 {
3348 int error;
3349 socklen_t errorlen = sizeof error;
3350 /* Get error, if any */
3351 getsockopt(socket, SOL_SOCKET1, SO_ERROR4, (void *)&error, &errorlen);
3352 }
3353
3354 if (sres_resolver_report_error(res, socket, errcode,
3355 msg->msg_name, msg->msg_namelen,
3356 info))
3357 return errcode;
3358 break;
3359 }
3360 }
3361
3362 if (errcode)
3363 sres_resolver_report_error(res, socket, errcode, NULL((void*)0), 0, info);
3364
3365 return errcode;
3366}
3367
3368#else
3369int sres_resolver_error(sres_resolver_t *res, int socket)
3370{
3371 int errcode = 0;
3372 socklen_t errorlen = sizeof(errcode);
3373
3374 SU_DEBUG_9(("%s(%p, %u) called\n", "sres_resolver_error",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3375, "%s(%p, %u) called\n", "sres_resolver_error"
, (void *)res, socket)) : (void)0)
3375 (void *)res, socket))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3375, "%s(%p, %u) called\n", "sres_resolver_error"
, (void *)res, socket)) : (void)0)
;
3376
3377 getsockopt(socket, SOL_SOCKET1, SO_ERROR4, (void *)&errcode, &errorlen);
3378
3379 return sres_resolver_report_error(res, socket, errcode, NULL((void*)0), 0, "");
3380}
3381#endif
3382
3383
3384/** Report error */
3385static
3386int
3387sres_resolver_report_error(sres_resolver_t *res,
3388 sres_socket_t socket,
3389 int errcode,
3390 struct sockaddr_storage *remote,
3391 socklen_t remotelen,
3392 char const *info)
3393{
3394 char buf[80];
3395
3396 buf[0] = '\0';
3397
3398 if (remote) {
3399 sres_canonize_sockaddr(remote, &remotelen);
3400
3401 if (remote->ss_family == AF_INET2) {
3402 struct sockaddr_in const *sin = (struct sockaddr_in *)remote;
3403 uint8_t const *in_addr = (uint8_t*)&sin->sin_addr;
3404 su_inet_ntopinet_ntop(AF_INET2, in_addr, buf, sizeof(buf));
3405 }
3406#if HAVE_SIN61
3407 else if (remote->ss_family == AF_INET610) {
3408 struct sockaddr_in6 const *sin6 = (struct sockaddr_in6 *)remote;
3409 uint8_t const *in_addr = (uint8_t*)&sin6->sin6_addr;
3410 su_inet_ntopinet_ntop(AF_INET610, in_addr, buf, sizeof(buf));
3411 }
3412#endif
3413 }
3414
3415 SU_DEBUG_5(("sres: network error %u (%s)%s%s%s%s\n",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3419, "sres: network error %u (%s)%s%s%s%s\n"
, errcode, su_strerror(errcode), buf[0] ? " from " : "", buf,
info ? " by " : "", info ? info : "")) : (void)0)
3416 errcode, su_strerror(errcode),(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3419, "sres: network error %u (%s)%s%s%s%s\n"
, errcode, su_strerror(errcode), buf[0] ? " from " : "", buf,
info ? " by " : "", info ? info : "")) : (void)0)
3417 buf[0] ? " from " : "", buf,(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3419, "sres: network error %u (%s)%s%s%s%s\n"
, errcode, su_strerror(errcode), buf[0] ? " from " : "", buf,
info ? " by " : "", info ? info : "")) : (void)0)
3418 info ? " by " : "",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3419, "sres: network error %u (%s)%s%s%s%s\n"
, errcode, su_strerror(errcode), buf[0] ? " from " : "", buf,
info ? " by " : "", info ? info : "")) : (void)0)
3419 info ? info : ""))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3419, "sres: network error %u (%s)%s%s%s%s\n"
, errcode, su_strerror(errcode), buf[0] ? " from " : "", buf,
info ? " by " : "", info ? info : "")) : (void)0)
;
3420
3421 if (res->res_queries->qt_used) {
3422 /* Report error to queries */
3423 sres_server_t *dns;
3424 sres_query_t *q;
3425 size_t i;
3426
3427 dns = sres_server_by_socket(res, socket);
3428
3429 if (dns) {
3430 time(&res->res_now);
3431 dns->dns_icmp = res->res_now;
3432
3433 for (i = 0; i < res->res_queries->qt_size; i++) {
3434 q = res->res_queries->qt_table[i];
3435
3436 if (!q || dns != res->res_servers[q->q_i_server])
3437 continue;
3438
3439 /* Resend query/report error to application */
3440 sres_resend_dns_query(res, q, 0);
3441
3442 if (q != res->res_queries->qt_table[i])
3443 i--;
3444 }
3445 }
3446 }
3447
3448 return 1;
3449}
3450
3451
3452/** Receive a response packet from socket. */
3453int
3454sres_resolver_receive(sres_resolver_t *res, int socket)
3455{
3456 ssize_t num_bytes;
3457 int error;
3458 sres_message_t m[1];
3459
3460 sres_query_t *query = NULL((void*)0);
3461 sres_record_t **reply;
3462 sres_server_t *dns;
3463
3464 struct sockaddr_storage from[1] = {{0}};
3465 socklen_t fromlen = sizeof from;
3466
3467 SU_DEBUG_9(("%s(%p, %u) called\n", "sres_resolver_receive",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3468, "%s(%p, %u) called\n", "sres_resolver_receive"
, (void *)res, socket)) : (void)0)
3468 (void *)res, socket))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3468, "%s(%p, %u) called\n", "sres_resolver_receive"
, (void *)res, socket)) : (void)0)
;
3469
3470 memset(m, 0, offsetof(sres_message_t, m_data)__builtin_offsetof(sres_message_t, m_packet.mp_data));
3471
3472 num_bytes = sres_recvfrom(socket, m->m_data, sizeof (m->m_data), 0,recvfrom((socket),(m->m_packet.mp_data),(sizeof (m->m_packet
.mp_data)),(0),((void *)from),(&fromlen))
3473 (void *)from, &fromlen)recvfrom((socket),(m->m_packet.mp_data),(sizeof (m->m_packet
.mp_data)),(0),((void *)from),(&fromlen))
;
3474
3475 if (num_bytes <= 0) {
3476 SU_DEBUG_5(("%s: %s\n", "sres_resolver_receive", su_strerror(su_errno())))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3476, "%s: %s\n", "sres_resolver_receive"
, su_strerror(su_errno()))) : (void)0)
;
3477 return 0;
3478 }
3479
3480 if (num_bytes > 65535)
3481 num_bytes = 65535;
3482
3483 dns = sres_server_by_socket(res, socket);
3484 if (!dns)
3485 return 0;
3486
3487 m->m_size = (uint16_t)num_bytes;
3488
3489 /* Decode the received message and get the matching query object */
3490 error = sres_decode_msg(res, m, &query, &reply);
3491
3492 sres_log_response(res, m, from, query, reply);
3493
3494 if (query == NULL((void*)0))
3495 ;
3496 else if (error == SRES_EDNS0_ERR) {
3497 dns->dns_edns = edns_not_supported;
3498 assert(query->q_id)((void) sizeof ((query->q_id) ? 1 : 0), __extension__ ({ if
(query->q_id) ; else __assert_fail ("query->q_id", "sres.c"
, 3498, __extension__ __PRETTY_FUNCTION__); }))
;
3499 sres_remove_query(res, query, 0);
3500 sres_gen_id(res, query);
3501 sres_qtable_append(res->res_queries, query);
3502 sres_send_dns_query(res, query);
3503 query->q_retry_count++;
3504 }
3505 else if (!error && reply) {
3506 /* Remove the query from the pending list */
3507 sres_remove_query(res, query, 1);
3508
3509 /* Resolve the CNAME alias, if necessary */
3510 if (query->q_type != sres_type_cname && query->q_type != sres_qtype_any &&
3511 reply[0] && reply[0]->sr_typesr_record->r_type == sres_type_cname) {
3512 const char *alias = reply[0]->sr_cname[0].cn_cname;
3513 sres_record_t **cached = NULL((void*)0);
3514
3515 /* Check for the aliased results in the cache */
3516 if (sres_cache_get(res->res_cache, query->q_type, alias, &cached)
3517 > 0) {
3518 reply = cached;
3519 }
3520 else {
3521 /* Submit a query with the aliased name, dropping this result */
3522 sres_resolve_cname(res, query, alias);
3523 return 1;
3524 }
3525 }
3526
3527 /* Notify the listener */
3528 if (query->q_callback != NULL((void*)0))
3529 (query->q_callback)(query->q_context, query, reply);
3530
3531 sres_free_query(res, query);
3532 }
3533 else {
3534 sres_query_report_error(query, reply);
3535 }
3536
3537 return 1;
3538}
3539
3540static
3541void sres_log_response(sres_resolver_t const *res,
3542 sres_message_t const *m,
3543 struct sockaddr_storage const *from,
3544 sres_query_t const *query,
3545 sres_record_t * const *reply)
3546{
3547 if (SU_LOGsresolv_log->log_level >= 5) {
3548#ifndef ADDRSIZE48
3549#define ADDRSIZE48 48
3550#endif
3551 char host[ADDRSIZE48] = "*";
3552 uint16_t port = 0;
3553
3554 if (from == NULL((void*)0))
3555 ;
3556 else if (from->ss_family == AF_INET2) {
3557 struct sockaddr_in sin;
3558 memcpy(&sin, from, sizeof sin);
3559 su_inet_ntopinet_ntop(AF_INET2, &sin.sin_addr, host, sizeof host);
3560 port = sin.sin_port;
3561 }
3562#if HAVE_SIN61
3563 else if (from->ss_family == AF_INET610) {
3564 struct sockaddr_in6 sin6;
3565 memcpy(&sin6, from, sizeof sin6);
3566 su_inet_ntopinet_ntop(AF_INET610, &sin6.sin6_addr, host, sizeof host);
3567 port = sin6.sin6_port;
3568 }
3569#endif
3570
3571 SU_DEBUG_5(("sres_resolver_receive(%p, %p) id=%u (from [%s]:%u)\n",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3573, "sres_resolver_receive(%p, %p) id=%u (from [%s]:%u)\n"
, (void *)res, (void *)query, m->m_packet.mp_header.mh_id,
host, ntohs(port))) : (void)0)
3572 (void *)res, (void *)query, m->m_id,(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3573, "sres_resolver_receive(%p, %p) id=%u (from [%s]:%u)\n"
, (void *)res, (void *)query, m->m_packet.mp_header.mh_id,
host, ntohs(port))) : (void)0)
3573 host, ntohs(port)))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3573, "sres_resolver_receive(%p, %p) id=%u (from [%s]:%u)\n"
, (void *)res, (void *)query, m->m_packet.mp_header.mh_id,
host, ntohs(port))) : (void)0)
;
3574 }
3575}
3576
3577/** Decode DNS message.
3578 *
3579 *
3580 * @retval 0 if successful
3581 * @retval >0 if message indicated error
3582 * @retval -1 if decoding error
3583 */
3584static
3585int
3586sres_decode_msg(sres_resolver_t *res,
3587 sres_message_t *m,
3588 sres_query_t **qq,
3589 sres_record_t ***return_answers)
3590{
3591 sres_record_t *rr = NULL((void*)0), **answers = NULL((void*)0), *error = NULL((void*)0);
3592 sres_query_t *query = NULL((void*)0), **hq;
3593 su_home_t *chome;
3594 hash_value_t hash;
3595 int err;
3596 unsigned i, total, errorcount = 0;
3597
3598 assert(res && m && return_answers)((void) sizeof ((res && m && return_answers) ?
1 : 0), __extension__ ({ if (res && m && return_answers
) ; else __assert_fail ("res && m && return_answers"
, "sres.c", 3598, __extension__ __PRETTY_FUNCTION__); }))
;
3599
3600 time(&res->res_now);
3601 chome = CHOME(res->res_cache)((su_home_t *)(res->res_cache));
3602
3603 *qq = NULL((void*)0);
3604 *return_answers = NULL((void*)0);
3605
3606 m->m_offset = sizeof(m->m_packet.mp_header);
3607
3608 if (m->m_size < m->m_offset) {
3609 SU_DEBUG_5(("sres_decode_msg: truncated message\n" VA_NONE))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3609, "sres_decode_msg: truncated message\n"
"%s", "")) : (void)0)
;
3610 return -1;
3611 }
3612
3613 m->m_flagsm_packet.mp_header.mh_flags = ntohs(m->m_flagsm_packet.mp_header.mh_flags);
3614 m->m_qdcountm_packet.mp_header.mh_qdcount = ntohs(m->m_qdcountm_packet.mp_header.mh_qdcount);
3615 m->m_ancountm_packet.mp_header.mh_ancount = ntohs(m->m_ancountm_packet.mp_header.mh_ancount);
3616 m->m_nscountm_packet.mp_header.mh_nscount = ntohs(m->m_nscountm_packet.mp_header.mh_nscount);
3617 m->m_arcountm_packet.mp_header.mh_arcount = ntohs(m->m_arcountm_packet.mp_header.mh_arcount);
3618
3619 hash = Q_PRIME3571 * m->m_idm_packet.mp_header.mh_id;
3620
3621 /* Search for query with this ID */
3622 for (hq = sres_qtable_hash(res->res_queries, hash);
3623 *hq;
3624 hq = sres_qtable_next(res->res_queries, hq))
3625 if (hash == (*hq)->q_hash)
3626 break;
3627
3628 *qq = query = *hq;
3629
3630 if (!query) {
3631 SU_DEBUG_5(("sres_decode_msg: matching query for id=%u\n", m->m_id))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3631, "sres_decode_msg: matching query for id=%u\n"
, m->m_packet.mp_header.mh_id)) : (void)0)
;
3632 return -1;
3633 }
3634
3635 assert(query && m->m_id == query->q_id)((void) sizeof ((query && m->m_packet.mp_header.mh_id
== query->q_id) ? 1 : 0), __extension__ ({ if (query &&
m->m_packet.mp_header.mh_id == query->q_id) ; else __assert_fail
("query && m->m_id == query->q_id", "sres.c", 3635
, __extension__ __PRETTY_FUNCTION__); }))
;
3636
3637 if ((m->m_flagsm_packet.mp_header.mh_flags & 15) == SRES_FORMAT_ERR && query->q_edns)
3638 return SRES_EDNS0_ERR;
3639
3640 /* Scan question section.
3641 * XXX: never mind the useless result values, this is done
3642 * for the side effects in m */
3643 for (i = 0; i < m->m_qdcountm_packet.mp_header.mh_qdcount; i++) {
3644 char name[1024];
3645 uint16_t qtype, qclass;
3646 m_get_domain(name, sizeof(name), m, 0); /* Query domain */
3647 qtype = m_get_uint16(m); /* Query type */
3648 qclass = m_get_uint16(m); /* Query class */
3649 if (qtype && qclass) {
3650 /* XXX: never mind these useless check, this is done to make compiler happy about unused value */
3651 }
3652
3653 }
3654
3655 if (m->m_error) {
3656 SU_DEBUG_5(("sres_decode_msg: %s\n", m->m_error))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3656, "sres_decode_msg: %s\n", m->
m_error)) : (void)0)
;
3657 return -1;
3658 }
3659
3660 err = m->m_flagsm_packet.mp_header.mh_flags & SRES_HDR_RCODE;
3661
3662 if (m->m_ancountm_packet.mp_header.mh_ancount == 0 && err == 0)
3663 err = SRES_RECORD_ERR;
3664
3665 if (err == SRES_RECORD_ERR ||
3666 err == SRES_NAME_ERR ||
3667 err == SRES_UNIMPL_ERR ||
3668 err == SRES_AUTH_ERR)
3669 errorcount = 1;
3670
3671 total = errorcount + m->m_ancountm_packet.mp_header.mh_ancount + m->m_nscountm_packet.mp_header.mh_nscount + m->m_arcountm_packet.mp_header.mh_arcount;
3672
3673 answers = su_zalloc(chome, (total + 2) * sizeof answers[0]);
3674 if (!answers)
3675 return -1;
3676
3677 /* Scan resource records */
3678 for (i = 0; i < total; i++) {
3679 if (i < errorcount)
3680 rr = error = sres_create_error_rr(res->res_cache, query, err);
3681 else
3682 rr = sres_create_record(res, m, i - errorcount);
3683
3684 if (!rr) {
3685 SU_DEBUG_5(("sres_create_record: %s\n", m->m_error))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3685, "sres_create_record: %s\n", m
->m_error)) : (void)0)
;
3686 break;
3687 }
3688
3689 if (error && rr->sr_typesr_record->r_type == sres_type_soa) {
3690 sres_soa_record_t *soa = (sres_soa_record_t *)rr;
3691 if (error->sr_ttlsr_record->r_ttl > soa->soa_minimum && soa->soa_minimum > 10)
3692 error->sr_ttlsr_record->r_ttl = soa->soa_minimum;
3693 }
3694
3695 answers[i] = rr;
3696 }
3697
3698 if (i < total) {
3699 SU_DEBUG_5(("sres_decode_msg: got %u but expected "(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3701, "sres_decode_msg: got %u but expected "
"errors=%u an=%u ar=%u ns=%u\n", i, errorcount, m->m_packet
.mp_header.mh_ancount, m->m_packet.mp_header.mh_arcount, m
->m_packet.mp_header.mh_nscount)) : (void)0)
3700 "errors=%u an=%u ar=%u ns=%u\n", i, errorcount,(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3701, "sres_decode_msg: got %u but expected "
"errors=%u an=%u ar=%u ns=%u\n", i, errorcount, m->m_packet
.mp_header.mh_ancount, m->m_packet.mp_header.mh_arcount, m
->m_packet.mp_header.mh_nscount)) : (void)0)
3701 m->m_ancount, m->m_arcount, m->m_nscount))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3701, "sres_decode_msg: got %u but expected "
"errors=%u an=%u ar=%u ns=%u\n", i, errorcount, m->m_packet
.mp_header.mh_ancount, m->m_packet.mp_header.mh_arcount, m
->m_packet.mp_header.mh_nscount)) : (void)0)
;
3702 for (i = 0; i < total; i++)
3703 sres_cache_free_record(res->res_cache, answers[i]);
3704 su_free(chome, answers);
3705 return -1;
3706 }
3707
3708 if (m->m_ancountm_packet.mp_header.mh_ancount > 0 && errorcount == 0 && query->q_type < sres_qtype_tsig
3709 && (query->q_callback == sres_resolving_cname ||
3710 answers[0]->sr_typesr_record->r_type != sres_type_cname)) {
3711
3712 for (i = 0; i < m->m_ancountm_packet.mp_header.mh_ancount; i++) {
3713 if (query->q_type == answers[i]->sr_typesr_record->r_type)
3714 break;
3715 }
3716
3717 if (i == m->m_ancountm_packet.mp_header.mh_ancount) {
3718 char b0[8], b1[8];
3719 /* The queried request was not found */
3720 SU_DEBUG_5(("sres_decode_msg: sent query %s, got %s\n",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3722, "sres_decode_msg: sent query %s, got %s\n"
, sres_record_type(query->q_type, b0), sres_record_type(answers
[0]->sr_record->r_type, b1))) : (void)0)
3721 sres_record_type(query->q_type, b0),(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3722, "sres_decode_msg: sent query %s, got %s\n"
, sres_record_type(query->q_type, b0), sres_record_type(answers
[0]->sr_record->r_type, b1))) : (void)0)
3722 sres_record_type(answers[0]->sr_type, b1)))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3722, "sres_decode_msg: sent query %s, got %s\n"
, sres_record_type(query->q_type, b0), sres_record_type(answers
[0]->sr_record->r_type, b1))) : (void)0)
;
3723 rr = sres_create_error_rr(res->res_cache, query, err = SRES_RECORD_ERR);
3724 memmove(answers + 1, answers, (sizeof answers[0]) * total++);
3725 answers[0] = rr;
3726 errorcount = 1;
3727 }
3728 }
3729
3730 for (i = 0; i < total; i++) {
3731 rr = answers[i];
3732
3733 if (i < m->m_ancountm_packet.mp_header.mh_ancount + errorcount)
3734 /* Increase reference count of entry passed in answers */
3735 rr->sr_refcountsr_record->r_refcount++;
3736 else
3737 /* Do not pass extra records to user */
3738 answers[i] = NULL((void*)0);
3739
3740 sres_cache_store(res->res_cache, rr, res->res_now);
3741 }
3742
3743 *return_answers = answers;
3744
3745 return err;
3746}
3747
3748static
3749sres_record_t *
3750sres_create_record(sres_resolver_t *res, sres_message_t *m, int nth)
3751{
3752 sres_cache_t *cache = res->res_cache;
3753 sres_record_t *sr, sr0[1];
3754
3755 uint16_t m_size;
3756 char name[1025];
3757 unsigned len;
3758 char btype[8], bclass[8];
3759
3760 sr = memset(sr0, 0, sizeof sr0);
3761
3762 len = m_get_domain(sr->sr_namesr_record->r_name = name, sizeof(name) - 1, m, 0); /* Name */
3763 sr->sr_typesr_record->r_type = m_get_uint16(m); /* Type */
3764 sr->sr_classsr_record->r_class = m_get_uint16(m); /* Class */
3765 sr->sr_ttlsr_record->r_ttl = m_get_uint32(m); /* TTL */
3766 sr->sr_rdlensr_record->r_rdlen = m_get_uint16(m); /* rdlength */
3767 sr->sr_parsedsr_record->r_parsed = 1;
3768 if (m->m_error)
3769 goto error;
3770 if (len >= (sizeof name)) {
3771 m->m_error = "too long domain name in record";
3772 goto error;
3773 }
3774 name[len] = 0;
3775
3776 SU_DEBUG_9(("%s RR received %s %s %s %d rdlen=%d\n",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3783, "%s RR received %s %s %s %d rdlen=%d\n"
, nth < m->m_packet.mp_header.mh_ancount ? "ANSWER" : nth
< m->m_packet.mp_header.mh_ancount + m->m_packet.mp_header
.mh_nscount ? "AUTHORITY" : "ADDITIONAL", name, sres_record_type
(sr->sr_record->r_type, btype), sres_record_class(sr->
sr_record->r_class, bclass), sr->sr_record->r_ttl, sr
->sr_record->r_rdlen)) : (void)0)
3777 nth < m->m_ancount ? "ANSWER" :(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3783, "%s RR received %s %s %s %d rdlen=%d\n"
, nth < m->m_packet.mp_header.mh_ancount ? "ANSWER" : nth
< m->m_packet.mp_header.mh_ancount + m->m_packet.mp_header
.mh_nscount ? "AUTHORITY" : "ADDITIONAL", name, sres_record_type
(sr->sr_record->r_type, btype), sres_record_class(sr->
sr_record->r_class, bclass), sr->sr_record->r_ttl, sr
->sr_record->r_rdlen)) : (void)0)
3778 nth < m->m_ancount + m->m_nscount ? "AUTHORITY" :(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3783, "%s RR received %s %s %s %d rdlen=%d\n"
, nth < m->m_packet.mp_header.mh_ancount ? "ANSWER" : nth
< m->m_packet.mp_header.mh_ancount + m->m_packet.mp_header
.mh_nscount ? "AUTHORITY" : "ADDITIONAL", name, sres_record_type
(sr->sr_record->r_type, btype), sres_record_class(sr->
sr_record->r_class, bclass), sr->sr_record->r_ttl, sr
->sr_record->r_rdlen)) : (void)0)
3779 "ADDITIONAL",(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3783, "%s RR received %s %s %s %d rdlen=%d\n"
, nth < m->m_packet.mp_header.mh_ancount ? "ANSWER" : nth
< m->m_packet.mp_header.mh_ancount + m->m_packet.mp_header
.mh_nscount ? "AUTHORITY" : "ADDITIONAL", name, sres_record_type
(sr->sr_record->r_type, btype), sres_record_class(sr->
sr_record->r_class, bclass), sr->sr_record->r_ttl, sr
->sr_record->r_rdlen)) : (void)0)
3780 name,(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3783, "%s RR received %s %s %s %d rdlen=%d\n"
, nth < m->m_packet.mp_header.mh_ancount ? "ANSWER" : nth
< m->m_packet.mp_header.mh_ancount + m->m_packet.mp_header
.mh_nscount ? "AUTHORITY" : "ADDITIONAL", name, sres_record_type
(sr->sr_record->r_type, btype), sres_record_class(sr->
sr_record->r_class, bclass), sr->sr_record->r_ttl, sr
->sr_record->r_rdlen)) : (void)0)
3781 sres_record_type(sr->sr_type, btype),(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3783, "%s RR received %s %s %s %d rdlen=%d\n"
, nth < m->m_packet.mp_header.mh_ancount ? "ANSWER" : nth
< m->m_packet.mp_header.mh_ancount + m->m_packet.mp_header
.mh_nscount ? "AUTHORITY" : "ADDITIONAL", name, sres_record_type
(sr->sr_record->r_type, btype), sres_record_class(sr->
sr_record->r_class, bclass), sr->sr_record->r_ttl, sr
->sr_record->r_rdlen)) : (void)0)
3782 sres_record_class(sr->sr_class, bclass),(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3783, "%s RR received %s %s %s %d rdlen=%d\n"
, nth < m->m_packet.mp_header.mh_ancount ? "ANSWER" : nth
< m->m_packet.mp_header.mh_ancount + m->m_packet.mp_header
.mh_nscount ? "AUTHORITY" : "ADDITIONAL", name, sres_record_type
(sr->sr_record->r_type, btype), sres_record_class(sr->
sr_record->r_class, bclass), sr->sr_record->r_ttl, sr
->sr_record->r_rdlen)) : (void)0)
3783 sr->sr_ttl, sr->sr_rdlen))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 9 ? (_su_llog(sresolv_log, 9, "sres.c"
, (const char *)__func__, 3783, "%s RR received %s %s %s %d rdlen=%d\n"
, nth < m->m_packet.mp_header.mh_ancount ? "ANSWER" : nth
< m->m_packet.mp_header.mh_ancount + m->m_packet.mp_header
.mh_nscount ? "AUTHORITY" : "ADDITIONAL", name, sres_record_type
(sr->sr_record->r_type, btype), sres_record_class(sr->
sr_record->r_class, bclass), sr->sr_record->r_ttl, sr
->sr_record->r_rdlen)) : (void)0)
;
3784
3785 if (m->m_offset + sr->sr_rdlensr_record->r_rdlen > m->m_size) {
3786 m->m_error = "truncated message";
3787 goto error;
3788 }
3789
3790 m_size = m->m_size;
3791 /* limit m_size to indicated rdlen, check whether record is truncated */
3792 m->m_size = m->m_offset + sr->sr_rdlensr_record->r_rdlen;
3793
3794 switch (sr->sr_typesr_record->r_type) {
3795 case sres_type_soa:
3796 sr = sres_init_rr_soa(cache, sr->sr_soa, m);
3797 break;
3798 case sres_type_a:
3799 sr = sres_init_rr_a(cache, sr->sr_a, m);
3800 break;
3801 case sres_type_a6:
3802 sr = sres_init_rr_a6(cache, sr->sr_a6, m);
3803 break;
3804 case sres_type_aaaa:
3805 sr = sres_init_rr_aaaa(cache, sr->sr_aaaa, m);
3806 break;
3807 case sres_type_cname:
3808 sr = sres_init_rr_cname(cache, sr->sr_cname, m);
3809 break;
3810 case sres_type_ptr:
3811 sr = sres_init_rr_ptr(cache, sr->sr_ptr, m);
3812 break;
3813 case sres_type_srv:
3814 sr = sres_init_rr_srv(cache, sr->sr_srv, m);
3815 break;
3816 case sres_type_naptr:
3817 sr = sres_init_rr_naptr(cache, sr->sr_naptr, m);
3818 break;
3819 default:
3820 sr = sres_init_rr_unknown(cache, sr->sr_record, m);
3821 break;
3822 }
3823
3824 if (m->m_error)
3825 goto error;
3826
3827 if (sr == sr0)
3828 sr = sres_cache_alloc_record(cache, sr, 0);
3829
3830 if (sr == NULL((void*)0)) {
3831 m->m_error = "memory exhausted";
3832 goto error;
3833 }
3834
3835 /* Fill in the common fields */
3836 m->m_size = m_size;
3837
3838 return sr;
3839
3840 error:
3841 if (sr && sr != sr0)
3842 sres_cache_free_record(cache, sr);
3843 SU_DEBUG_5(("%s: %s\n", "sres_create_record", m->m_error))(((sresolv_log != ((void*)0) && sresolv_log->log_init
) == 0 ? 9 : ((sresolv_log != ((void*)0) && sresolv_log
->log_init > 1) ? sresolv_log->log_level : su_log_default
->log_level)) >= 5 ? (_su_llog(sresolv_log, 5, "sres.c"
, (const char *)__func__, 3843, "%s: %s\n", "sres_create_record"
, m->m_error)) : (void)0)
;
3844 return NULL((void*)0);
3845}
3846
3847/** Decode SOA record */
3848static sres_record_t *sres_init_rr_soa(sres_cache_t *cache,
3849 sres_soa_record_t *soa,
3850 sres_message_t *m)
3851{
3852 uint16_t moffset, roffset;
3853 unsigned mnamelen, rnamelen;
3854
3855 soa->soa_record->r_size = sizeof *soa;
3856
3857 moffset = m->m_offset, mnamelen = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
3858 roffset = m->m_offset, rnamelen = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
3859
3860 soa->soa_serial = m_get_uint32(m);
3861 soa->soa_refresh = m_get_uint32(m);
3862 soa->soa_retry = m_get_uint32(m);
3863 soa->soa_expire = m_get_uint32(m);
3864 soa->soa_minimum = m_get_uint32(m);
3865
3866 if (m->m_error)
3867 return NULL((void*)0);
3868
3869 soa = (void *)sres_cache_alloc_record(cache, (void *)soa,
3870 mnamelen + rnamelen);
3871
3872 if (soa) {
3873 char *mname, *rname;
3874
3875 assert(moffset > 0 && roffset > 0 && mnamelen > 1 && rnamelen > 1)((void) sizeof ((moffset > 0 && roffset > 0 &&
mnamelen > 1 && rnamelen > 1) ? 1 : 0), __extension__
({ if (moffset > 0 && roffset > 0 && mnamelen
> 1 && rnamelen > 1) ; else __assert_fail ("moffset > 0 && roffset > 0 && mnamelen > 1 && rnamelen > 1"
, "sres.c", 3875, __extension__ __PRETTY_FUNCTION__); }))
;
3876
3877 m_get_domain(mname = (char *)(soa + 1), mnamelen, m, moffset);
3878 soa->soa_mname = mname;
3879
3880 m_get_domain(rname = mname + mnamelen, rnamelen, m, roffset);
3881 soa->soa_rname = rname;
3882 }
3883
3884 return (sres_record_t *)soa;
3885}
3886
3887/** Decode A record */
3888static sres_record_t *sres_init_rr_a(sres_cache_t *cache,
3889 sres_a_record_t *a,
3890 sres_message_t *m)
3891{
3892 a->a_record->r_size = sizeof *a;
3893
3894 a->a_addr.s_addr = htonl(m_get_uint32(m));
3895
3896 return (sres_record_t *)a;
3897}
3898
3899/** Decode A6 record. See @RFC2874 */
3900static sres_record_t *sres_init_rr_a6(sres_cache_t *cache,
3901 sres_a6_record_t *a6,
3902 sres_message_t *m)
3903{
3904
3905 unsigned suffixlen = 0, i;
3906 unsigned prefixlen = 0;
3907 uint16_t offset;
3908
3909 a6->a6_record->r_size = sizeof *a6;
3910
3911 a6->a6_prelen = m_get_uint8(m);
3912
3913 if (a6->a6_prelen > 128) {
3914 m->m_error = "Invalid prefix length in A6 record";
3915 return NULL((void*)0);
3916 }
3917
3918 suffixlen = (128 + 7 - a6->a6_prelen) / 8;
3919 for (i = 16 - suffixlen; i < 16; i++)
3920 a6->a6_suffix.u6_addr[i] = m_get_uint8(m);
3921
3922 if (a6->a6_prelen > 0) {
3923 if (suffixlen > 0)
3924 /* Zero pad bits */
3925 a6->a6_suffix.u6_addr[16 - suffixlen] &= 0xff >> (a6->a6_prelen & 7);
3926
3927 offset = m->m_offset, prefixlen = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
3928
3929 if (m->m_error)
3930 return NULL((void*)0);
3931
3932 a6 = (void *)sres_cache_alloc_record(cache, (void *)a6, prefixlen);
3933 if (a6)
3934 m_get_domain(a6->a6_prename = (char *)(a6 + 1), prefixlen, m, offset);
3935 }
3936
3937 return (sres_record_t *)a6;
3938}
3939
3940/** Decode AAAA record */
3941static sres_record_t *sres_init_rr_aaaa(sres_cache_t *cache,
3942 sres_aaaa_record_t *aaaa,
3943 sres_message_t *m)
3944{
3945 aaaa->aaaa_record->r_size = sizeof *aaaa;
3946
3947 if (m->m_offset + sizeof(aaaa->aaaa_addr) <= m->m_size) {
3948 memcpy(&aaaa->aaaa_addr, m->m_datam_packet.mp_data + m->m_offset, sizeof(aaaa->aaaa_addr));
3949 m->m_offset += sizeof(aaaa->aaaa_addr);
3950 }
3951 else
3952 m->m_error = "truncated AAAA record";
3953
3954 return (sres_record_t *)aaaa;
3955}
3956
3957/** Decode CNAME record */
3958static sres_record_t *sres_init_rr_cname(sres_cache_t *cache,
3959 sres_cname_record_t *cn,
3960 sres_message_t *m)
3961{
3962 uint16_t offset;
3963 unsigned dlen;
3964
3965 cn->cn_record->r_size = sizeof *cn;
3966
3967 offset = m->m_offset, dlen = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
3968
3969 if (m->m_error)
3970 return NULL((void*)0);
3971
3972 cn = (void *)sres_cache_alloc_record(cache, (void *)cn, dlen);
3973 if (cn)
3974 m_get_domain(cn->cn_cname = (char *)(cn + 1), dlen, m, offset);
3975
3976 return (sres_record_t *)cn;
3977}
3978
3979/** Decode PTR record */
3980static sres_record_t *sres_init_rr_ptr(sres_cache_t *cache,
3981 sres_ptr_record_t *ptr,
3982 sres_message_t *m)
3983{
3984 uint16_t offset;
3985 unsigned dlen;
3986
3987 ptr->ptr_record->r_size = sizeof *ptr;
3988
3989 offset = m->m_offset, dlen = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
3990
3991 if (m->m_error)
3992 return NULL((void*)0);
3993
3994 ptr = (void *)sres_cache_alloc_record(cache, (void *)ptr, dlen);
3995 if (ptr)
3996 m_get_domain(ptr->ptr_domain = (char *)(ptr + 1), dlen, m, offset);
3997
3998 return (sres_record_t *)ptr;
3999}
4000
4001/** Decode SRV record */
4002static sres_record_t *sres_init_rr_srv(sres_cache_t *cache,
4003 sres_srv_record_t *srv,
4004 sres_message_t *m)
4005{
4006 uint16_t offset;
4007 unsigned dlen;
4008
4009 srv->srv_record->r_size = sizeof *srv;
4010
4011 srv->srv_priority = m_get_uint16(m);
4012 srv->srv_weight = m_get_uint16(m);
4013 srv->srv_port = m_get_uint16(m);
4014 offset = m->m_offset, dlen = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
4015 if (m->m_error)
4016 return NULL((void*)0);
4017
4018 srv = (void *)sres_cache_alloc_record(cache, (void *)srv, dlen);
4019 if (srv)
4020 m_get_domain(srv->srv_target = (char *)(srv + 1), dlen, m, offset);
4021
4022 return (sres_record_t *)srv;
4023}
4024
4025/** Decode NAPTR record */
4026static sres_record_t *sres_init_rr_naptr(sres_cache_t *cache,
4027 sres_naptr_record_t *na,
4028 sres_message_t *m)
4029{
4030 uint16_t offset[4];
4031 unsigned len[4];
4032
4033 na->na_record->r_size = sizeof *na;
4034
4035 na->na_order = m_get_uint16(m);
4036 na->na_prefer = m_get_uint16(m);
4037
4038 offset[0] = m->m_offset, len[0] = m_get_string(NULL((void*)0), 0, m, 0) + 1;
4039 offset[1] = m->m_offset, len[1] = m_get_string(NULL((void*)0), 0, m, 0) + 1;
4040 offset[2] = m->m_offset, len[2] = m_get_string(NULL((void*)0), 0, m, 0) + 1;
4041 offset[3] = m->m_offset, len[3] = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
4042
4043 if (m->m_error)
4044 return NULL((void*)0);
4045
4046 na = (void *)sres_cache_alloc_record(cache, (void *)na,
4047 len[0] + len[1] + len[2] + len[3]);
4048 if (na) {
4049 char *s = (char *)(na + 1);
4050 m_get_string(na->na_flags = s, len[0], m, offset[0]), s += len[0];
4051 m_get_string(na->na_services = s, len[1], m, offset[1]), s += len[1];
4052 m_get_string(na->na_regexp = s, len[2], m, offset[2]), s += len[2];
4053 m_get_domain(na->na_replace = s, len[3], m, offset[3]), s += len[3];
4054 }
4055
4056 return (sres_record_t *)na;
4057}
4058
4059/** Decode unknown record */
4060static sres_record_t *sres_init_rr_unknown(sres_cache_t *cache,
4061 sres_common_t *r,
4062 sres_message_t *m)
4063{
4064 if (m->m_offset + r->r_rdlen > m->m_size)
4065 m->m_error = "truncated record";
4066
4067 if (m->m_error)
4068 return NULL((void*)0);
4069
4070 r->r_size = sizeof *r;
4071
4072 r = (void *)sres_cache_alloc_record(cache, (void *)r, r->r_rdlen + 1);
4073 if (r) {
4074 char *data = (char *)(r + 1);
4075
4076 r->r_parsed = 0;
4077
4078 memcpy(data, m->m_datam_packet.mp_data + m->m_offset, r->r_rdlen);
4079 m->m_offset += r->r_rdlen;
4080 data[r->r_rdlen] = 0;
4081 }
4082
4083 return (sres_record_t *)r;
4084}
4085
4086static
4087sres_record_t *sres_create_error_rr(sres_cache_t *cache,
4088 sres_query_t const *q,
4089 uint16_t errcode)
4090{
4091 sres_record_t *sr, r[1];
4092 char buf[SRES_MAXDNAME(SRES_MAXDNAME)];
4093
4094 sr = memset(r, 0, sizeof *sr);
4095
4096 sr->sr_namesr_record->r_name = (char *)sres_toplevel(buf, sizeof buf, q->q_name);
4097 sr->sr_sizesr_record->r_size = sizeof *sr;
4098 sr->sr_statussr_record->r_status = errcode;
4099 sr->sr_typesr_record->r_type = q->q_type;
4100 sr->sr_classsr_record->r_class = q->q_class;
4101 sr->sr_ttlsr_record->r_ttl = 10 * 60;
4102
4103 return sres_cache_alloc_record(cache, sr, 0);
4104}
4105
4106/* Message processing primitives */
4107
4108static
4109void
4110m_put_uint16(sres_message_t *m,
4111 uint16_t h)
4112{
4113 uint8_t *p;
4114
4115 if (m->m_error)
4116 return;
4117
4118 p = m->m_datam_packet.mp_data + m->m_offset;
4119 m->m_offset += sizeof h;
4120
4121 if (m->m_offset > m->m_size) {
4122 m->m_error = "message size overflow";
4123 return;
4124 }
4125
4126 p[0] = h >> 8; p[1] = h;
4127}
4128
4129static
4130void
4131m_put_uint32(sres_message_t *m,
4132 uint32_t w)
4133{
4134 uint8_t *p;
4135
4136 if (m->m_error)
4137 return;
4138
4139 p = m->m_datam_packet.mp_data + m->m_offset;
4140 m->m_offset += sizeof w;
4141
4142 if (m->m_offset > m->m_size) {
4143 m->m_error = "message size overflow";
4144 return;
4145 }
4146
4147 p[0] = w >> 24; p[1] = w >> 16; p[2] = w >> 8; p[3] = w;
4148}
4149
4150/*
4151 * Put domain into query
4152 */
4153static
4154uint16_t
4155m_put_domain(sres_message_t *m,
4156 char const *domain,
4157 uint16_t top,
4158 char const *topdomain)
4159{
4160 char const *label;
4161 size_t llen;
4162
4163 if (m->m_error)
4164 return top;
4165
4166 /* Copy domain into query label at a time */
4167 for (label = domain; label && label[0]; label += llen) {
4168 if (label[0] == '.' && label[1] != '\0') {
4169 m->m_error = "empty label";
4170 return 0;
4171 }
4172
4173 llen = strcspn(label, ".");
4174
4175 if (llen >= 64) {
4176 m->m_error = "too long label";
4177 return 0;
4178 }
4179 if (m->m_offset + llen + 1 > m->m_size) {
4180 m->m_error = "message size overflow";
4181 return 0;
4182 }
4183
4184 m->m_datam_packet.mp_data[m->m_offset++] = (uint8_t)llen;
4185 memcpy(m->m_datam_packet.mp_data + m->m_offset, label, llen);
4186 m->m_offset += (uint8_t)llen;
4187
4188 if (label[llen] == '\0')
4189 break;
4190 if (llen == 0)
4191 return top;
4192 if (label[llen + 1])
4193 llen++;
4194 }
4195
4196 if (top) {
4197 m_put_uint16(m, 0xc000 | top);
4198 return top;
4199 }
4200 else if (topdomain) {
4201 uint16_t retval = m->m_offset;
4202 m_put_domain(m, topdomain, 0, NULL((void*)0));
4203 return retval;
4204 }
4205 else if (m->m_offset < m->m_size)
4206 m->m_datam_packet.mp_data[m->m_offset++] = '\0';
4207 else
4208 m->m_error = "message size overflow";
4209
4210 return 0;
4211}
4212
4213static
4214uint32_t
4215m_get_uint32(sres_message_t *m)
4216{
4217 uint8_t const *p = m->m_datam_packet.mp_data + m->m_offset;
4218
4219 if (m->m_error)
4220 return 0;
4221
4222 m->m_offset += 4;
4223
4224 if (m->m_offset > m->m_size) {
4225 m->m_error = "truncated message";
4226 return 0;
4227 }
4228
4229 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
4230}
4231
4232static
4233uint16_t
4234m_get_uint16(sres_message_t *m)
4235{
4236 uint8_t const *p = m->m_datam_packet.mp_data + m->m_offset;
4237
4238 if (m->m_error)
4239 return 0;
4240
4241 m->m_offset += 2;
4242
4243 if (m->m_offset > m->m_size) {
4244 m->m_error = "truncated message";
4245 return 0;
4246 }
4247
4248 return (p[0] << 8) | p[1];
4249}
4250
4251static
4252uint8_t
4253m_get_uint8(sres_message_t *m)
4254{
4255 uint8_t const *p = m->m_datam_packet.mp_data + m->m_offset;
4256
4257 if (m->m_error)
4258 return 0;
4259
4260 m->m_offset += 1;
4261
4262 if (m->m_offset > m->m_size) {
4263 m->m_error = "truncated message";
4264 return 0;
4265 }
4266
4267 return p[0];
4268}
4269
4270/**
4271 * Get a string.
4272 */
4273static unsigned
4274m_get_string(char *d,
4275 unsigned n,
4276 sres_message_t *m,
4277 uint16_t offset)
4278{
4279 uint8_t size;
4280 uint8_t *p = m->m_datam_packet.mp_data;
4281 int save_offset;
4282
4283 if (m->m_error)
4284 return 0;
4285
4286 if (offset == 0)
4287 offset = m->m_offset, save_offset = 1;
4288 else
4289 save_offset = 0;
4290
4291 size = p[offset++];
4292
4293 if (size + offset >= m->m_size) {
4294 m->m_error = "truncated message";
4295 return size;
4296 }
4297
4298 offset += size;
4299
4300 if (save_offset)
4301 m->m_offset = offset;
4302
4303 if (n == 0 || d == NULL((void*)0))
4304 return size; /* Just return the size (without NUL). */
4305
4306 memcpy(d, p + offset - size, size < n ? size : n);
4307
4308 if (size < n)
4309 d[size] = '\0'; /* NUL terminate */
4310
4311 return size;
4312}
4313
4314/**
4315 * Uncompress a domain.
4316 *
4317 * @param offset start uncompression from this point in message
4318 */
4319static unsigned
4320m_get_domain(char *d,
4321 unsigned n,
4322 sres_message_t *m,
4323 uint16_t offset)
4324{
4325 uint8_t cnt;
4326 unsigned i = 0;
4327 uint8_t *p = m->m_datam_packet.mp_data;
4328 uint16_t new_offset;
4329 int save_offset;
4330
4331 if (m->m_error)
4332 return 0;
4333
4334 if (d == NULL((void*)0))
4335 n = 0;
4336
4337 if (offset == 0)
4338 offset = m->m_offset, save_offset = 1;
4339 else
4340 save_offset = 0;
4341
4342 while ((cnt = p[offset++])) {
4343 if (cnt >= 0xc0) {
4344 if (offset >= m->m_size) {
4345 m->m_error = "truncated message";
4346 return 0;
4347 }
4348
4349 new_offset = ((cnt & 0x3F) << 8) + p[offset++];
4350
4351 if (save_offset)
4352 m->m_offset = offset;
4353
4354 if (new_offset <= 0 || new_offset >= m->m_size) {
4355 m->m_error = "invalid domain compression";
4356 return 0;
4357 }
4358
4359 offset = new_offset;
4360 save_offset = 0;
4361 }
4362 else {
4363 if (offset + cnt >= m->m_size) {
4364 m->m_error = "truncated message";
4365 return 0;
4366 }
4367 if (i + cnt + 1 < n) {
4368 memcpy(d + i, p + offset, cnt);
4369 d[i + cnt] = '.';
4370 }
4371
4372 i += cnt + 1;
4373 offset += cnt;
4374 }
4375 }
4376
4377 if (i == 0) {
4378 if (i < n)
4379 d[i] = '.';
4380 i++;
4381 }
4382
4383 if (i < n)
4384 d[i] = '\0';
4385
4386 if (save_offset)
4387 m->m_offset = offset;
4388
4389 return i;
4390}