Asterisk - The Open Source Telephony Project  18.5.0
Macros | Enumerations | Functions
dns_naptr.c File Reference

DNS NAPTR Record Support. More...

#include "asterisk.h"
#include <arpa/nameser.h>
#include <netinet/in.h>
#include <resolv.h>
#include <regex.h>
#include "asterisk/dns_core.h"
#include "asterisk/dns_naptr.h"
#include "asterisk/linkedlists.h"
#include "asterisk/dns_internal.h"
#include "asterisk/utils.h"
Include dependency graph for dns_naptr.c:

Go to the source code of this file.

Macros

#define PAST_END_OF_RECORD   ptr >= end_of_record
 

Enumerations

enum  flags_result { FLAGS_TERMINAL, FLAGS_EMPTY, FLAGS_UNKNOWN, FLAGS_INVALID }
 Result of analyzing NAPTR flags on a record. More...
 

Functions

const char * ast_dns_naptr_get_flags (const struct ast_dns_record *record)
 Get the flags from a NAPTR record. More...
 
unsigned short ast_dns_naptr_get_order (const struct ast_dns_record *record)
 Get the order from a NAPTR record. More...
 
unsigned short ast_dns_naptr_get_preference (const struct ast_dns_record *record)
 Get the preference from a NAPTR record. More...
 
const char * ast_dns_naptr_get_regexp (const struct ast_dns_record *record)
 Get the regular expression from a NAPTR record. More...
 
const char * ast_dns_naptr_get_replacement (const struct ast_dns_record *record)
 Get the replacement value from a NAPTR record. More...
 
const char * ast_dns_naptr_get_service (const struct ast_dns_record *record)
 Get the service from a NAPTR record. More...
 
static int compare_order (const void *record1, const void *record2)
 
static int compare_preference (const void *record1, const void *record2)
 
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. More...
 
void dns_naptr_sort (struct ast_dns_result *result)
 Sort the NAPTR records on a result. More...
 
static enum flags_result interpret_flags (const char *flags, uint8_t flags_size)
 Analyze and interpret NAPTR flags as per RFC 3404. More...
 
static int regexp_flags_invalid (const char *flags, const char *end)
 Determine if flags in the regexp are invalid. More...
 
static int regexp_invalid (const char *regexp, uint8_t regexp_size)
 Determine if the regexp in a NAPTR record is invalid. More...
 
static int regexp_pattern_invalid (const char *pattern, const char *end)
 Determine if the pattern in a regexp is invalid. More...
 
static int regexp_repl_invalid (const char *repl, const char *end, char delim)
 Determine if the replacement in the regexp is invalid. More...
 
static int services_invalid (const char *services, uint8_t services_size)
 Analyze NAPTR services for validity as defined by RFC 3404. More...
 

Detailed Description

DNS NAPTR Record Support.

Author
Joshua Colp jcolp.nosp@m.@dig.nosp@m.ium.c.nosp@m.om

Definition in file dns_naptr.c.

Macro Definition Documentation

◆ PAST_END_OF_RECORD

#define PAST_END_OF_RECORD   ptr >= end_of_record

Definition at line 378 of file dns_naptr.c.

Referenced by dns_naptr_alloc().

Enumeration Type Documentation

◆ flags_result

Result of analyzing NAPTR flags on a record.

Enumerator
FLAGS_TERMINAL 

Terminal record, meaning the DDDS algorithm can be stopped

FLAGS_EMPTY 

No flags provided, likely meaning another NAPTR lookup

FLAGS_UNKNOWN 

Unrecognized but valid flags. We cannot conclude what they mean

FLAGS_INVALID 

Non-alphanumeric or invalid combination of flags

Definition at line 46 of file dns_naptr.c.

46  {
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 };

Function Documentation

◆ ast_dns_naptr_get_flags()

const char* ast_dns_naptr_get_flags ( const struct ast_dns_record record)

Get the flags from a NAPTR record.

Parameters
recordThe DNS record
Returns
the flags

Definition at line 600 of file dns_naptr.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_naptr_record::flags.

Referenced by AST_TEST_DEFINE(), and sip_resolve_handle_naptr().

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 }
const char * flags
The flags from the NAPTR record.
Definition: dns_internal.h:96
#define ast_assert(a)
Definition: utils.h:695
Definition: enum.h:28
A NAPTR record.
Definition: dns_internal.h:92
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

◆ ast_dns_naptr_get_order()

unsigned short ast_dns_naptr_get_order ( const struct ast_dns_record record)

Get the order from a NAPTR record.

Parameters
recordThe DNS record
Returns
the order

Definition at line 632 of file dns_naptr.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_naptr_record::order.

