dns_internal.h File Reference

Internal DNS structure definitions. More...

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_dns_naptr_record
 A NAPTR record. More...
struct  ast_dns_query
 A DNS query. More...
struct  ast_dns_query_active
 An active DNS query. More...
struct  ast_dns_query_recurring
 A recurring DNS query. More...
struct  ast_dns_record
 Generic DNS record information. More...
struct  ast_dns_result
 The result of a DNS query. More...
struct  ast_dns_srv_record
 An SRV record. More...

Functions

struct ast_sched_contextast_dns_get_sched (void)
 Retrieve the DNS scheduler context.
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.
struct ast_dns_recorddns_naptr_alloc (struct ast_dns_query *query, const char *data, const size_t size)
 Allocate and parse a DNS NAPTR record.
void dns_naptr_sort (struct ast_dns_result *result)
 Sort the NAPTR records on a result.
int dns_parse_short (unsigned char *cur, uint16_t *val)
 Parse a 16-bit unsigned value from a DNS record.
int dns_parse_string (char *cur, uint8_t *size, char **val)
 Parse a DNS string from a DNS record.
struct ast_dns_recorddns_srv_alloc (struct ast_dns_query *query, const char *data, const size_t size)
 Allocate and parse a DNS SRV record.
void dns_srv_sort (struct ast_dns_result *result)
 Sort the SRV records on a result.


Detailed Description

Internal DNS structure definitions.

Author:
Joshua Colp <jcolp@digium.com>

Definition in file dns_internal.h.


Function Documentation

struct ast_sched_context* ast_dns_get_sched ( void   )  [read]

Retrieve the DNS scheduler context.

Returns:
scheduler context

Definition at line 53 of file dns_core.c.

Referenced by ast_dns_resolve_recurring(), ast_dns_resolve_recurring_cancel(), and dns_query_recurring_resolution_callback().

00054 {
00055    return sched;
00056 }

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.

The DNS record that has been returned by the resolver may be a copy of the record that was found in the complete DNS response. If so, then some DNS record types (specifically those that parse domains) will need to locate the DNS record within the complete DNS response. This is so that if the domain contains pointers to other sections of the DNS response, then the referenced domains may be located.

Parameters:
record The DNS record returned by a resolver implementation
record_size The size of the DNS record in bytes
response The complete DNS answer
response_size The size of the complete DNS response

Definition at line 614 of file dns_core.c.

References ast_assert, and NULL.

Referenced by dns_naptr_alloc(), and dns_srv_alloc().

00615 {
00616    size_t remaining_size = response_size;
00617    const char *search_base = response;
00618    char *record_offset;
00619 
00620    while (1) {
00621       record_offset = memchr(search_base, record[0], remaining_size);
00622 
00623       ast_assert(record_offset != NULL);
00624       ast_assert(search_base + remaining_size - record_offset >= record_size);
00625 
00626       if (!memcmp(record_offset, record, record_size)) {
00627          return record_offset;
00628       }
00629 
00630       remaining_size -= record_offset - search_base;
00631       search_base = record_offset + 1;
00632    }
00633 }

struct ast_dns_record* dns_naptr_alloc ( struct ast_dns_query query,
const char *  data,
const size_t  size 
) [read]

Allocate and parse a DNS NAPTR record.

Parameters:
query The DNS query
data This specific NAPTR record
size The size of the NAPTR record
Return values:
non-NULL success
NULL failure

Definition at line 381 of file dns_naptr.c.

References ast_dns_result::answer, ast_dns_result::answer_size, ast_assert, ast_calloc, ast_log, ast_dns_naptr_record::data, ast_dns_record::data_ptr, dns_find_record(), dns_parse_short(), dns_parse_string(), errno, ast_dns_naptr_record::flags, FLAGS_INVALID, ast_dns_naptr_record::generic, interpret_flags(), LOG_ERROR, NULL, ast_dns_naptr_record::order, order, PAST_END_OF_RECORD, ast_dns_naptr_record::preference, ast_dns_naptr_record::regexp, regexp_invalid(), ast_dns_naptr_record::replacement, ast_dns_query::result, ast_dns_naptr_record::service, and services_invalid().

