Asterisk - The Open Source Telephony Project  21.4.1
dns.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006 Thorsten Lockert
5  *
6  * Written by Thorsten Lockert <tholo@trollphone.org>
7  *
8  * Funding provided by Troll Phone Networks AS
9  *
10  * See http://www.asterisk.org for more information about
11  * the Asterisk project. Please do not directly contact
12  * any of the maintainers of this project for assistance;
13  * the project provides a web site, mailing lists and IRC
14  * channels for your use.
15  *
16  * This program is free software, distributed under the terms of
17  * the GNU General Public License Version 2. See the LICENSE file
18  * at the top of the source tree.
19  */
20 
21 /*! \file
22  *
23  * \brief DNS Support for Asterisk
24  *
25  * \author Thorsten Lockert <tholo@trollphone.org>
26  *
27  * \par Reference
28  * - DNR SRV records http://www.ietf.org/rfc/rfc2782.txt
29  *
30  */
31 
32 /*** MODULEINFO
33  <support_level>core</support_level>
34  ***/
35 
36 #include "asterisk.h"
37 
38 #include "asterisk/network.h"
39 #include <arpa/nameser.h> /* res_* functions */
40 #include <resolv.h>
41 
42 #include "asterisk/channel.h"
43 #include "asterisk/dns.h"
44 #include "asterisk/endian.h"
45 
46 /*! \brief The maximum size permitted for the answer from the DNS server */
47 #define MAX_SIZE 4096
48 
49 #ifdef __PDP_ENDIAN
50 #if __BYTE_ORDER == __PDP_ENDIAN
51 #define DETERMINED_BYTE_ORDER __LITTLE_ENDIAN
52 #endif
53 #endif
54 #if __BYTE_ORDER == __BIG_ENDIAN
55 #define DETERMINED_BYTE_ORDER __BIG_ENDIAN
56 #endif
57 #if __BYTE_ORDER == __LITTLE_ENDIAN
58 #define DETERMINED_BYTE_ORDER __LITTLE_ENDIAN
59 #endif
60 
61 #ifndef HAVE_RES_NINIT
62 AST_MUTEX_DEFINE_STATIC(res_lock);
63 #endif
64 
65 /* The dns_HEADER structure definition below originated
66  in the arpa/nameser.h header file distributed with ISC
67  BIND, which contains the following copyright and license
68  notices:
69 
70  * ++Copyright++ 1983, 1989, 1993
71  * -
72  * Copyright (c) 1983, 1989, 1993
73  * The Regents of the University of California. All rights reserved.
74  *
75  * Redistribution and use in source and binary forms, with or without
76  * modification, are permitted provided that the following conditions
77  * are met:
78  * 1. Redistributions of source code must retain the above copyright
79  * notice, this list of conditions and the following disclaimer.
80  * 2. Redistributions in binary form must reproduce the above copyright
81  * notice, this list of conditions and the following disclaimer in the
82  * documentation and/or other materials provided with the distribution.
83  * 3. All advertising materials mentioning features or use of this software
84  * must display the following acknowledgement:
85  * This product includes software developed by the University of
86  * California, Berkeley and its contributors.
87  * 4. Neither the name of the University nor the names of its contributors
88  * may be used to endorse or promote products derived from this software
89  * without specific prior written permission.
90  *
91  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
92  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
93  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
94  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
95  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
96  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
97  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
98  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
99  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
100  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
101  * SUCH DAMAGE.
102  * -
103  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
104  *
105  * Permission to use, copy, modify, and distribute this software for any
106  * purpose with or without fee is hereby granted, provided that the above
107  * copyright notice and this permission notice appear in all copies, and that
108  * the name of Digital Equipment Corporation not be used in advertising or
109  * publicity pertaining to distribution of the document or software without
110  * specific, written prior permission.
111  *
112  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
113  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
114  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
115  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
116  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
117  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
118  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
119  * SOFTWARE.
120  * -
121  * --Copyright--
122  */
123 
124 typedef struct {
125  unsigned id:16; /*!< query identification number */
126 #if DETERMINED_BYTE_ORDER == __BIG_ENDIAN
127  /* fields in third byte */
128  unsigned qr:1; /*!< response flag */
129  unsigned opcode:4; /*!< purpose of message */
130  unsigned aa:1; /*!< authoritative answer */
131  unsigned tc:1; /*!< truncated message */
132  unsigned rd:1; /*!< recursion desired */
133  /* fields in fourth byte */
134  unsigned ra:1; /*!< recursion available */
135  unsigned unused:1; /*!< unused bits (MBZ as of 4.9.3a3) */
136  unsigned ad:1; /*!< authentic data from named */
137  unsigned cd:1; /*!< checking disabled by resolver */
138  unsigned rcode:4; /*!< response code */
139 #endif
140 #if DETERMINED_BYTE_ORDER == __LITTLE_ENDIAN
141  /* fields in third byte */
142  unsigned rd:1; /*!< recursion desired */
143  unsigned tc:1; /*!< truncated message */
144  unsigned aa:1; /*!< authoritative answer */
145  unsigned opcode:4; /*!< purpose of message */
146  unsigned qr:1; /*!< response flag */
147  /* fields in fourth byte */
148  unsigned rcode:4; /*!< response code */
149  unsigned cd:1; /*!< checking disabled by resolver */
150  unsigned ad:1; /*!< authentic data from named */
151  unsigned unused:1; /*!< unused bits (MBZ as of 4.9.3a3) */
152  unsigned ra:1; /*!< recursion available */
153 #endif
154  /* remaining bytes */
155  unsigned qdcount:16; /*!< number of question entries */
156  unsigned ancount:16; /*!< number of answer entries */
157  unsigned nscount:16; /*!< number of authority entries */
158  unsigned arcount:16; /*!< number of resource entries */
159 } dns_HEADER;
160 
161 struct dn_answer {
162  unsigned short rtype; /*!< The resource record type. */
163  unsigned short class; /*!< The resource record class. */
164  unsigned int ttl; /*!< The resource record time to live. */
165  unsigned short size; /*!< The resource record size. */
166 } __attribute__((__packed__));
167 
168 /*!
169  * \brief Tries to find the position of the next field in the DNS response.
170  *
171  * \internal
172  *
173  * \param s A char pointer to the current frame in the DNS response.
174  * \param len The remaining available length of the DNS response.
175  *
176  * \return The position of the next field
177  * \retval -1 if there are no remaining fields
178  */
179 static int skip_name(unsigned char *s, int len)
180 {
181  int x = 0;
182 
183  while (x < len) {
184  if (*s == '\0') {
185  s++;
186  x++;
187  break;
188  }
189 
190  if ((*s & 0xc0) == 0xc0) {
191  s += 2;
192  x += 2;
193  break;
194  }
195 
196  x += *s + 1;
197  s += *s + 1;
198  }
199 
200  /* If we are out of room to search, return failure. */
201  if (x >= len) {
202  return AST_DNS_SEARCH_FAILURE;
203  }
204 
205  /* Return the value for the current position in the DNS response. This is the start
206  position of the next field. */
207  return x;
208 }
209 
210 /*!
211  * \brief Advances the position of the DNS response pointer by the size of the current field.
212  *
213  * \internal
214  *
215  * \param dns_response A pointer to a char pointer to the current field in the DNS response.
216  * \param remaining_len The remaining available length in the DNS response to search.
217  * \param field_size A positive value representing the size of the current field
218  pointed to by the dns_response parameter.
219  *
220  * \return The remaining length in the DNS response
221  * \retval -1 there are no frames remaining in the DNS response
222  */
223 static int dns_advance_field(unsigned char **dns_response, int remaining_len, int field_size)
224 {
225  if (dns_response == NULL || field_size < 0 || remaining_len < field_size) {
226  return AST_DNS_SEARCH_FAILURE;
227  }
228 
229  *dns_response += field_size;
230  remaining_len -= field_size;
231 
232  return remaining_len;
233 }
234 
235 #ifndef HAVE_RES_NINIT
236 /*!
237  * \brief Handles the DNS search if the system has RES_INIT.
238  *
239  * \internal
240  *
241  * \param dname Domain name to lookup (host, SRV domain, TXT record name).
242  * \param rr_class Record Class (see "man res_search").
243  * \param rr_type Record type (see "man res_search").
244  * \param dns_response The full DNS response.
245  * \param dns_response_len The length of the full DNS response.
246  *
247  * \return The length of the DNS response
248  * \retval -1 on search failure
249  */
250 static int dns_search_res(const char *dname, int rr_class, int rr_type,
251  unsigned char *dns_response, int dns_response_len)
252 {
253 
254  int ret = AST_DNS_SEARCH_FAILURE;
255 
256  ast_mutex_lock(&res_lock);
257  res_init();
258  ret = res_search(dname,
259  rr_class,
260  rr_type,
261  dns_response,
262  dns_response_len);
263 
264 #ifdef HAVE_RES_CLOSE
265  res_close();
266 #endif
267 
268  ast_mutex_unlock(&res_lock);
269 
270  return ret;
271 }
272 #else
273 /*!
274  * \brief Handles the DNS search if the system has RES_NINIT.
275  *
276  * \internal
277  *
278  * \param dname Domain name to lookup (host, SRV domain, TXT record name).
279  * \param rr_class Record Class (see "man res_search").
280  * \param rr_type Record type (see "man res_search").
281  * \param dns_response The full DNS response.
282  * \param dns_response_len The length of the full DNS response.
283  *
284  * \return The length of the DNS response
285  * \retval -1 on search failure
286  */
287 static int dns_search_res(const char *dname, int rr_class, int rr_type,
288  unsigned char *dns_response, int dns_response_len)
289 {
290 
291  int ret = AST_DNS_SEARCH_FAILURE;
292  struct __res_state dns_state;
293 
294  memset(&dns_state, 0, sizeof(dns_state));
295  res_ninit(&dns_state);
296  ret = res_nsearch(&dns_state,
297  dname,
298  rr_class,
299  rr_type,
300  dns_response,
301  dns_response_len);
302 
303 #ifdef HAVE_RES_NDESTROY
304  res_ndestroy(&dns_state);
305 #else
306  res_nclose(&dns_state);
307 #endif
308 
309  return ret;
310 }
311 #endif
312 
313 /*!
314  * \brief Parse DNS lookup result, call callback
315  *
316  * \internal
317  *
318  * \param context Void pointer containing data to use in the callback functions.
319  * \param class Record Class (see "man res_search").
320  * \param type Record type (see "man res_search").
321  * \param answer The full DNS response.
322  * \param len The length of the full DNS response.
323  * \param callback Callback function for handling the discovered resource records from the DNS search.
324  *
325  * \retval -1 on search failure
326  * \retval 0 on no records found
327  * \retval 1 on success
328  */
329 static int dns_parse_answer(void *context,
330  int class, int type, unsigned char *answer, int len,
331  int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
332 {
333  unsigned char *fullanswer = answer;
334  struct dn_answer *ans;
335  dns_HEADER *h;
336  int ret = 0;
337  int res;
338  int x;
339 
340  h = (dns_HEADER *)answer;
341  answer += sizeof(dns_HEADER);
342  len -= sizeof(dns_HEADER);
343 
344  for (x = 0; x < ntohs(h->qdcount); x++) {
345  if ((res = skip_name(answer, len)) < 0) {
346  ast_log(LOG_WARNING, "Couldn't skip over name\n");
347  return -1;
348  }
349  answer += res + 4; /* Skip name and QCODE / QCLASS */
350  len -= res + 4;
351  if (len < 0) {
352  ast_log(LOG_WARNING, "Strange query size\n");
353  return -1;
354  }
355  }
356 
357  for (x = 0; x < ntohs(h->ancount); x++) {
358  if ((res = skip_name(answer, len)) < 0) {
359  ast_log(LOG_WARNING, "Failed skipping name\n");
360  return -1;
361  }
362  answer += res;
363  len -= res;
364  ans = (struct dn_answer *)answer;
365  answer += sizeof(struct dn_answer);
366  len -= sizeof(struct dn_answer);
367  if (len < 0) {
368  ast_log(LOG_WARNING, "Length of DNS answer exceeds frame\n");
369  return -1;
370  }
371 
372  if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
373  if (callback) {
374  if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
375  ast_log(LOG_WARNING, "Failed to parse result\n");
376  return -1;
377  }
378  ret = 1;
379  }
380  }
381  answer += ntohs(ans->size);
382  len -= ntohs(ans->size);
383  }
384  return ret;
385 }
386 
387 /*!
388  * \brief Extended version of the DNS Parsing function.
389  *
390  * \details Parses the DNS lookup result and notifies the observer of each discovered
391  * resource record with the provided callback.
392  *
393  * \internal
394  *
395  * \param context Void pointer containing data to use in the callback functions.
396  * \param rr_class Record Class (see "man res_search").
397  * \param rr_type Record type (see "man res_search").
398  * \param answer The full DNS response.
399  * \param answer_len The length of the full DNS response.
400  * \param response_handler Callback function for handling the DNS response.
401  * \param record_handler Callback function for handling the discovered resource records from the DNS search.
402  *
403  * \retval -1 on search failure
404  * \retval 0 on no records found
405  * \retval 1 on success
406  */
407 static int dns_parse_answer_ex(void *context, int rr_class, int rr_type, unsigned char *answer, int answer_len,
408  int (*response_handler)(void *context, unsigned char *dns_response, int dns_response_len, int rcode),
409  int (*record_handler)(void *context, unsigned char *record, int record_len, int ttl))
410 {
411  unsigned char *dns_response = answer;
412  dns_HEADER *dns_header = (dns_HEADER *)answer;
413 
414  struct dn_answer *ans;
415  int res, x, pos, dns_response_len, ret;
416 
417  dns_response_len = answer_len;
419 
420  /* Invoke the response_handler callback to notify the observer of the raw DNS response */
421  response_handler(context, dns_response, dns_response_len, ntohs(dns_header->rcode));
422 
423  /* Verify there is something to parse */
424  if (answer_len == 0) {
425  return ret;
426  }
427 
428  /* Try advancing the cursor for the dns header */
429  if ((pos = dns_advance_field(&answer, answer_len, sizeof(dns_HEADER))) < 0) {
430  ast_log(LOG_WARNING, "Length of DNS answer exceeds available search frames\n");
431  return AST_DNS_SEARCH_FAILURE;
432  }
433 
434  /* Skip domain name and QCODE / QCLASS */
435  for (x = 0; x < ntohs(dns_header->qdcount); x++) {
436  if ((res = skip_name(answer, pos)) < 0) {
437  ast_log(LOG_WARNING, "Failed skipping name\n");
438  return AST_DNS_SEARCH_FAILURE;
439  }
440 
441  /* Try advancing the cursor for the name and QCODE / QCLASS fields */
442  if ((pos = dns_advance_field(&answer, pos, res + 4)) < 0) {
443  return AST_DNS_SEARCH_FAILURE;
444  }
445  }
446 
447  /* Extract the individual records */
448  for (x = 0; x < ntohs(dns_header->ancount); x++) {
449  if ((res = skip_name(answer, pos)) < 0) {
450  ast_log(LOG_WARNING, "Failed skipping name\n");
451  return AST_DNS_SEARCH_FAILURE;
452  }
453 
454  /* Try advancing the cursor to the current record */
455  if ((pos = dns_advance_field(&answer, pos, res)) < 0) {
456  ast_log(LOG_WARNING, "Length of DNS answer exceeds available search frames\n");
457  return AST_DNS_SEARCH_FAILURE;
458  }
459 
460  /* Cast the current value for the answer pointer as a dn_answer struct */
461  ans = (struct dn_answer *) answer;
462 
463  /* Try advancing the cursor to the end of the current record */
464  if ((pos = dns_advance_field(&answer, pos, sizeof(struct dn_answer))) < 0) {
465  ast_log(LOG_WARNING, "Length of DNS answer exceeds available search frames\n");
466  return AST_DNS_SEARCH_FAILURE;
467  }
468 
469  /* Skip over the records that do not have the same resource record class and type we care about */
470  if (ntohs(ans->class) == rr_class && ntohs(ans->rtype) == rr_type) {
471  /* Invoke the record handler callback to deliver the discovered record */
472  record_handler(context, answer, ntohs(ans->size), ntohl(ans->ttl));
473  /*At least one record was found */
475  }
476 
477  /* Try and update the field to the next record, but ignore any errors that come
478  * back because this may be the end of the line. */
479  pos = dns_advance_field(&answer, pos, ntohs(ans->size));
480  }
481 
482  return ret;
483 }
484 
485 /*!
486  * \brief Lookup record in DNS
487  *
488  * \note Asterisk DNS is synchronus at this time. This means that if your DNS does not
489  * work properly, Asterisk might not start properly or a channel may lock.
490 */
491 int ast_search_dns(void *context,
492  const char *dname, int class, int type,
493  int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
494 {
495 #ifdef HAVE_RES_NINIT
496  struct __res_state dnsstate;
497 #endif
498  unsigned char answer[MAX_SIZE];
499  int res, ret = -1;
500 
501 #ifdef HAVE_RES_NINIT
502  memset(&dnsstate, 0, sizeof(dnsstate));
503  res_ninit(&dnsstate);
504  res = res_nsearch(&dnsstate, dname, class, type, answer, sizeof(answer));
505 #else
506  ast_mutex_lock(&res_lock);
507  res_init();
508  res = res_search(dname, class, type, answer, sizeof(answer));
509 #endif
510  if (res > 0) {
511  if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
512  ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
513  ret = -1;
514  } else if (res == 0) {
515  ast_debug(1, "No matches found in DNS for %s\n", dname);
516  ret = 0;
517  } else
518  ret = 1;
519  }
520 #ifdef HAVE_RES_NINIT
521 #ifdef HAVE_RES_NDESTROY
522  res_ndestroy(&dnsstate);
523 #else
524  res_nclose(&dnsstate);
525 #endif
526 #else
527 #ifdef HAVE_RES_CLOSE
528  res_close();
529 #endif
530  ast_mutex_unlock(&res_lock);
531 #endif
532 
533  return ret;
534 }
535 
536 enum ast_dns_search_result ast_search_dns_ex(void *context, const char *dname, int rr_class, int rr_type,
537  int (*response_handler)(void *context, unsigned char *dns_response, int dns_response_len, int rcode),
538  int (*record_handler)(void *context, unsigned char *record, int record_len, int ttl))
539 {
540  int ret, dns_response_len;
541  unsigned char dns_response[MAX_SIZE];
542 
543  /* Assert that the callbacks are not NULL */
544  ast_assert(response_handler != NULL);
545  ast_assert(record_handler != NULL);
546 
547  /* Try the DNS search. */
548  dns_response_len = dns_search_res(dname,
549  rr_class,
550  rr_type,
551  dns_response,
552  sizeof(dns_response));
553 
554  if (dns_response_len < 0) {
555  ast_debug(1, "DNS search failed for %s\n", dname);
556  response_handler(context, (unsigned char *)"", 0, NXDOMAIN);
557  return AST_DNS_SEARCH_FAILURE;
558  }
559 
560  /* Parse records from DNS response */
561  ret = dns_parse_answer_ex(context,
562  rr_class,
563  rr_type,
564  dns_response,
565  dns_response_len,
566  response_handler,
567  record_handler);
568 
569  /* Handle the return code from parsing the DNS response */
570  if (ret == AST_DNS_SEARCH_FAILURE) {
571  /* Parsing Error */
572  ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
573  } else if (ret == AST_DNS_SEARCH_NO_RECORDS) {
574  /* No results found */
575  ast_debug(1, "DNS search yielded no results for %s\n", dname);
576  }
577 
578  return ret;
579 }
580 
582 {
583 #ifdef HAVE_RES_NINIT
584  struct __res_state dnsstate;
585 #endif
586  struct __res_state *state;
587  struct ao2_container *nameservers;
588  int i;
589 
591  if (!nameservers) {
592  return NULL;
593  }
594 
595 #ifdef HAVE_RES_NINIT
596  memset(&dnsstate, 0, sizeof(dnsstate));
597  res_ninit(&dnsstate);
598  state = &dnsstate;
599 #else
600  ast_mutex_lock(&res_lock);
601  res_init();
602  state = &_res;
603 #endif
604 
605  for (i = 0; i < state->nscount; i++) {
606  char addr[INET6_ADDRSTRLEN];
607  const char *addrp = NULL;
608 
609  /* glibc sets sin_family to 0 when the nameserver is an IPv6 address */
610  if (state->nsaddr_list[i].sin_family) {
611  addrp = inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, addr, sizeof(addr));
612 #if defined(HAVE_RES_NINIT) && defined(HAVE_STRUCT___RES_STATE__U__EXT_NSADDRS)
613  } else if (state->_u._ext.nsaddrs[i]) {
614  addrp = inet_ntop(AF_INET6, &state->_u._ext.nsaddrs[i]->sin6_addr, addr, sizeof(addr));
615 #endif
616  }
617 
618  if (addrp) {
619  ast_debug(1, "Discovered nameserver: %s\n", addrp);
620  ast_str_container_add(nameservers, addrp);
621  }
622  }
623 
624 #ifdef HAVE_RES_NINIT
625 #ifdef HAVE_RES_NDESTROY
626  res_ndestroy(&dnsstate);
627 #else
628  res_nclose(&dnsstate);
629 #endif
630 #else
631 #ifdef HAVE_RES_CLOSE
632  res_close();
633 #endif
634  ast_mutex_unlock(&res_lock);
635 #endif
636 
637  return nameservers;
638 }
unsigned ancount
Definition: dns.c:156
Asterisk main include file. File version handling, generic pbx functions.
static int dns_parse_answer_ex(void *context, int rr_class, int rr_type, unsigned char *answer, int answer_len, int(*response_handler)(void *context, unsigned char *dns_response, int dns_response_len, int rcode), int(*record_handler)(void *context, unsigned char *record, int record_len, int ttl))
Extended version of the DNS Parsing function.
Definition: dns.c:407
unsigned short size
Definition: dns.c:165
enum ast_dns_search_result ast_search_dns_ex(void *context, const char *dname, int rr_class, int rr_type, int(*response_handler)(void *context, unsigned char *dns_response, int dns_response_len, int rcode), int(*record_handler)(void *context, unsigned char *record, int record_len, int ttl))
Extended version of the DNS search function.
Definition: dns.c:536
static int dns_advance_field(unsigned char **dns_response, int remaining_len, int field_size)
Advances the position of the DNS response pointer by the size of the current field.
Definition: dns.c:223
static int dns_search_res(const char *dname, int rr_class, int rr_type, unsigned char *dns_response, int dns_response_len)
Handles the DNS search if the system has RES_NINIT.
Definition: dns.c:287
General Asterisk PBX channel definitions.
struct ao2_container * ast_str_container_alloc_options(enum ao2_alloc_opts opts, int buckets)
Allocates a hash container for bare strings.
Definition: strings.c:200
ast_dns_search_result
DNS search return values.
Definition: dns.h:28
Asterisk architecture endianess compatibility definitions.
#define ast_debug(level,...)
Log a DEBUG message.
Wrapper for network related headers, masking differences between various operating systems...
unsigned short class
Definition: dns.c:163
unsigned int ttl
Definition: dns.c:164
static int skip_name(unsigned char *s, int len)
Tries to find the position of the next field in the DNS response.
Definition: dns.c:179
struct ao2_container * ast_dns_get_nameservers(void)
Retrieve the configured nameservers of the system.
Definition: dns.c:581
unsigned short rtype
Definition: dns.c:162
#define MAX_SIZE
The maximum size permitted for the answer from the DNS server.
Definition: dns.c:47
Generic container type.
unsigned qdcount
Definition: dns.c:155
Definition: dns.c:161
int ast_search_dns(void *context, const char *dname, int class, int type, int(*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
Lookup record in DNS.
Definition: dns.c:491
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
Definition: strings.c:205
DNS support for Asterisk.
static int dns_parse_answer(void *context, int class, int type, unsigned char *answer, int len, int(*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
Parse DNS lookup result, call callback.
Definition: dns.c:329