Asterisk - The Open Source Telephony Project  18.5.0
dns_naptr.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2015, Digium, Inc.
5  *
6  * Joshua Colp <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief DNS NAPTR Record Support
22  *
23  * \author Joshua Colp <[email protected]>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 #include <arpa/nameser.h>
33 #include <netinet/in.h>
34 #include <resolv.h>
35 #include <regex.h>
36 
37 #include "asterisk/dns_core.h"
38 #include "asterisk/dns_naptr.h"
39 #include "asterisk/linkedlists.h"
40 #include "asterisk/dns_internal.h"
41 #include "asterisk/utils.h"
42 
43 /*!
44  * \brief Result of analyzing NAPTR flags on a record
45  */
47  /*! Terminal record, meaning the DDDS algorithm can be stopped */
49  /*! No flags provided, likely meaning another NAPTR lookup */
51  /*! Unrecognized but valid flags. We cannot conclude what they mean */
53  /*! Non-alphanumeric or invalid combination of flags */
55 };
56 
57 /*!
58  * \brief Analyze and interpret NAPTR flags as per RFC 3404
59  *
60  * \note The flags string passed into this function is NOT NULL-terminated
61  *
62  * \param flags The flags string from a NAPTR record
63  * \flags_size The size of the flags string in bytes
64  * \return flag result
65  */
66 static enum flags_result interpret_flags(const char *flags, uint8_t flags_size)
67 {
68  int i;
69  char known_flag_found = 0;
70 
71  if (flags_size == 0) {
72  return FLAGS_EMPTY;
73  }
74 
75  /* Take care of the most common (and easy) case, one character */
76  if (flags_size == 1) {
77  if (*flags == 's' || *flags == 'S' ||
78  *flags == 'a' || *flags == 'A' ||
79  *flags == 'u' || *flags == 'U') {
80  return FLAGS_TERMINAL;
81  } else if (!isalnum(*flags)) {
82  return FLAGS_INVALID;
83  } else {
84  return FLAGS_UNKNOWN;
85  }
86  }
87 
88  /*
89  * Multiple flags are allowed, but you cannot mix the
90  * S, A, U, and P flags together.
91  */
92  for (i = 0; i < flags_size; ++i) {
93  if (!isalnum(flags[i])) {
94  return FLAGS_INVALID;
95  } else if (flags[i] == 's' || flags[i] == 'S') {
96  if (known_flag_found && known_flag_found != 's') {
97  return FLAGS_INVALID;
98  }
99  known_flag_found = 's';
100  } else if (flags[i] == 'u' || flags[i] == 'U') {
101  if (known_flag_found && known_flag_found != 'u') {
102  return FLAGS_INVALID;
103  }
104  known_flag_found = 'u';
105  } else if (flags[i] == 'a' || flags[i] == 'A') {
106  if (known_flag_found && known_flag_found != 'a') {
107  return FLAGS_INVALID;
108  }
109  known_flag_found = 'a';
110  } else if (flags[i] == 'p' || flags[i] == 'P') {
111  if (known_flag_found && known_flag_found != 'p') {
112  return FLAGS_INVALID;
113  }
114  known_flag_found = 'p';
115  }
116  }
117 
118  return (!known_flag_found || known_flag_found == 'p') ? FLAGS_UNKNOWN : FLAGS_TERMINAL;
119 }
120 
121 /*!
122  * \brief Analyze NAPTR services for validity as defined by RFC 3404
123  *
124  * \note The services string passed to this function is NOT NULL-terminated
125  * \param services The services string parsed from a NAPTR record
126  * \param services_size The size of the services string
127  * \retval 0 Services are valid
128  * \retval -1 Services are invalid
129  */
130 static int services_invalid(const char *services, uint8_t services_size)
131 {
132  const char *current_pos = services;
133  const char *end_of_services = services + services_size;
134 
135  if (services_size == 0) {
136  return 0;
137  }
138 
139  /* Services are broken into sections divided by a + sign. Each section
140  * must start with an alphabetic character, and then can only contain
141  * alphanumeric characters. The size of any section is limited to
142  * 32 characters
143  */
144  while (1) {
145  char *plus_pos = memchr(current_pos, '+', end_of_services - current_pos);
146  uint8_t current_size = plus_pos ? plus_pos - current_pos : end_of_services - current_pos;
147  int i;
148 
149  if (!isalpha(current_pos[0])) {
150  return -1;
151  }
152 
153  if (current_size > 32) {
154  return -1;
155  }
156 
157  for (i = 1; i < current_size; ++i) {
158  if (!isalnum(current_pos[i])) {
159  return -1;
160  }
161  }
162 
163  if (!plus_pos) {
164  break;
165  }
166  current_pos = plus_pos + 1;
167  }
168 
169  return 0;
170 }
171 
172 /*!
173  * \brief Determine if flags in the regexp are invalid
174  *
175  * A NAPTR regexp is structured like so
176  * /pattern/repl/FLAGS
177  *
178  * This ensures that the flags on the regexp are valid. Regexp
179  * flags can either be zero or one character long. If the flags
180  * are one character long, that character must be "i" to indicate
181  * the regex evaluation is case-insensitive.
182  *
183  * \note The flags string passed to this function is not NULL-terminated
184  * \param flags The regexp flags from the NAPTR record
185  * \param end A pointer to the end of the flags string
186  * \retval 0 Flags are valid
187  * \retval -1 Flags are invalid
188  */
189 static int regexp_flags_invalid(const char *flags, const char *end)
190 {
191  if (flags >= end) {
192  return 0;
193  }
194 
195  if (end - flags > 1) {
196  return -1;
197  }
198 
199  if (*flags != 'i') {
200  return -1;
201  }
202 
203  return 0;
204 }
205 
206 /*!
207  * \brief Determine if the replacement in the regexp is invalid
208  *
209  * A NAPTR regexp is structured like so
210  * /pattern/REPL/flags
211  *
212  * This ensures that the replacement on the regexp is valid. The regexp
213  * replacement is free to use any character it wants, plus backreferences
214  * and an escaped regexp delimiter.
215  *
216  * This function does not attempt to ensure that the backreferences refer
217  * to valid portions of the regexp's regex pattern.
218  *
219  * \note The repl string passed to this function is NOT NULL-terminated
220  *
221  * \param repl The regexp replacement string
222  * \param end Pointer to the end of the replacement string
223  * \param delim The delimiter character for the regexp
224  *
225  * \retval 0 Replacement is valid
226  * \retval -1 Replacement is invalid
227  */
228 static int regexp_repl_invalid(const char *repl, const char *end, char delim)
229 {
230  const char *ptr = repl;
231 
232  if (repl == end) {
233  /* Kind of weird, but this is fine */
234  return 0;
235  }
236 
237  while (1) {
238  char *backslash_pos = memchr(ptr, '\\', end - ptr);
239  if (!backslash_pos) {
240  break;
241  }
242 
243  ast_assert(backslash_pos < end - 1);
244 
245  /* XXX RFC 3402 is unclear about whether other backslash-escaped characters
246  * (such as a backslash-escaped backslash) are legal
247  */
248  if (!strchr("12345689", backslash_pos[1]) && backslash_pos[1] != delim) {
249  return -1;
250  }
251 
252  ptr = backslash_pos + 1;
253  }
254 
255  return 0;
256 }
257 
258 /*!
259  * \brief Determine if the pattern in a regexp is invalid
260  *
261  * A NAPTR regexp is structured like so
262  * /PATTERN/repl/flags
263  *
264  * This ensures that the pattern on the regexp is valid. The pattern is
265  * passed to a regex compiler to determine its validity.
266  *
267  * \note The pattern string passed to this function is NOT NULL-terminated
268  *
269  * \param pattern The pattern from the NAPTR record
270  * \param end A pointer to the end of the pattern
271  *
272  * \retval 0 Pattern is valid
273  * \retval non-zero Pattern is invalid
274  */
275 static int regexp_pattern_invalid(const char *pattern, const char *end)
276 {
277  int pattern_size = end - pattern;
278  char pattern_str[pattern_size + 1];
279  regex_t reg;
280  int res;
281 
282  /* regcomp requires a NULL-terminated string */
283  memcpy(pattern_str, pattern, pattern_size);
284  pattern_str[pattern_size] = '\0';
285 
286  res = regcomp(&reg, pattern_str, REG_EXTENDED);
287 
288  regfree(&reg);
289 
290  return res;
291 }
292 
293 /*!
294  * \brief Determine if the regexp in a NAPTR record is invalid
295  *
296  * The goal of this function is to divide the regexp into its
297  * constituent parts and then let validation subroutines determine
298  * if each part is valid. If all parts are valid, then the entire
299  * regexp is valid.
300  *
301  * \note The regexp string passed to this function is NOT NULL-terminated
302  *
303  * \param regexp The regexp from the NAPTR record
304  * \param regexp_size The size of the regexp string
305  *
306  * \retval 0 regexp is valid
307  * \retval non-zero regexp is invalid
308  */
309 static int regexp_invalid(const char *regexp, uint8_t regexp_size)
310 {
311  char delim;
312  const char *delim2_pos;
313  const char *delim3_pos;
314  const char *ptr = regexp;
315  const char *end_of_regexp = regexp + regexp_size;
316  const char *regex_pos;
317  const char *repl_pos;
318  const char *flags_pos;
319 
320  if (regexp_size == 0) {
321  return 0;
322  }
323 
324  /* The delimiter will be a ! or / in most cases, but the rules allow
325  * for the delimiter to be nearly any character. It cannot be 'i' because
326  * the delimiter cannot be the same as regexp flags. The delimiter cannot
327  * be 1-9 because the delimiter cannot be a backreference number. RFC
328  * 2915 specified that backslash was also not allowed as a delimiter, but
329  * RFC 3402 does not say this. We've gone ahead and made the character
330  * illegal for our purposes.
331  */
332  delim = *ptr;
333  if (strchr("123456789\\i", delim)) {
334  return -1;
335  }
336  ++ptr;
337  regex_pos = ptr;
338 
339  /* Find the other two delimiters. If the delim is escaped with a backslash, it doesn't count */
340  while (1) {
341  delim2_pos = memchr(ptr, delim, end_of_regexp - ptr);
342  if (!delim2_pos) {
343  return -1;
344  }
345  ptr = delim2_pos + 1;
346  if (delim2_pos[-1] != '\\') {
347  break;
348  }
349  }
350 
351  if (ptr >= end_of_regexp) {
352  return -1;
353  }
354 
355  repl_pos = ptr;
356 
357  while (1) {
358  delim3_pos = memchr(ptr, delim, end_of_regexp - ptr);
359  if (!delim3_pos) {
360  return -1;
361  }
362  ptr = delim3_pos + 1;
363  if (delim3_pos[-1] != '\\') {
364  break;
365  }
366  }
367  flags_pos = ptr;
368 
369  if (regexp_flags_invalid(flags_pos, end_of_regexp) ||
370  regexp_repl_invalid(repl_pos, delim3_pos, delim) ||
371  regexp_pattern_invalid(regex_pos, delim2_pos)) {
372  return -1;
373  }
374 
375  return 0;
376 }
377 
378 #define PAST_END_OF_RECORD ptr >= end_of_record
379 
380 struct ast_dns_record *dns_naptr_alloc(struct ast_dns_query *query, const char *data, const size_t size)
381 {
382  struct ast_dns_naptr_record *naptr;
383  char *ptr = NULL;
384  uint16_t order;
385  uint16_t preference;
386  uint8_t flags_size;
387  char *flags;
388  uint8_t services_size;
389  char *services;
390  uint8_t regexp_size;
391  char *regexp;
392  char replacement[256] = "";
393  int replacement_size;
394  const char *end_of_record;
395  enum flags_result flags_res;
396  size_t naptr_len;
397 
398  ptr = dns_find_record(data, size, query->result->answer, query->result->answer_size);
399  ast_assert(ptr != NULL);
400 
401  end_of_record = ptr + size;
402 
403  /* ORDER */
404  /* This assignment takes a big-endian 16-bit value and stores it in the
405  * machine's native byte order. Using this method allows us to avoid potential
406  * alignment issues in case the order is not on a short-addressable boundary.
407  * See http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html for
408  * more information
409  */
410  ptr += dns_parse_short((unsigned char *) ptr, &order);
411  if (PAST_END_OF_RECORD) {
412  return NULL;
413  }
414 
415  /* PREFERENCE */
416  ptr += dns_parse_short((unsigned char *) ptr, &preference);
417  if (PAST_END_OF_RECORD) {
418  return NULL;
419  }
420 
421  /* FLAGS */
422  ptr += dns_parse_string(ptr, &flags_size, &flags);
423  if (PAST_END_OF_RECORD) {
424  return NULL;
425  }
426 
427  /* SERVICES */
428  ptr += dns_parse_string(ptr, &services_size, &services);
429  if (PAST_END_OF_RECORD) {
430  return NULL;
431  }
432 
433  /* REGEXP */
434  ptr += dns_parse_string(ptr, &regexp_size, &regexp);
435  if (PAST_END_OF_RECORD) {
436  return NULL;
437  }
438 
439  /*
440  * The return value from dn_expand represents the size of the replacement
441  * in the buffer which MAY be compressed. Since the expanded replacement
442  * is NULL terminated, you can use strlen() to get the expanded size.
443  */
444  replacement_size = dn_expand((unsigned char *)query->result->answer,
445  (unsigned char *) end_of_record, (unsigned char *) ptr,
446  replacement, sizeof(replacement) - 1);
447  if (replacement_size < 0) {
448  ast_log(LOG_ERROR, "Failed to expand domain name: %s\n", strerror(errno));
449  return NULL;
450  }
451 
452  ptr += replacement_size;
453 
454  if (ptr != end_of_record) {
455  ast_log(LOG_ERROR, "NAPTR record gave undersized string indications.\n");
456  return NULL;
457  }
458 
459  /* We've validated the size of the NAPTR record. Now we can validate
460  * the individual parts
461  */
462  flags_res = interpret_flags(flags, flags_size);
463  if (flags_res == FLAGS_INVALID) {
464  ast_log(LOG_ERROR, "NAPTR Record contained invalid flags %.*s\n", flags_size, flags);
465  return NULL;
466  }
467 
468  if (services_invalid(services, services_size)) {
469  ast_log(LOG_ERROR, "NAPTR record contained invalid services %.*s\n", services_size, services);
470  return NULL;
471  }
472 
473  if (regexp_invalid(regexp, regexp_size)) {
474  ast_log(LOG_ERROR, "NAPTR record contained invalid regexp %.*s\n", regexp_size, regexp);
475  return NULL;
476  }
477 
478  /* replacement_size takes into account the NULL label, so a NAPTR record with no replacement
479  * will have a replacement_size of 1.
480  */
481  if (regexp_size && replacement_size > 1) {
482  ast_log(LOG_ERROR, "NAPTR record contained both a regexp and replacement\n");
483  return NULL;
484  }
485 
486  naptr_len = sizeof(*naptr) + size + flags_size + 1 + services_size + 1
487  + regexp_size + 1 + strlen(replacement) + 1;
488  naptr = ast_calloc(1, naptr_len);
489  if (!naptr) {
490  return NULL;
491  }
492 
493  naptr->order = order;
494  naptr->preference = preference;
495 
496  ptr = naptr->data;
497  ptr += size;
498 
499  strncpy(ptr, flags, flags_size);
500  ptr[flags_size] = '\0';
501  naptr->flags = ptr;
502  ptr += flags_size + 1;
503 
504  strncpy(ptr, services, services_size);
505  ptr[services_size] = '\0';
506  naptr->service = ptr;
507  ptr += services_size + 1;
508 
509  strncpy(ptr, regexp, regexp_size);
510  ptr[regexp_size] = '\0';
511  naptr->regexp = ptr;
512  ptr += regexp_size + 1;
513 
514  strcpy(ptr, replacement);
515  naptr->replacement = ptr;
516 
517  naptr->generic.data_ptr = naptr->data;
518 
519  return (struct ast_dns_record *)naptr;
520 }
521 
522 
523 static int compare_order(const void *record1, const void *record2)
524 {
525  const struct ast_dns_naptr_record **left = (const struct ast_dns_naptr_record **)record1;
526  const struct ast_dns_naptr_record **right = (const struct ast_dns_naptr_record **)record2;
527 
528  if ((*left)->order < (*right)->order) {
529  return -1;
530  } else if ((*left)->order > (*right)->order) {
531  return 1;
532  } else {
533  return 0;
534  }
535 }
536 
537 static int compare_preference(const void *record1, const void *record2)
538 {
539  const struct ast_dns_naptr_record **left = (const struct ast_dns_naptr_record **)record1;
540  const struct ast_dns_naptr_record **right = (const struct ast_dns_naptr_record **)record2;
541 
542  if ((*left)->preference < (*right)->preference) {
543  return -1;
544  } else if ((*left)->preference > (*right)->preference) {
545  return 1;
546  } else {
547  return 0;
548  }
549 }
550 
552 {
553  struct ast_dns_record *current;
554  size_t num_records = 0;
555  struct ast_dns_naptr_record **records;
556  int i = 0;
557  int j = 0;
558  int cur_order;
559 
560  /* Determine the number of records */
561  AST_LIST_TRAVERSE(&result->records, current, list) {
562  ++num_records;
563  }
564 
565  /* No point in continuing if there are no records */
566  if (num_records == 0) {
567  return;
568  }
569 
570  /* Allocate an array with that number of records */
571  records = ast_alloca(num_records * sizeof(*records));
572 
573  /* Move records from the list to the array */
574  AST_LIST_TRAVERSE_SAFE_BEGIN(&result->records, current, list) {
575  records[i++] = (struct ast_dns_naptr_record *) current;
577  }
579 
580  /* Sort the array by order */
581  qsort(records, num_records, sizeof(*records), compare_order);
582 
583  /* Sort subarrays by preference */
584  for (i = 0; i < num_records; i = j) {
585  cur_order = records[i]->order;
586  for (j = i + 1; j < num_records; ++j) {
587  if (records[j]->order != cur_order) {
588  break;
589  }
590  }
591  qsort(&records[i], j - i, sizeof(*records), compare_preference);
592  }
593 
594  /* Place sorted records back into the original list */
595  for (i = 0; i < num_records; ++i) {
596  AST_LIST_INSERT_TAIL(&result->records, (struct ast_dns_record *)(records[i]), list);
597  }
598 }
599 
600 const char *ast_dns_naptr_get_flags(const struct ast_dns_record *record)
601 {
602  struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record;
603 
604  ast_assert(ast_dns_record_get_rr_type(record) == T_NAPTR);
605  return naptr->flags;
606 }
607 
608 const char *ast_dns_naptr_get_service(const struct ast_dns_record *record)
609 {
610  struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record;
611 
612  ast_assert(ast_dns_record_get_rr_type(record) == T_NAPTR);
613  return naptr->service;
614 }
615 
616 const char *ast_dns_naptr_get_regexp(const struct ast_dns_record *record)
617 {
618  struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record;
619 
620  ast_assert(ast_dns_record_get_rr_type(record) == T_NAPTR);
621  return naptr->regexp;
622 }
623 
624 const char *ast_dns_naptr_get_replacement(const struct ast_dns_record *record)
625 {
626  struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record;
627 
628  ast_assert(ast_dns_record_get_rr_type(record) == T_NAPTR);
629  return naptr->replacement;
630 }
631 
632 unsigned short ast_dns_naptr_get_order(const struct ast_dns_record *record)
633 {
634  struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record;
635 
636  ast_assert(ast_dns_record_get_rr_type(record) == T_NAPTR);
637  return naptr->order;
638 }
639 
640 unsigned short ast_dns_naptr_get_preference(const struct ast_dns_record *record)
641 {
642  struct ast_dns_naptr_record *naptr = (struct ast_dns_naptr_record *) record;
643 
644  ast_assert(ast_dns_record_get_rr_type(record) == T_NAPTR);
645  return naptr->preference;
646 }
static int records
Definition: cdr_mysql.c:84
Asterisk main include file. File version handling, generic pbx functions.
void dns_naptr_sort(struct ast_dns_result *result)
Sort the NAPTR records on a result.
Definition: dns_naptr.c:551
int dns_parse_string(char *cur, uint8_t *size, char **val)
Parse a DNS string from a DNS record.
Definition: dns_core.c:734
static int compare_order(const void *record1, const void *record2)
Definition: dns_naptr.c:523
const char * replacement
The replacement from the NAPTR record.
Definition: dns_internal.h:102
char * data_ptr
pointer to record-specific data.
Definition: dns_internal.h:58
const char * ast_dns_naptr_get_flags(const struct ast_dns_record *record)
Get the flags from a NAPTR record.
Definition: dns_naptr.c:600
For AST_LIST.
Definition: dns_internal.h:39
const char * flags
The flags from the NAPTR record.
Definition: dns_internal.h:96
int dns_parse_short(unsigned char *cur, uint16_t *val)
Parse a 16-bit unsigned value from a DNS record.
Definition: dns_core.c:722
#define ast_assert(a)
Definition: utils.h:695
static int regexp_flags_invalid(const char *flags, const char *end)
Determine if flags in the regexp are invalid.
Definition: dns_naptr.c:189
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
const char * regexp
The regular expression from the NAPTR record.
Definition: dns_internal.h:100
Utility functions.
unsigned short ast_dns_naptr_get_order(const struct ast_dns_record *record)
Get the order from a NAPTR record.
Definition: dns_naptr.c:632
static int services_invalid(const char *services, uint8_t services_size)
Analyze NAPTR services for validity as defined by RFC 3404.
Definition: dns_naptr.c:130
static int compare_preference(const void *record1, const void *record2)
Definition: dns_naptr.c:537
#define ast_log
Definition: astobj2.c:42
integer order
Definition: analys.c:66
static int regexp_repl_invalid(const char *repl, const char *end, char delim)
Determine if the replacement in the regexp is invalid.
Definition: dns_naptr.c:228
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
A set of macros to manage forward-linked lists.
unsigned short ast_dns_naptr_get_preference(const struct ast_dns_record *record)
Get the preference from a NAPTR record.
Definition: dns_naptr.c:640
struct ast_dns_record * dns_naptr_alloc(struct ast_dns_query *query, const char *data, const size_t size)
Allocate and parse a DNS NAPTR record.
Definition: dns_naptr.c:380
const char * ast_dns_naptr_get_service(const struct ast_dns_record *record)
Get the service from a NAPTR record.
Definition: dns_naptr.c:608
char data[0]
The raw DNS record.
Definition: dns_internal.h:60
const char * service
The service from the NAPTR record.
Definition: dns_internal.h:98
The result of a DNS query.
Definition: dns_internal.h:117
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
#define PAST_END_OF_RECORD
Definition: dns_naptr.c:378
static enum flags_result interpret_flags(const char *flags, uint8_t flags_size)
Analyze and interpret NAPTR flags as per RFC 3404.
Definition: dns_naptr.c:66
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
char data[0]
Buffer for NAPTR-specific data.
Definition: dns_internal.h:113
struct ast_dns_result * result
Result of the DNS query.
Definition: dns_internal.h:147
const char * ast_dns_naptr_get_replacement(const struct ast_dns_record *record)
Get the replacement value from a NAPTR record.
Definition: dns_naptr.c:624
int errno
static int regexp_pattern_invalid(const char *pattern, const char *end)
Determine if the pattern in a regexp is invalid.
Definition: dns_naptr.c:275
const char * ast_dns_naptr_get_regexp(const struct ast_dns_record *record)
Get the regular expression from a NAPTR record.
Definition: dns_naptr.c:616
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
Internal DNS structure definitions.
A DNS query.
Definition: dns_internal.h:137
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
unsigned short preference
The preference of the NAPTR record.
Definition: dns_internal.h:106
Definition: enum.h:28
flags_result
Result of analyzing NAPTR flags on a record.
Definition: dns_naptr.c:46
static int regexp_invalid(const char *regexp, uint8_t regexp_size)
Determine if the regexp in a NAPTR record is invalid.
Definition: dns_naptr.c:309
DNS NAPTR Record Parsing API.
struct ast_dns_record generic
Generic DNS record information.
Definition: dns_internal.h:94
static PGresult * result
Definition: cel_pgsql.c:88
A NAPTR record.
Definition: dns_internal.h:92
char * dns_find_record(const char *record, size_t record_size, const char *response, size_t response_size)
Find the location of a DNS record within the entire DNS answer.
Definition: dns_core.c:701
size_t answer_size
The size of the raw DNS answer.
Definition: dns_internal.h:131
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
int ast_dns_record_get_rr_type(const struct ast_dns_record *record)
Get the resource record type of a DNS record.
Definition: dns_core.c:145
const char * answer
The raw DNS answer.
Definition: dns_internal.h:129
struct ast_dns_result::dns_records records
unsigned short order
The order for the NAPTR record.
Definition: dns_internal.h:104
Core DNS API.