Referenced by AST_TEST_DEFINE(), and sip_resolve_callback().

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 }
#define ast_assert(a)
Definition: utils.h:695
Definition: enum.h:28
A NAPTR record.
Definition: dns_internal.h:92
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
unsigned short order
The order for the NAPTR record.
Definition: dns_internal.h:104

◆ ast_dns_naptr_get_preference()

unsigned short ast_dns_naptr_get_preference ( const struct ast_dns_record record)

Get the preference from a NAPTR record.

Parameters
recordThe DNS record
Returns
the preference

Definition at line 640 of file dns_naptr.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_naptr_record::preference.

Referenced by AST_TEST_DEFINE().

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 }
#define ast_assert(a)
Definition: utils.h:695
unsigned short preference
The preference of the NAPTR record.
Definition: dns_internal.h:106
Definition: enum.h:28
A NAPTR record.
Definition: dns_internal.h:92
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

◆ ast_dns_naptr_get_regexp()

const char* ast_dns_naptr_get_regexp ( const struct ast_dns_record record)

Get the regular expression from a NAPTR record.

Parameters
recordThe DNS record
Returns
the regular expression

Definition at line 616 of file dns_naptr.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_naptr_record::regexp.

Referenced by AST_TEST_DEFINE().

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 }
#define ast_assert(a)
Definition: utils.h:695
const char * regexp
The regular expression from the NAPTR record.
Definition: dns_internal.h:100
Definition: enum.h:28
A NAPTR record.
Definition: dns_internal.h:92
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

◆ ast_dns_naptr_get_replacement()

const char* ast_dns_naptr_get_replacement ( const struct ast_dns_record record)

Get the replacement value from a NAPTR record.

Parameters
recordThe DNS record
Returns
the replacement value

Definition at line 624 of file dns_naptr.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_naptr_record::replacement.

Referenced by AST_TEST_DEFINE(), and sip_resolve_handle_naptr().

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 }
const char * replacement
The replacement from the NAPTR record.
Definition: dns_internal.h:102
#define ast_assert(a)
Definition: utils.h:695
Definition: enum.h:28
A NAPTR record.
Definition: dns_internal.h:92
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

◆ ast_dns_naptr_get_service()

const char* ast_dns_naptr_get_service ( const struct ast_dns_record record)

Get the service from a NAPTR record.

Parameters
recordThe DNS record
Returns
the service

Definition at line 608 of file dns_naptr.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_naptr_record::service.

Referenced by AST_TEST_DEFINE(), and sip_resolve_handle_naptr().

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 }
#define ast_assert(a)
Definition: utils.h:695
const char * service
The service from the NAPTR record.
Definition: dns_internal.h:98
Definition: enum.h:28
A NAPTR record.
Definition: dns_internal.h:92
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

◆ compare_order()

static int compare_order ( const void *  record1,
const void *  record2 
)
static

Definition at line 523 of file dns_naptr.c.

Referenced by dns_naptr_sort().

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 }
A NAPTR record.
Definition: dns_internal.h:92

◆ compare_preference()

static int compare_preference ( const void *  record1,
const void *  record2 
)
static

Definition at line 537 of file dns_naptr.c.

Referenced by dns_naptr_sort().

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 }
A NAPTR record.
Definition: dns_internal.h:92

◆ dns_naptr_alloc()

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.

Parameters
queryThe DNS query
dataThis specific NAPTR record
sizeThe size of the NAPTR record
Return values
non-NULLsuccess
NULLfailure

Definition at line 380 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, order, ast_dns_naptr_record::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().

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 }
int dns_parse_string(char *cur, uint8_t *size, char **val)
Parse a DNS string from a DNS record.
Definition: dns_core.c:734
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
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
#define NULL
Definition: resample.c:96
const char * regexp
The regular expression from the NAPTR record.
Definition: dns_internal.h:100
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
#define ast_log
Definition: astobj2.c:42
integer order
Definition: analys.c:66
const char * service
The service from the NAPTR record.
Definition: dns_internal.h:98
#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
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
int errno
#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
struct ast_dns_record generic
Generic DNS record information.
Definition: dns_internal.h:94
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
const char * answer
The raw DNS answer.
Definition: dns_internal.h:129
unsigned short order
The order for the NAPTR record.
Definition: dns_internal.h:104

◆ dns_naptr_sort()

void dns_naptr_sort ( struct ast_dns_result result)

Sort the NAPTR records on a result.

Parameters
resultThe DNS result

Definition at line 551 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, records, and ast_dns_result::records.

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 }
static int records
Definition: cdr_mysql.c:84
static int compare_order(const void *record1, const void *record2)
Definition: dns_naptr.c:523
For AST_LIST.
Definition: dns_internal.h:39
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
static int compare_preference(const void *record1, const void *record2)
Definition: dns_naptr.c:537
integer order
Definition: analys.c:66
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
A NAPTR record.
Definition: dns_internal.h:92
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
struct ast_dns_result::dns_records records
unsigned short order
The order for the NAPTR record.
Definition: dns_internal.h:104