00382 {
00383    struct ast_dns_naptr_record *naptr;
00384    char *ptr = NULL;
00385    uint16_t order;
00386    uint16_t preference;
00387    uint8_t flags_size;
00388    char *flags;
00389    uint8_t services_size;
00390    char *services;
00391    uint8_t regexp_size;
00392    char *regexp;
00393    char replacement[256] = "";
00394    int replacement_size;
00395    const char *end_of_record;
00396    enum flags_result flags_res;
00397 
00398    ptr = dns_find_record(data, size, query->result->answer, query->result->answer_size);
00399    ast_assert(ptr != NULL);
00400 
00401    end_of_record = ptr + size;
00402 
00403    /* ORDER */
00404    /* This assignment takes a big-endian 16-bit value and stores it in the
00405     * machine's native byte order. Using this method allows us to avoid potential
00406     * alignment issues in case the order is not on a short-addressable boundary.
00407     * See http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html for
00408     * more information
00409     */
00410    ptr += dns_parse_short((unsigned char *) ptr, &order);
00411    if (PAST_END_OF_RECORD) {
00412       return NULL;
00413    }
00414 
00415    /* PREFERENCE */
00416    ptr += dns_parse_short((unsigned char *) ptr, &preference);
00417    if (PAST_END_OF_RECORD) {
00418       return NULL;
00419    }
00420 
00421    /* FLAGS */
00422    ptr += dns_parse_string(ptr, &flags_size, &flags);
00423    if (PAST_END_OF_RECORD) {
00424       return NULL;
00425    }
00426 
00427    /* SERVICES */
00428    ptr += dns_parse_string(ptr, &services_size, &services);
00429    if (PAST_END_OF_RECORD) {
00430       return NULL;
00431    }
00432 
00433    /* REGEXP */
00434    ptr += dns_parse_string(ptr, &regexp_size, &regexp);
00435    if (PAST_END_OF_RECORD) {
00436       return NULL;
00437    }
00438 
00439    replacement_size = dn_expand((unsigned char *)query->result->answer, (unsigned char *) end_of_record, (unsigned char *) ptr, replacement, sizeof(replacement) - 1);
00440    if (replacement_size < 0) {
00441       ast_log(LOG_ERROR, "Failed to expand domain name: %s\n", strerror(errno));
00442       return NULL;
00443    }
00444 
00445    ptr += replacement_size;
00446 
00447    if (ptr != end_of_record) {
00448       ast_log(LOG_ERROR, "NAPTR record gave undersized string indications.\n");
00449       return NULL;
00450    }
00451 
00452    /* We've validated the size of the NAPTR record. Now we can validate
00453     * the individual parts
00454     */
00455    flags_res = interpret_flags(flags, flags_size);
00456    if (flags_res == FLAGS_INVALID) {
00457       ast_log(LOG_ERROR, "NAPTR Record contained invalid flags %.*s\n", flags_size, flags);
00458       return NULL;
00459    }
00460 
00461    if (services_invalid(services, services_size)) {
00462       ast_log(LOG_ERROR, "NAPTR record contained invalid services %.*s\n", services_size, services);
00463       return NULL;
00464    }
00465 
00466    if (regexp_invalid(regexp, regexp_size)) {
00467       ast_log(LOG_ERROR, "NAPTR record contained invalid regexp %.*s\n", regexp_size, regexp);
00468       return NULL;
00469    }
00470 
00471    /* replacement_size takes into account the NULL label, so a NAPTR record with no replacement
00472     * will have a replacement_size of 1.
00473     */
00474    if (regexp_size && replacement_size > 1) {
00475       ast_log(LOG_ERROR, "NAPTR record contained both a regexp and replacement\n");
00476       return NULL;
00477    }
00478 
00479    naptr = ast_calloc(1, sizeof(*naptr) + size + flags_size + 1 + services_size + 1 + regexp_size + 1 + replacement_size + 1);
00480    if (!naptr) {
00481       return NULL;
00482    }
00483 
00484    naptr->order = order;
00485    naptr->preference = preference;
00486 
00487    ptr = naptr->data;
00488    ptr += size;
00489 
00490    strncpy(ptr, flags, flags_size);
00491    ptr[flags_size] = '\0';
00492    naptr->flags = ptr;
00493    ptr += flags_size + 1;
00494 
00495    strncpy(ptr, services, services_size);
00496    ptr[services_size] = '\0';
00497    naptr->service = ptr;
00498    ptr += services_size + 1;
00499 
00500    strncpy(ptr, regexp, regexp_size);
00501    ptr[regexp_size] = '\0';
00502    naptr->regexp = ptr;
00503    ptr += regexp_size + 1;
00504 
00505    strcpy(ptr, replacement);
00506    naptr->replacement = ptr;
00507 
00508    naptr->generic.data_ptr = naptr->data;
00509 
00510    return (struct ast_dns_record *)naptr;
00511 }

void dns_naptr_sort ( struct ast_dns_result result  ) 

Sort the NAPTR records on a result.

Parameters:
result The DNS result

Definition at line 542 of file dns_naptr.c.

References ast_alloca, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, compare_order(), compare_preference(), order, ast_dns_naptr_record::order, and records.

