Asterisk - The Open Source Telephony Project GIT-master-f36a736
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 <jcolp@digium.com>
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 <jcolp@digium.com>
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"
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 * \param flags_size The size of the flags string in bytes
64 * \return flag result
65 */
66static 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 */
130static 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 */
189static 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 */
228static 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 */
275static 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 */
309static 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
380struct ast_dns_record *dns_naptr_alloc(struct ast_dns_query *query, const char *data, const size_t size)
381{
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
523static 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
537static 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;
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 */
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
600const 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
608const 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
616const 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
624const 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
632unsigned 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
640unsigned 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}
integer order
Definition: analys.c:66
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
static int records
Definition: cdr_pgsql.c:78
static PGresult * result
Definition: cel_pgsql.c:84
Core DNS API.
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
Internal DNS structure definitions.
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:703
int dns_parse_short(unsigned char *cur, uint16_t *val)
Parse a 16-bit unsigned value from a DNS record.
Definition: dns_core.c:724
int dns_parse_string(char *cur, uint8_t *size, char **val)
Parse a DNS string from a DNS record.
Definition: dns_core.c:736
void dns_naptr_sort(struct ast_dns_result *result)
Sort the NAPTR records on a result.
Definition: dns_naptr.c:551
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
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
#define PAST_END_OF_RECORD
Definition: dns_naptr.c:378
static int regexp_flags_invalid(const char *flags, const char *end)
Determine if flags in the regexp are invalid.
Definition: dns_naptr.c:189
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
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
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
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_service(const struct ast_dns_record *record)
Get the service from a NAPTR record.
Definition: dns_naptr.c:608
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 regexp_invalid(const char *regexp, uint8_t regexp_size)
Determine if the regexp in a NAPTR record is invalid.
Definition: dns_naptr.c:309
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
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 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
static int compare_order(const void *record1, const void *record2)
Definition: dns_naptr.c:523
flags_result
Result of analyzing NAPTR flags on a record.
Definition: dns_naptr.c:46
@ FLAGS_INVALID
Definition: dns_naptr.c:54
@ FLAGS_UNKNOWN
Definition: dns_naptr.c:52
@ FLAGS_TERMINAL
Definition: dns_naptr.c:48
@ FLAGS_EMPTY
Definition: dns_naptr.c:50
static int compare_preference(const void *record1, const void *record2)
Definition: dns_naptr.c:537
DNS NAPTR Record Parsing API.
char * end
Definition: eagi_proxy.c:73
#define LOG_ERROR
A set of macros to manage forward-linked lists.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
size_t current
Definition: main/cli.c:113
int errno
#define NULL
Definition: resample.c:96
A NAPTR record.
Definition: dns_internal.h:92
unsigned short preference
The preference of the NAPTR record.
Definition: dns_internal.h:106
const char * regexp
The regular expression from the NAPTR record.
Definition: dns_internal.h:100
char data[0]
Buffer for NAPTR-specific data.
Definition: dns_internal.h:113
const char * flags
The flags from the NAPTR record.
Definition: dns_internal.h:96
const char * replacement
The replacement from the NAPTR record.
Definition: dns_internal.h:102
A DNS query.
Definition: dns_internal.h:137
struct ast_dns_result * result
Result of the DNS query.
Definition: dns_internal.h:147
For AST_LIST.
Definition: dns_internal.h:39
char data[0]
The raw DNS record.
Definition: dns_internal.h:60
The result of a DNS query.
Definition: dns_internal.h:117
size_t answer_size
The size of the raw DNS answer.
Definition: dns_internal.h:131
const char * answer
The raw DNS answer.
Definition: dns_internal.h:129
Definition: enum.h:30
unsigned short order
Definition: enum.h:31
Utility functions.
#define ast_assert(a)
Definition: utils.h:739