◆ interpret_flags()

static enum flags_result interpret_flags ( const char *  flags,
uint8_t  flags_size 
)
static

Analyze and interpret NAPTR flags as per RFC 3404.

Note
The flags string passed into this function is NOT NULL-terminated
Parameters
flagsThe flags string from a NAPTR record The size of the flags string in bytes
Returns
flag result

Definition at line 66 of file dns_naptr.c.

References FLAGS_EMPTY, FLAGS_INVALID, FLAGS_TERMINAL, and FLAGS_UNKNOWN.

Referenced by dns_naptr_alloc().

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 }
const char * flags
The flags from the NAPTR record.
Definition: dns_internal.h:96

◆ regexp_flags_invalid()

static int regexp_flags_invalid ( const char *  flags,
const char *  end 
)
static

Determine if flags in the regexp are invalid.

A NAPTR regexp is structured like so /pattern/repl/FLAGS

This ensures that the flags on the regexp are valid. Regexp flags can either be zero or one character long. If the flags are one character long, that character must be "i" to indicate the regex evaluation is case-insensitive.

Note
The flags string passed to this function is not NULL-terminated
Parameters
flagsThe regexp flags from the NAPTR record
endA pointer to the end of the flags string
Return values
0Flags are valid
-1Flags are invalid

Definition at line 189 of file dns_naptr.c.

Referenced by regexp_invalid().

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 }
const char * flags
The flags from the NAPTR record.
Definition: dns_internal.h:96
char * end
Definition: eagi_proxy.c:73

◆ regexp_invalid()

static int regexp_invalid ( const char *  regexp,
uint8_t  regexp_size 
)
static

Determine if the regexp in a NAPTR record is invalid.

The goal of this function is to divide the regexp into its constituent parts and then let validation subroutines determine if each part is valid. If all parts are valid, then the entire regexp is valid.

Note
The regexp string passed to this function is NOT NULL-terminated
Parameters
regexpThe regexp from the NAPTR record
regexp_sizeThe size of the regexp string
Return values
0regexp is valid
non-zeroregexp is invalid

Definition at line 309 of file dns_naptr.c.

References regexp_flags_invalid(), regexp_pattern_invalid(), and regexp_repl_invalid().

Referenced by dns_naptr_alloc().

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 }
static int regexp_flags_invalid(const char *flags, const char *end)
Determine if flags in the regexp are invalid.
Definition: dns_naptr.c:189
const char * regexp
The regular expression from the NAPTR record.
Definition: dns_internal.h:100
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
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

◆ regexp_pattern_invalid()

static int regexp_pattern_invalid ( const char *  pattern,
const char *  end 
)
static

Determine if the pattern in a regexp is invalid.

A NAPTR regexp is structured like so /PATTERN/repl/flags

This ensures that the pattern on the regexp is valid. The pattern is passed to a regex compiler to determine its validity.

Note
The pattern string passed to this function is NOT NULL-terminated
Parameters
patternThe pattern from the NAPTR record
endA pointer to the end of the pattern
Return values
0Pattern is valid
non-zeroPattern is invalid

Definition at line 275 of file dns_naptr.c.

Referenced by regexp_invalid().

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 }
char * end
Definition: eagi_proxy.c:73

◆ regexp_repl_invalid()

static int regexp_repl_invalid ( const char *  repl,
const char *  end,
char  delim 
)
static

Determine if the replacement in the regexp is invalid.

A NAPTR regexp is structured like so /pattern/REPL/flags

This ensures that the replacement on the regexp is valid. The regexp replacement is free to use any character it wants, plus backreferences and an escaped regexp delimiter.

This function does not attempt to ensure that the backreferences refer to valid portions of the regexp's regex pattern.

Note
The repl string passed to this function is NOT NULL-terminated
Parameters
replThe regexp replacement string
endPointer to the end of the replacement string
delimThe delimiter character for the regexp
Return values
0Replacement is valid
-1Replacement is invalid

Definition at line 228 of file dns_naptr.c.

References ast_assert.

Referenced by regexp_invalid().

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 }
#define ast_assert(a)
Definition: utils.h:695
char * end
Definition: eagi_proxy.c:73

◆ services_invalid()

static int services_invalid ( const char *  services,
uint8_t  services_size 
)
static

Analyze NAPTR services for validity as defined by RFC 3404.

Note
The services string passed to this function is NOT NULL-terminated
Parameters
servicesThe services string parsed from a NAPTR record
services_sizeThe size of the services string
Return values
0Services are valid
-1Services are invalid

Definition at line 130 of file dns_naptr.c.

Referenced by dns_naptr_alloc().

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 }