00543 {
00544    struct ast_dns_record *current;
00545    size_t num_records = 0;
00546    struct ast_dns_naptr_record **records;
00547    int i = 0;
00548    int j = 0;
00549    int cur_order;
00550 
00551    /* Determine the number of records */
00552    AST_LIST_TRAVERSE(&result->records, current, list) {
00553       ++num_records;
00554    }
00555 
00556    /* No point in continuing if there are no records */
00557    if (num_records == 0) {
00558       return;
00559    }
00560 
00561    /* Allocate an array with that number of records */
00562    records = ast_alloca(num_records * sizeof(*records));
00563 
00564    /* Move records from the list to the array */
00565    AST_LIST_TRAVERSE_SAFE_BEGIN(&result->records, current, list) {
00566       records[i++] = (struct ast_dns_naptr_record *) current;
00567       AST_LIST_REMOVE_CURRENT(list);
00568    }
00569    AST_LIST_TRAVERSE_SAFE_END;
00570 
00571    /* Sort the array by order */
00572    qsort(records, num_records, sizeof(*records), compare_order);
00573 
00574    /* Sort subarrays by preference */
00575    for (i = 0; i < num_records; i = j) {
00576       cur_order = records[i]->order;
00577       for (j = i + 1; j < num_records; ++j) {
00578          if (records[j]->order != cur_order) {
00579             break;
00580          }
00581       }
00582       qsort(&records[i], j - i, sizeof(*records), compare_preference);
00583    }
00584 
00585    /* Place sorted records back into the original list */
00586    for (i = 0; i < num_records; ++i) {
00587       AST_LIST_INSERT_TAIL(&result->records, (struct ast_dns_record *)(records[i]), list);
00588    }
00589 }

int dns_parse_short ( unsigned char *  cur,
uint16_t *  val 
)

Parse a 16-bit unsigned value from a DNS record.

Parameters:
cur Pointer to the location of the 16-bit value in the DNS record
[out] val The parsed 16-bit unsigned integer
Returns:
The number of bytes consumed while parsing

Definition at line 635 of file dns_core.c.

Referenced by dns_naptr_alloc(), and dns_srv_alloc().

00636 {
00637    /* This assignment takes a big-endian 16-bit value and stores it in the
00638     * machine's native byte order. Using this method allows us to avoid potential
00639     * alignment issues in case the order is not on a short-addressable boundary.
00640     * See http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html for
00641     * more information
00642     */
00643    *val = (cur[1] << 0) | (cur[0] << 8);
00644    return sizeof(*val);
00645 }

int dns_parse_string ( char *  cur,
uint8_t *  size,
char **  val 
)

Parse a DNS string from a DNS record.

A DNS string consists of an 8-bit size, followed by the string value (not NULL-terminated).

Parameters:
cur Pointer to the location of the DNS string
[out] size The parsed size of the DNS string
[out] val The contained string (not NULL-terminated)
Returns:
The number of bytes consumed while parsing

Definition at line 647 of file dns_core.c.

Referenced by dns_naptr_alloc().

00648 {
00649    *size = *cur++;
00650    *val = cur;
00651    return *size + 1;
00652 }

struct ast_dns_record* dns_srv_alloc ( struct ast_dns_query query,
const char *  data,
const size_t  size 
) [read]

Allocate and parse a DNS SRV record.

Parameters:
query The DNS query
data This specific SRV record
size The size of the SRV record
Return values:
non-NULL success
NULL failure

Definition at line 44 of file dns_srv.c.

References ast_dns_result::answer, ast_dns_result::answer_size, ast_assert, ast_calloc, ast_log, ast_dns_srv_record::data, ast_dns_record::data_ptr, dns_find_record(), dns_parse_short(), errno, ast_dns_srv_record::generic, ast_dns_srv_record::host, host, LOG_ERROR, NULL, ast_dns_srv_record::port, ast_dns_srv_record::priority, ast_dns_query::result, ast_dns_srv_record::weight, and weight.

