Bug Summary

File:sresolv/sres.c
Warning:line 3839, column 3
Address of stack memory associated with local variable 'sr0' returned to caller

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -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-eagerly-assume -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 -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/llvm-7/lib/clang/7.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-7/lib/clang/7.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 -fmessage-length 0 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /drone/src/scan-build/2021-08-31-182631-364-1 -x c sres.c -faddrsig
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");
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) {
1
Assuming the condition is false
2
Taking false branch
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);
3
Loop condition is false. Execution continues on line 3628
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) {
4
Assuming 'query' is non-null
5
Taking false branch
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)
6
Assuming the condition is false
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++) {
7
Assuming the condition is false
8
Loop condition is false. Execution continues on line 3655
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) {
9
Assuming the condition is false
10
Taking false branch
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)
11
Assuming the condition is false
3663 err = SRES_RECORD_ERR;
3664
3665 if (err == SRES_RECORD_ERR ||
14
Taking false branch
3666 err == SRES_NAME_ERR ||
12
Assuming 'err' is not equal to SRES_NAME_ERR
3667 err == SRES_UNIMPL_ERR)
13
Assuming 'err' is not equal to SRES_UNIMPL_ERR
3668 errorcount = 1;
3669
3670 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;
3671
3672 answers = su_zalloc(chome, (total + 2) * sizeof answers[0]);
3673 if (!answers)
15
Assuming 'answers' is non-null
16
Taking false branch
3674 return -1;
3675
3676 /* Scan resource records */
3677 for (i = 0; i < total; i++) {
17
Assuming 'i' is < 'total'
18
Loop condition is true. Entering loop body
3678 if (i < errorcount)
19
Taking false branch
3679 rr = error = sres_create_error_rr(res->res_cache, query, err);
3680 else
3681 rr = sres_create_record(res, m, i - errorcount);
20
Calling 'sres_create_record'
3682
3683 if (!rr) {
3684 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__, 3684, "sres_create_record: %s\n", m
->m_error)) : (void)0)
;
3685 break;
3686 }
3687
3688 if (error && rr->sr_typesr_record->r_type == sres_type_soa) {
3689 sres_soa_record_t *soa = (sres_soa_record_t *)rr;
3690 if (error->sr_ttlsr_record->r_ttl > soa->soa_minimum && soa->soa_minimum > 10)
3691 error->sr_ttlsr_record->r_ttl = soa->soa_minimum;
3692 }
3693
3694 answers[i] = rr;
3695 }
3696
3697 if (i < total) {
3698 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__, 3700, "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)
3699 "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__, 3700, "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 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__, 3700, "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 for (i = 0; i < total; i++)
3702 sres_cache_free_record(res->res_cache, answers[i]);
3703 su_free(chome, answers);
3704 return -1;
3705 }
3706
3707 if (m->m_ancountm_packet.mp_header.mh_ancount > 0 && errorcount == 0 && query->q_type < sres_qtype_tsig
3708 && (query->q_callback == sres_resolving_cname ||
3709 answers[0]->sr_typesr_record->r_type != sres_type_cname)) {
3710
3711 for (i = 0; i < m->m_ancountm_packet.mp_header.mh_ancount; i++) {
3712 if (query->q_type == answers[i]->sr_typesr_record->r_type)
3713 break;
3714 }
3715
3716 if (i == m->m_ancountm_packet.mp_header.mh_ancount) {
3717 char b0[8], b1[8];
3718 /* The queried request was not found */
3719 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__, 3721, "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)
3720 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__, 3721, "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(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__, 3721, "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 rr = sres_create_error_rr(res->res_cache, query, err = SRES_RECORD_ERR);
3723 memmove(answers + 1, answers, (sizeof answers[0]) * total++);
3724 answers[0] = rr;
3725 errorcount = 1;
3726 }
3727 }
3728
3729 for (i = 0; i < total; i++) {
3730 rr = answers[i];
3731
3732 if (i < m->m_ancountm_packet.mp_header.mh_ancount + errorcount)
3733 /* Increase reference count of entry passed in answers */
3734 rr->sr_refcountsr_record->r_refcount++;
3735 else
3736 /* Do not pass extra records to user */
3737 answers[i] = NULL((void*)0);
3738
3739 sres_cache_store(res->res_cache, rr, res->res_now);
3740 }
3741
3742 *return_answers = answers;
3743
3744 return err;
3745}
3746
3747static
3748sres_record_t *
3749sres_create_record(sres_resolver_t *res, sres_message_t *m, int nth)
3750{
3751 sres_cache_t *cache = res->res_cache;
3752 sres_record_t *sr, sr0[1];
3753
3754 uint16_t m_size;
3755 char name[1025];
3756 unsigned len;
3757 char btype[8], bclass[8];
3758
3759 sr = memset(sr0, 0, sizeof sr0);
3760
3761 len = m_get_domain(sr->sr_namesr_record->r_name = name, sizeof(name) - 1, m, 0); /* Name */
3762 sr->sr_typesr_record->r_type = m_get_uint16(m); /* Type */
3763 sr->sr_classsr_record->r_class = m_get_uint16(m); /* Class */
3764 sr->sr_ttlsr_record->r_ttl = m_get_uint32(m); /* TTL */
3765 sr->sr_rdlensr_record->r_rdlen = m_get_uint16(m); /* rdlength */
3766 sr->sr_parsedsr_record->r_parsed = 1;
3767 if (m->m_error)
21
Taking false branch
3768 goto error;
3769 if (len >= (sizeof name)) {
22
Taking false branch
3770 m->m_error = "too long domain name in record";
3771 goto error;
3772 }
3773 name[len] = 0;
3774
3775 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__, 3782, "%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)
3776 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__, 3782, "%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 + 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__, 3782, "%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 "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__, 3782, "%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 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__, 3782, "%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 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__, 3782, "%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_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__, 3782, "%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 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__, 3782, "%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
3784 if (m->m_offset + sr->sr_rdlensr_record->r_rdlen > m->m_size) {
23
Assuming the condition is false
24
Taking false branch
3785 m->m_error = "truncated message";
3786 goto error;
3787 }
3788
3789 m_size = m->m_size;
3790 /* limit m_size to indicated rdlen, check whether record is truncated */
3791 m->m_size = m->m_offset + sr->sr_rdlensr_record->r_rdlen;
3792
3793 switch (sr->sr_typesr_record->r_type) {
25
Control jumps to 'case sres_type_aaaa:' at line 3803
3794 case sres_type_soa:
3795 sr = sres_init_rr_soa(cache, sr->sr_soa, m);
3796 break;
3797 case sres_type_a:
3798 sr = sres_init_rr_a(cache, sr->sr_a, m);
3799 break;
3800 case sres_type_a6:
3801 sr = sres_init_rr_a6(cache, sr->sr_a6, m);
3802 break;
3803 case sres_type_aaaa:
3804 sr = sres_init_rr_aaaa(cache, sr->sr_aaaa, m);
3805 break;
26
Execution continues on line 3823
3806 case sres_type_cname:
3807 sr = sres_init_rr_cname(cache, sr->sr_cname, m);
3808 break;
3809 case sres_type_ptr:
3810 sr = sres_init_rr_ptr(cache, sr->sr_ptr, m);
3811 break;
3812 case sres_type_srv:
3813 sr = sres_init_rr_srv(cache, sr->sr_srv, m);
3814 break;
3815 case sres_type_naptr:
3816 sr = sres_init_rr_naptr(cache, sr->sr_naptr, m);
3817 break;
3818 default:
3819 sr = sres_init_rr_unknown(cache, sr->sr_record, m);
3820 break;
3821 }
3822
3823 if (m->m_error)
27
Taking false branch
3824 goto error;
3825
3826 if (sr == sr0)
28
Taking false branch
3827 sr = sres_cache_alloc_record(cache, sr, 0);
3828
3829 assert(sr != sr0)((void) sizeof ((sr != sr0) ? 1 : 0), __extension__ ({ if (sr
!= sr0) ; else __assert_fail ("sr != sr0", "sres.c", 3829, __extension__
__PRETTY_FUNCTION__); }))
;
3830
3831 if (sr == NULL((void*)0)) {
29
Taking false branch
3832 m->m_error = "memory exhausted";
3833 goto error;
3834 }
3835
3836 /* Fill in the common fields */
3837 m->m_size = m_size;
3838
3839 return sr;
30
Address of stack memory associated with local variable 'sr0' returned to caller
3840
3841 error:
3842 if (sr && sr != sr0)
3843 sres_cache_free_record(cache, sr);
3844 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__, 3844, "%s: %s\n", "sres_create_record"
, m->m_error)) : (void)0)
;
3845 return NULL((void*)0);
3846}
3847
3848/** Decode SOA record */
3849static sres_record_t *sres_init_rr_soa(sres_cache_t *cache,
3850 sres_soa_record_t *soa,
3851 sres_message_t *m)
3852{
3853 uint16_t moffset, roffset;
3854 unsigned mnamelen, rnamelen;
3855
3856 soa->soa_record->r_size = sizeof *soa;
3857
3858 moffset = m->m_offset, mnamelen = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
3859 roffset = m->m_offset, rnamelen = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
3860
3861 soa->soa_serial = m_get_uint32(m);
3862 soa->soa_refresh = m_get_uint32(m);
3863 soa->soa_retry = m_get_uint32(m);
3864 soa->soa_expire = m_get_uint32(m);
3865 soa->soa_minimum = m_get_uint32(m);
3866
3867 if (m->m_error)
3868 return NULL((void*)0);
3869
3870 soa = (void *)sres_cache_alloc_record(cache, (void *)soa,
3871 mnamelen + rnamelen);
3872
3873 if (soa) {
3874 char *mname, *rname;
3875
3876 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", 3876, __extension__ __PRETTY_FUNCTION__); }))
;
3877
3878 m_get_domain(mname = (char *)(soa + 1), mnamelen, m, moffset);
3879 soa->soa_mname = mname;
3880
3881 m_get_domain(rname = mname + mnamelen, rnamelen, m, roffset);
3882 soa->soa_rname = rname;
3883 }
3884
3885 return (sres_record_t *)soa;
3886}
3887
3888/** Decode A record */
3889static sres_record_t *sres_init_rr_a(sres_cache_t *cache,
3890 sres_a_record_t *a,
3891 sres_message_t *m)
3892{
3893 a->a_record->r_size = sizeof *a;
3894
3895 a->a_addr.s_addr = htonl(m_get_uint32(m));
3896
3897 return (sres_record_t *)a;
3898}
3899
3900/** Decode A6 record. See @RFC2874 */
3901static sres_record_t *sres_init_rr_a6(sres_cache_t *cache,
3902 sres_a6_record_t *a6,
3903 sres_message_t *m)
3904{
3905
3906 unsigned suffixlen = 0, i;
3907 unsigned prefixlen = 0;
3908 uint16_t offset;
3909
3910 a6->a6_record->r_size = sizeof *a6;
3911
3912 a6->a6_prelen = m_get_uint8(m);
3913
3914 if (a6->a6_prelen > 128) {
3915 m->m_error = "Invalid prefix length in A6 record";
3916 return NULL((void*)0);
3917 }
3918
3919 suffixlen = (128 + 7 - a6->a6_prelen) / 8;
3920 for (i = 16 - suffixlen; i < 16; i++)
3921 a6->a6_suffix.u6_addr[i] = m_get_uint8(m);
3922
3923 if (a6->a6_prelen > 0) {
3924 if (suffixlen > 0)
3925 /* Zero pad bits */
3926 a6->a6_suffix.u6_addr[16 - suffixlen] &= 0xff >> (a6->a6_prelen & 7);
3927
3928 offset = m->m_offset, prefixlen = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
3929
3930 if (m->m_error)
3931 return NULL((void*)0);
3932
3933 a6 = (void *)sres_cache_alloc_record(cache, (void *)a6, prefixlen);
3934 if (a6)
3935 m_get_domain(a6->a6_prename = (char *)(a6 + 1), prefixlen, m, offset);
3936 }
3937
3938 return (sres_record_t *)a6;
3939}
3940
3941/** Decode AAAA record */
3942static sres_record_t *sres_init_rr_aaaa(sres_cache_t *cache,
3943 sres_aaaa_record_t *aaaa,
3944 sres_message_t *m)
3945{
3946 aaaa->aaaa_record->r_size = sizeof *aaaa;
3947
3948 if (m->m_offset + sizeof(aaaa->aaaa_addr) <= m->m_size) {
3949 memcpy(&aaaa->aaaa_addr, m->m_datam_packet.mp_data + m->m_offset, sizeof(aaaa->aaaa_addr));
3950 m->m_offset += sizeof(aaaa->aaaa_addr);
3951 }
3952 else
3953 m->m_error = "truncated AAAA record";
3954
3955 return (sres_record_t *)aaaa;
3956}
3957
3958/** Decode CNAME record */
3959static sres_record_t *sres_init_rr_cname(sres_cache_t *cache,
3960 sres_cname_record_t *cn,
3961 sres_message_t *m)
3962{
3963 uint16_t offset;
3964 unsigned dlen;
3965
3966 cn->cn_record->r_size = sizeof *cn;
3967
3968 offset = m->m_offset, dlen = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
3969
3970 if (m->m_error)
3971 return NULL((void*)0);
3972
3973 cn = (void *)sres_cache_alloc_record(cache, (void *)cn, dlen);
3974 if (cn)
3975 m_get_domain(cn->cn_cname = (char *)(cn + 1), dlen, m, offset);
3976
3977 return (sres_record_t *)cn;
3978}
3979
3980/** Decode PTR record */
3981static sres_record_t *sres_init_rr_ptr(sres_cache_t *cache,
3982 sres_ptr_record_t *ptr,
3983 sres_message_t *m)
3984{
3985 uint16_t offset;
3986 unsigned dlen;
3987
3988 ptr->ptr_record->r_size = sizeof *ptr;
3989
3990 offset = m->m_offset, dlen = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
3991
3992 if (m->m_error)
3993 return NULL((void*)0);
3994
3995 ptr = (void *)sres_cache_alloc_record(cache, (void *)ptr, dlen);
3996 if (ptr)
3997 m_get_domain(ptr->ptr_domain = (char *)(ptr + 1), dlen, m, offset);
3998
3999 return (sres_record_t *)ptr;
4000}
4001
4002/** Decode SRV record */
4003static sres_record_t *sres_init_rr_srv(sres_cache_t *cache,
4004 sres_srv_record_t *srv,
4005 sres_message_t *m)
4006{
4007 uint16_t offset;
4008 unsigned dlen;
4009
4010 srv->srv_record->r_size = sizeof *srv;
4011
4012 srv->srv_priority = m_get_uint16(m);
4013 srv->srv_weight = m_get_uint16(m);
4014 srv->srv_port = m_get_uint16(m);
4015 offset = m->m_offset, dlen = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
4016 if (m->m_error)
4017 return NULL((void*)0);
4018
4019 srv = (void *)sres_cache_alloc_record(cache, (void *)srv, dlen);
4020 if (srv)
4021 m_get_domain(srv->srv_target = (char *)(srv + 1), dlen, m, offset);
4022
4023 return (sres_record_t *)srv;
4024}
4025
4026/** Decode NAPTR record */
4027static sres_record_t *sres_init_rr_naptr(sres_cache_t *cache,
4028 sres_naptr_record_t *na,
4029 sres_message_t *m)
4030{
4031 uint16_t offset[4];
4032 unsigned len[4];
4033
4034 na->na_record->r_size = sizeof *na;
4035
4036 na->na_order = m_get_uint16(m);
4037 na->na_prefer = m_get_uint16(m);
4038
4039 offset[0] = m->m_offset, len[0] = m_get_string(NULL((void*)0), 0, m, 0) + 1;
4040 offset[1] = m->m_offset, len[1] = m_get_string(NULL((void*)0), 0, m, 0) + 1;
4041 offset[2] = m->m_offset, len[2] = m_get_string(NULL((void*)0), 0, m, 0) + 1;
4042 offset[3] = m->m_offset, len[3] = m_get_domain(NULL((void*)0), 0, m, 0) + 1;
4043
4044 if (m->m_error)
4045 return NULL((void*)0);
4046
4047 na = (void *)sres_cache_alloc_record(cache, (void *)na,
4048 len[0] + len[1] + len[2] + len[3]);
4049 if (na) {
4050 char *s = (char *)(na + 1);
4051 m_get_string(na->na_flags = s, len[0], m, offset[0]), s += len[0];
4052 m_get_string(na->na_services = s, len[1], m, offset[1]), s += len[1];
4053 m_get_string(na->na_regexp = s, len[2], m, offset[2]), s += len[2];
4054 m_get_domain(na->na_replace = s, len[3], m, offset[3]), s += len[3];
4055 }
4056
4057 return (sres_record_t *)na;
4058}
4059
4060/** Decode unknown record */
4061static sres_record_t *sres_init_rr_unknown(sres_cache_t *cache,
4062 sres_common_t *r,
4063 sres_message_t *m)
4064{
4065 if (m->m_offset + r->r_rdlen > m->m_size)
4066 m->m_error = "truncated record";
4067
4068 if (m->m_error)
4069 return NULL((void*)0);
4070
4071 r->r_size = sizeof *r;
4072
4073 r = (void *)sres_cache_alloc_record(cache, (void *)r, r->r_rdlen + 1);
4074 if (r) {
4075 char *data = (char *)(r + 1);
4076
4077 r->r_parsed = 0;
4078
4079 memcpy(data, m->m_datam_packet.mp_data + m->m_offset, r->r_rdlen);
4080 m->m_offset += r->r_rdlen;
4081 data[r->r_rdlen] = 0;
4082 }
4083
4084 return (sres_record_t *)r;
4085}
4086
4087static
4088sres_record_t *sres_create_error_rr(sres_cache_t *cache,
4089 sres_query_t const *q,
4090 uint16_t errcode)
4091{
4092 sres_record_t *sr, r[1];
4093 char buf[SRES_MAXDNAME(SRES_MAXDNAME)];
4094
4095 sr = memset(r, 0, sizeof *sr);
4096
4097 sr->sr_namesr_record->r_name = (char *)sres_toplevel(buf, sizeof buf, q->q_name);
4098 sr->sr_sizesr_record->r_size = sizeof *sr;
4099 sr->sr_statussr_record->r_status = errcode;
4100 sr->sr_typesr_record->r_type = q->q_type;
4101 sr->sr_classsr_record->r_class = q->q_class;
4102 sr->sr_ttlsr_record->r_ttl = 10 * 60;
4103
4104 return sres_cache_alloc_record(cache, sr, 0);
4105}
4106
4107/* Message processing primitives */
4108
4109static
4110void
4111m_put_uint16(sres_message_t *m,
4112 uint16_t h)
4113{
4114 uint8_t *p;
4115
4116 if (m->m_error)
4117 return;
4118
4119 p = m->m_datam_packet.mp_data + m->m_offset;
4120 m->m_offset += sizeof h;
4121
4122 if (m->m_offset > m->m_size) {
4123 m->m_error = "message size overflow";
4124 return;
4125 }
4126
4127 p[0] = h >> 8; p[1] = h;
4128}
4129
4130static
4131void
4132m_put_uint32(sres_message_t *m,
4133 uint32_t w)
4134{
4135 uint8_t *p;
4136
4137 if (m->m_error)
4138 return;
4139
4140 p = m->m_datam_packet.mp_data + m->m_offset;
4141 m->m_offset += sizeof w;
4142
4143 if (m->m_offset > m->m_size) {
4144 m->m_error = "message size overflow";
4145 return;
4146 }
4147
4148 p[0] = w >> 24; p[1] = w >> 16; p[2] = w >> 8; p[3] = w;
4149}
4150
4151/*
4152 * Put domain into query
4153 */
4154static
4155uint16_t
4156m_put_domain(sres_message_t *m,
4157 char const *domain,
4158 uint16_t top,
4159 char const *topdomain)
4160{
4161 char const *label;
4162 size_t llen;
4163
4164 if (m->m_error)
4165 return top;
4166
4167 /* Copy domain into query label at a time */
4168 for (label = domain; label && label[0]; label += llen) {
4169 if (label[0] == '.' && label[1] != '\0') {
4170 m->m_error = "empty label";
4171 return 0;
4172 }
4173
4174 llen = strcspn(label, ".");
4175
4176 if (llen >= 64) {
4177 m->m_error = "too long label";
4178 return 0;
4179 }
4180 if (m->m_offset + llen + 1 > m->m_size) {
4181 m->m_error = "message size overflow";
4182 return 0;
4183 }
4184
4185 m->m_datam_packet.mp_data[m->m_offset++] = (uint8_t)llen;
4186 memcpy(m->m_datam_packet.mp_data + m->m_offset, label, llen);
4187 m->m_offset += (uint8_t)llen;
4188
4189 if (label[llen] == '\0')
4190 break;
4191 if (llen == 0)
4192 return top;
4193 if (label[llen + 1])
4194 llen++;
4195 }
4196
4197 if (top) {
4198 m_put_uint16(m, 0xc000 | top);
4199 return top;
4200 }
4201 else if (topdomain) {
4202 uint16_t retval = m->m_offset;
4203 m_put_domain(m, topdomain, 0, NULL((void*)0));
4204 return retval;
4205 }
4206 else if (m->m_offset < m->m_size)
4207 m->m_datam_packet.mp_data[m->m_offset++] = '\0';
4208 else
4209 m->m_error = "message size overflow";
4210
4211 return 0;
4212}
4213
4214static
4215uint32_t
4216m_get_uint32(sres_message_t *m)
4217{
4218 uint8_t const *p = m->m_datam_packet.mp_data + m->m_offset;
4219
4220 if (m->m_error)
4221 return 0;
4222
4223 m->m_offset += 4;
4224
4225 if (m->m_offset > m->m_size) {
4226 m->m_error = "truncated message";
4227 return 0;
4228 }
4229
4230 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
4231}
4232
4233static
4234uint16_t
4235m_get_uint16(sres_message_t *m)
4236{
4237 uint8_t const *p = m->m_datam_packet.mp_data + m->m_offset;
4238
4239 if (m->m_error)
4240 return 0;
4241
4242 m->m_offset += 2;
4243
4244 if (m->m_offset > m->m_size) {
4245 m->m_error = "truncated message";
4246 return 0;
4247 }
4248
4249 return (p[0] << 8) | p[1];
4250}
4251
4252static
4253uint8_t
4254m_get_uint8(sres_message_t *m)
4255{
4256 uint8_t const *p = m->m_datam_packet.mp_data + m->m_offset;
4257
4258 if (m->m_error)
4259 return 0;
4260
4261 m->m_offset += 1;
4262
4263 if (m->m_offset > m->m_size) {
4264 m->m_error = "truncated message";
4265 return 0;
4266 }
4267
4268 return p[0];
4269}
4270
4271/**
4272 * Get a string.
4273 */
4274static unsigned
4275m_get_string(char *d,
4276 unsigned n,
4277 sres_message_t *m,
4278 uint16_t offset)
4279{
4280 uint8_t size;
4281 uint8_t *p = m->m_datam_packet.mp_data;
4282 int save_offset;
4283
4284 if (m->m_error)
4285 return 0;
4286
4287 if (offset == 0)
4288 offset = m->m_offset, save_offset = 1;
4289 else
4290 save_offset = 0;
4291
4292 size = p[offset++];
4293
4294 if (size + offset >= m->m_size) {
4295 m->m_error = "truncated message";
4296 return size;
4297 }
4298
4299 offset += size;
4300
4301 if (save_offset)
4302 m->m_offset = offset;
4303
4304 if (n == 0 || d == NULL((void*)0))
4305 return size; /* Just return the size (without NUL). */
4306
4307 memcpy(d, p + offset - size, size < n ? size : n);
4308
4309 if (size < n)
4310 d[size] = '\0'; /* NUL terminate */
4311
4312 return size;
4313}
4314
4315/**
4316 * Uncompress a domain.
4317 *
4318 * @param offset start uncompression from this point in message
4319 */
4320static unsigned
4321m_get_domain(char *d,
4322 unsigned n,
4323 sres_message_t *m,
4324 uint16_t offset)
4325{
4326 uint8_t cnt;
4327 unsigned i = 0;
4328 uint8_t *p = m->m_datam_packet.mp_data;
4329 uint16_t new_offset;
4330 int save_offset;
4331
4332 if (m->m_error)
4333 return 0;
4334
4335 if (d == NULL((void*)0))
4336 n = 0;
4337
4338 if (offset == 0)
4339 offset = m->m_offset, save_offset = 1;
4340 else
4341 save_offset = 0;
4342
4343 while ((cnt = p[offset++])) {
4344 if (cnt >= 0xc0) {
4345 if (offset >= m->m_size) {
4346 m->m_error = "truncated message";
4347 return 0;
4348 }
4349
4350 new_offset = ((cnt & 0x3F) << 8) + p[offset++];
4351
4352 if (save_offset)
4353 m->m_offset = offset;
4354
4355 if (new_offset <= 0 || new_offset >= m->m_size) {
4356 m->m_error = "invalid domain compression";
4357 return 0;
4358 }
4359
4360 offset = new_offset;
4361 save_offset = 0;
4362 }
4363 else {
4364 if (offset + cnt >= m->m_size) {
4365 m->m_error = "truncated message";
4366 return 0;
4367 }
4368 if (i + cnt + 1 < n) {
4369 memcpy(d + i, p + offset, cnt);
4370 d[i + cnt] = '.';
4371 }
4372
4373 i += cnt + 1;
4374 offset += cnt;
4375 }
4376 }
4377
4378 if (i == 0) {
4379 if (i < n)
4380 d[i] = '.';
4381 i++;
4382 }
4383
4384 if (i < n)
4385 d[i] = '\0';
4386
4387 if (save_offset)
4388 m->m_offset = offset;
4389
4390 return i;
4391}