00045 {
00046    uint16_t priority;
00047    uint16_t weight;
00048    uint16_t port;
00049    const char *ptr;
00050    const char *end_of_record;
00051    struct ast_dns_srv_record *srv;
00052    int host_size;
00053    char host[NI_MAXHOST] = "";
00054 
00055    ptr = dns_find_record(data, size, query->result->answer, query->result->answer_size);
00056    ast_assert(ptr != NULL);
00057 
00058    end_of_record = ptr + size;
00059 
00060    /* PRIORITY */
00061    ptr += dns_parse_short((unsigned char *) ptr, &priority);
00062    if (ptr >= end_of_record) {
00063       return NULL;
00064    }
00065 
00066    /* WEIGHT */
00067    ptr += dns_parse_short((unsigned char *) ptr, &weight);
00068    if (ptr >= end_of_record) {
00069       return NULL;
00070    }
00071 
00072    /* PORT */
00073    ptr += dns_parse_short((unsigned char *) ptr, &port);
00074    if (ptr >= end_of_record) {
00075       return NULL;
00076    }
00077 
00078    host_size = dn_expand((unsigned char *)query->result->answer, (unsigned char *) end_of_record, (unsigned char *) ptr, host, sizeof(host) - 1);
00079    if (host_size < 0) {
00080       ast_log(LOG_ERROR, "Failed to expand domain name: %s\n", strerror(errno));
00081       return NULL;
00082    }
00083 
00084    if (!strcmp(host, ".")) {
00085       return NULL;
00086    }
00087 
00088    srv = ast_calloc(1, sizeof(*srv) + size + host_size + 1);
00089    if (!srv) {
00090       return NULL;
00091    }
00092 
00093    srv->priority = priority;
00094    srv->weight = weight;
00095    srv->port = port;
00096 
00097    srv->host = srv->data + size;
00098    strcpy((char *)srv->host, host); /* SAFE */
00099    ((char *)srv->host)[host_size] = '\0';
00100 
00101    srv->generic.data_ptr = srv->data;
00102 
00103    return (struct ast_dns_record *)srv;
00104 }

void dns_srv_sort ( struct ast_dns_result result  ) 

Sort the SRV records on a result.

Parameters:
result The DNS result

Definition at line 109 of file dns_srv.c.

References AST_LIST_APPEND_LIST, AST_LIST_FIRST, AST_LIST_HEAD_NOLOCK_INIT_VALUE, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_MOVE_CURRENT, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_random(), ast_dns_srv_record::priority, weight, and ast_dns_srv_record::weight_sum.

00110 {
00111    struct ast_dns_record *current;
00112    struct dns_records newlist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00113 
00114    while (AST_LIST_FIRST(&result->records)) {
00115       unsigned short cur_priority = 0;
00116       struct dns_records temp_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00117 
00118       /* Find the lowest current priority to work on */
00119       AST_LIST_TRAVERSE(&result->records, current, list) {
00120          if (!cur_priority || ((struct ast_dns_srv_record *)current)->priority < cur_priority) {
00121             cur_priority = ((struct ast_dns_srv_record *)current)->priority;
00122          }
00123       }
00124 
00125       /* Find all records which match this priority */
00126       AST_LIST_TRAVERSE_SAFE_BEGIN(&result->records, current, list) {
00127          if (((struct ast_dns_srv_record *)current)->priority != cur_priority) {
00128             continue;
00129          }
00130 
00131          AST_LIST_REMOVE_CURRENT(list);
00132 
00133          /* Records with a weight of zero must always be at the head */
00134          if (((struct ast_dns_srv_record *)current)->weight == 0) {
00135             AST_LIST_INSERT_HEAD(&temp_list, current, list);
00136          } else {
00137             AST_LIST_INSERT_TAIL(&temp_list, current, list);
00138          }
00139       }
00140       AST_LIST_TRAVERSE_SAFE_END;
00141 
00142       /* Apply weighting - as each record is passed the sum of all previous weights (plus its own) is stored away, and then a random weight
00143        * is calculated. The first record with a weight sum greater than the random weight is put in the new list and the whole thing starts
00144        * once again.
00145        */
00146       while (AST_LIST_FIRST(&temp_list)) {
00147          unsigned int weight_sum = 0;
00148          unsigned int random_weight;
00149 
00150          AST_LIST_TRAVERSE(&temp_list, current, list) {
00151             ((struct ast_dns_srv_record *)current)->weight_sum = weight_sum += ((struct ast_dns_srv_record *)current)->weight;
00152          }
00153 
00154          /* if all the remaining entries have weight == 0,
00155             then just append them to the result list and quit */
00156          if (weight_sum == 0) {
00157             AST_LIST_APPEND_LIST(&newlist, &temp_list, list);
00158             break;
00159          }
00160 
00161          random_weight = 1 + (unsigned int) ((float) weight_sum * (ast_random() / ((float) RAND_MAX + 1.0)));
00162 
00163          AST_LIST_TRAVERSE_SAFE_BEGIN(&temp_list, current, list) {
00164             if (((struct ast_dns_srv_record *)current)->weight_sum < random_weight) {
00165                continue;
00166             }
00167 
00168             AST_LIST_MOVE_CURRENT(&newlist, list);
00169             break;
00170          }
00171          AST_LIST_TRAVERSE_SAFE_END;
00172       }
00173 
00174    }
00175 
00176    /* now that the new list has been ordered,
00177       put it in place */
00178 
00179    AST_LIST_APPEND_LIST(&result->records, &newlist, list);
00180 }


Generated on Thu Apr 16 06:30:42 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6