Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Functions
enum.h File Reference

DNS and ENUM functions. More...

#include "asterisk/channel.h"
Include dependency graph for enum.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  enum_context
 
struct  enum_naptr_rr
 
struct  naptr
 

Functions

int ast_get_enum (struct ast_channel *chan, const char *number, char *location, int maxloc, char *technology, int maxtech, char *suffix, char *options, unsigned int record, struct enum_context **argcontext)
 Lookup entry in ENUM. More...
 
int ast_get_txt (struct ast_channel *chan, const char *number, char *txt, int maxtxt, char *suffix)
 Lookup DNS TXT record (used by app TXTCIDnum) More...
 

Detailed Description

DNS and ENUM functions.

Definition in file enum.h.

Function Documentation

◆ ast_get_enum()

int ast_get_enum ( struct ast_channel chan,
const char *  number,
char *  location,
int  maxloc,
char *  technology,
int  maxtech,
char *  suffix,
char *  options,
unsigned int  record,
struct enum_context **  argcontext 
)

Lookup entry in ENUM.

Parameters
chanChannel
numberE164 number with or without the leading +
locationNumber returned (or SIP uri)
maxlocMax length
technologyTechnology (from url scheme in response) You can set it to get particular answer RR, if there are many techs in DNS response, example: "sip" If you need any record, then set it to "ALL" string
maxtechMax length
suffixZone suffix (WARNING: No defaults here any more)
optionsOptions 'c' - Count number of NAPTR RR number - Position of the requested RR in the answer list 'u' - Full URI return (does not strip URI scheme) 'i' - Infrastructure ENUM lookup 's' - ISN based lookup 'd' - Direct DNS query
recordThe position of required RR in the answer list
argcontextArgument for caching results into an enum_context pointer (NULL is used for not caching)
Return values
1if found
0if not found
-1on hangup

Definition at line 649 of file enum.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_copy_string(), ast_debug, ast_free, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_search_dns(), ast_strlen_zero, ast_tvdiff_ms(), ast_tvnow(), blr_ebl(), blr_txt(), cclen(), context, enum_context::count, enum_context::dst, enum_context::dstlen, ebl_alg, enum_callback(), enumlock, ENUMLOOKUP_BLR_CC, ENUMLOOKUP_BLR_EBL, ENUMLOOKUP_BLR_TXT, ENUMLOOKUP_OPTIONS_COUNT, ENUMLOOKUP_OPTIONS_DIRECT, ENUMLOOKUP_OPTIONS_IENUM, ENUMLOOKUP_OPTIONS_ISN, errno, ienum_branchlabel, LOG_WARNING, enum_naptr_rr::naptr, enum_context::naptr_rrs, enum_context::naptr_rrs_count, enum_context::naptrinput, NULL, enum_context::options, naptr::order, enum_context::position, naptr::pref, enum_naptr_rr::result, enum_naptr_rr::sort_pos, enum_naptr_rr::tech, enum_context::tech, enum_context::techlen, and tmp().

Referenced by enum_query_read(), and function_enum().

650 {
651  struct enum_context *context;
652  char tmp[512];
653  char domain[256];
654  char left[128];
655  char middle[128];
656  char naptrinput[128];
657  char apex[128] = "";
658  int ret = -1;
659  /* for ISN rewrite */
660  char *p1 = NULL;
661  char *p2 = NULL;
662  char *p3 = NULL;
663  int k = 0;
664  int i = 0;
665  int z = 0;
666  int spaceleft = 0;
667  struct timeval time_start, time_end;
668 
669  if (ast_strlen_zero(suffix)) {
670  ast_log(LOG_WARNING, "ast_get_enum need a suffix parameter now.\n");
671  return -1;
672  }
673 
674  ast_debug(2, "num='%s', tech='%s', suffix='%s', options='%s', record=%u\n", number, tech, suffix, options, record);
675 
676 /*
677  We don't need that any more, that "n" preceding the number has been replaced by a flag
678  in the options paramter.
679  ast_copy_string(naptrinput, number, sizeof(naptrinput));
680 */
681 /*
682  * The "number" parameter includes a leading '+' if it's a full E.164 number (and not ISN)
683  * We need to preserve that as the regex inside NAPTRs expect the +.
684  *
685  * But for the domain generation, the '+' is a nuissance, so we get rid of it.
686 */
687  ast_copy_string(naptrinput, number[0] == 'n' ? number + 1 : number, sizeof(naptrinput));
688  if (number[0] == '+') {
689  number++;
690  }
691 
692  if (!(context = ast_calloc(1, sizeof(*context)))) {
693  return -1;
694  }
695 
696  if ((p3 = strchr(naptrinput, '*'))) {
697  *p3='\0';
698  }
699 
700  context->naptrinput = naptrinput; /* The number */
701  context->dst = dst; /* Return string */
702  context->dstlen = dstlen;
703  context->tech = tech;
704  context->techlen = techlen;
705  context->options = 0;
706  context->position = record > 0 ? record : 1;
707  context->count = 0;
708  context->naptr_rrs = NULL;
709  context->naptr_rrs_count = 0;
710 
711  /*
712  * Process options:
713  *
714  * c Return count, not URI
715  * i Use infrastructure ENUM
716  * s Do ISN transformation
717  * d Direct DNS query: no reversing.
718  *
719  */
720  if (options != NULL) {
721  if (strchr(options,'s')) {
722  context->options |= ENUMLOOKUP_OPTIONS_ISN;
723  } else if (strchr(options,'i')) {
724  context->options |= ENUMLOOKUP_OPTIONS_IENUM;
725  } else if (strchr(options,'d')) {
727  }
728  if (strchr(options,'c')) {
729  context->options |= ENUMLOOKUP_OPTIONS_COUNT;
730  }
731  if (strchr(number,'*')) {
732  context->options |= ENUMLOOKUP_OPTIONS_ISN;
733  }
734  }
735  ast_debug(2, "ENUM options(%s): pos=%d, options='%d'\n", options, context->position, context->options);
736  ast_debug(1, "n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
737  number, tech, suffix, context->options, context->position);
738 
739  /*
740  * This code does more than simple RFC3261 ENUM. All these rewriting
741  * schemes have in common that they build the FQDN for the NAPTR lookup
742  * by concatenating
743  * - a number which needs be flipped and "."-seperated (left)
744  * - some fixed string (middle)
745  * - an Apex. (apex)
746  *
747  * The RFC3261 ENUM is: left=full number, middle="", apex=from args.
748  * ISN: number = "middle*left", apex=from args
749  * I-ENUM: EBL parameters build the split, can change apex
750  * Direct: left="", middle=argument, apex=from args
751  *
752  */
753 
754  /* default: the whole number will be flipped, no middle domain component */
755  ast_copy_string(left, number, sizeof(left));
756  middle[0] = '\0';
757  /*
758  * I-ENUM can change the apex, thus we copy it
759  */
760  ast_copy_string(apex, suffix, sizeof(apex));
761  /* ISN rewrite */
762  if ((context->options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
763  *p1++ = '\0';
764  ast_copy_string(left, number, sizeof(left));
765  ast_copy_string(middle, p1, sizeof(middle) - 1);
766  strcat(middle, ".");
767  ast_debug(2, "ISN ENUM: left=%s, middle='%s'\n", left, middle);
768  /* Direct DNS lookup rewrite */
769  } else if (context->options & ENUMLOOKUP_OPTIONS_DIRECT) {
770  left[0] = 0; /* nothing to flip around */
771  ast_copy_string(middle, number, sizeof(middle) - 1);
772  strcat(middle, ".");
773  ast_debug(2, "DIRECT ENUM: middle='%s'\n", middle);
774  /* Infrastructure ENUM rewrite */
775  } else if (context->options & ENUMLOOKUP_OPTIONS_IENUM) {
776  int sdl = 0;
777  char cc[8];
778  char sep[256], n_apex[256];
779  int cc_len = cclen(number);
780  sdl = cc_len;
782  ast_copy_string(sep, ienum_branchlabel, sizeof(sep)); /* default */
784 
785  switch (ebl_alg) {
786  case ENUMLOOKUP_BLR_EBL:
787  ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
788  sdl = blr_ebl(cc, suffix, sep, sizeof(sep) - 1, n_apex, sizeof(n_apex) - 1);
789 
790  if (sdl >= 0) {
791  ast_copy_string(apex, n_apex, sizeof(apex));
792  ast_debug(2, "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
793  } else {
794  sdl = cc_len;
795  }
796  break;
797  case ENUMLOOKUP_BLR_TXT:
798  ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
799  sdl = blr_txt(cc, suffix);
800 
801  if (sdl < 0) {
802  sdl = cc_len;
803  }
804  break;
805 
806  case ENUMLOOKUP_BLR_CC: /* BLR is at the country-code level */
807  default:
808  sdl = cc_len;
809  break;
810  }
811 
812  if (sdl > strlen(number)) { /* Number too short for this sdl? */
813  ast_log(LOG_WARNING, "I-ENUM: subdomain location %d behind number %s\n", sdl, number);
814  ast_free(context);
815  return 0;
816  }
817  ast_copy_string(left, number + sdl, sizeof(left));
818 
820  ast_copy_string(middle, sep, sizeof(middle) - 1);
821  strcat(middle, ".");
823 
824  /* check the space we need for middle */
825  if ((sdl * 2 + strlen(middle) + 2) > sizeof(middle)) {
826  ast_log(LOG_WARNING, "ast_get_enum: not enough space for I-ENUM rewrite.\n");
827  ast_free(context);
828  return -1;
829  }
830 
831  p1 = middle + strlen(middle);
832  for (p2 = (char *) number + sdl - 1; p2 >= number; p2--) {
833  if (isdigit(*p2)) {
834  *p1++ = *p2;
835  *p1++ = '.';
836  }
837  }
838  *p1 = '\0';
839 
840  ast_debug(2, "I-ENUM: cclen=%d, left=%s, middle='%s', apex='%s'\n", cc_len, left, middle, apex);
841  }
842 
843  if (strlen(left) * 2 + 2 > sizeof(domain)) {
844  ast_log(LOG_WARNING, "string to long in ast_get_enum\n");
845  ast_free(context);
846  return -1;
847  }
848 
849  /* flip left into domain */
850  p1 = domain;
851  for (p2 = left + strlen(left); p2 >= left; p2--) {
852  if (isdigit(*p2)) {
853  *p1++ = *p2;
854  *p1++ = '.';
855  }
856  }
857  *p1 = '\0';
858 
859  if (chan && ast_autoservice_start(chan) < 0) {
860  ast_free(context);
861  return -1;
862  }
863 
864  spaceleft = sizeof(tmp) - 2;
865  ast_copy_string(tmp, domain, spaceleft);
866  spaceleft -= strlen(domain);
867 
868  if (*middle) {
869  strncat(tmp, middle, spaceleft);
870  spaceleft -= strlen(middle);
871  }
872 
873  strncat(tmp,apex,spaceleft);
874  time_start = ast_tvnow();
875  ret = ast_search_dns(context, tmp, C_IN, T_NAPTR, enum_callback);
876  time_end = ast_tvnow();
877 
878  ast_debug(2, "profiling: %s, %s, %" PRIi64 " ms\n",
879  (ret == 0) ? "OK" : "FAIL", tmp, ast_tvdiff_ms(time_end, time_start));
880 
881  if (ret < 0) {
882  ast_debug(1, "No such number found: %s (%s)\n", tmp, strerror(errno));
883  context->naptr_rrs_count = -1;
884  strcpy(dst, "0");
885  ret = 0;
886  }
887 
888  if (context->naptr_rrs_count >= context->position && ! (context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
889  /* sort array by NAPTR order/preference */
890  for (k = 0; k < context->naptr_rrs_count; k++) {
891  for (i = 0; i < context->naptr_rrs_count; i++) {
892  /* use order first and then preference to compare */
893  if ((ntohs(context->naptr_rrs[k].naptr.order) < ntohs(context->naptr_rrs[i].naptr.order)
894  && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
895  || (ntohs(context->naptr_rrs[k].naptr.order) > ntohs(context->naptr_rrs[i].naptr.order)
896  && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
897  z = context->naptr_rrs[k].sort_pos;
898  context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
899  context->naptr_rrs[i].sort_pos = z;
900  continue;
901  }
902  if (ntohs(context->naptr_rrs[k].naptr.order) == ntohs(context->naptr_rrs[i].naptr.order)) {
903  if ((ntohs(context->naptr_rrs[k].naptr.pref) < ntohs(context->naptr_rrs[i].naptr.pref)
904  && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
905  || (ntohs(context->naptr_rrs[k].naptr.pref) > ntohs(context->naptr_rrs[i].naptr.pref)
906  && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
907  z = context->naptr_rrs[k].sort_pos;
908  context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
909  context->naptr_rrs[i].sort_pos = z;
910  }
911  }
912  }
913  }
914  for (k = 0; k < context->naptr_rrs_count; k++) {
915  if (context->naptr_rrs[k].sort_pos == context->position - 1) {
916  ast_copy_string(context->dst, context->naptr_rrs[k].result, dstlen);
917  ast_copy_string(context->tech, context->naptr_rrs[k].tech, techlen);
918  break;
919  }
920  }
921  } else if (!(context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
922  context->dst[0] = 0;
923  } else if ((context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
924  snprintf(context->dst, context->dstlen, "%d", context->naptr_rrs_count + context->count);
925  }
926 
927  if (chan) {
928  ret |= ast_autoservice_stop(chan);
929  }
930 
931  if (!argcontext) {
932  for (k = 0; k < context->naptr_rrs_count; k++) {
933  ast_free(context->naptr_rrs[k].result);
934  ast_free(context->naptr_rrs[k].tech);
935  }
936  ast_free(context->naptr_rrs);
937  ast_free(context);
938  } else {
939  *argcontext = context;
940  }
941 
942  return ret;
943 }
static int enum_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Callback from ENUM lookup function.
Definition: enum.c:616
#define ENUMLOOKUP_OPTIONS_COUNT
Definition: enum.c:607
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
int count
Definition: enum.h:49
static char ienum_branchlabel[32]
Definition: enum.c:91
struct enum_naptr_rr * naptr_rrs
Definition: enum.h:51
#define LOG_WARNING
Definition: logger.h:274
int ast_search_dns(void *context, const char *dname, int class, int type, int(*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
Perform DNS lookup (used by DNS, enum and SRV lookups)
Definition: dns.c:493
static int cclen(const char *number)
Determine the length of a country code when given an E.164 string.
Definition: enum.c:116
static ast_mutex_t enumlock
Definition: enum.c:101
static int ebl_alg
Definition: enum.c:96
static int tmp()
Definition: bt_open.c:389
unsigned short pref
Definition: enum.h:30
int dstlen
Definition: enum.h:42
int position
Definition: enum.h:48
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define ast_mutex_lock(a)
Definition: lock.h:187
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
#define NULL
Definition: resample.c:96
Domain data structure.
Definition: sip.h:888
#define ENUMLOOKUP_OPTIONS_DIRECT
Definition: enum.c:613
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ENUMLOOKUP_BLR_CC
Definition: enum.c:93
Number structure.
Definition: app_followme.c:154
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define ENUMLOOKUP_BLR_EBL
Definition: enum.c:95
int techlen
Definition: enum.h:44
char * dst
Definition: enum.h:41
unsigned short order
Definition: enum.h:29
struct naptr naptr
Definition: enum.h:34
char * naptrinput
Definition: enum.h:47
char * tech
Definition: enum.h:36
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int errno
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
char * result
Definition: enum.h:35
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
int naptr_rrs_count
Definition: enum.h:52
#define ENUMLOOKUP_OPTIONS_IENUM
Definition: enum.c:611
static struct test_options options
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
char * tech
Definition: enum.h:43
int sort_pos
Definition: enum.h:37
#define ENUMLOOKUP_OPTIONS_ISN
Definition: enum.c:609
int options
Definition: enum.h:50
#define ENUMLOOKUP_BLR_TXT
Definition: enum.c:94
static int blr_txt(const char *cc, const char *suffix)
Determine the branch location record as stored in a TXT record.
Definition: enum.c:201
static int blr_ebl(const char *cc, const char *suffix, char *separator, int sep_len, char *apex, int apex_len)
Evaluate the I-ENUM branch as stored in an EBL record.
Definition: enum.c:330
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ ast_get_txt()

int ast_get_txt ( struct ast_channel chan,
const char *  number,
char *  txt,
int  maxtxt,
char *  suffix 
)

Lookup DNS TXT record (used by app TXTCIDnum)

Really has nothing to do with enum, but anyway... Actually, there is now an internet-draft which describes how callerID should be stored in ENUM domains: draft-ietf-enum-cnam-04.txt The algorithm implemented here will thus be obsolete soon.

Parameters
chanChannel
numberE164 number with or without the leading +
txtText string (return value)
maxtxtMax length of "txt"
suffixZone suffix
Version
1.6.1 new suffix parameter to take into account caller ids that aren't in e164.arpa
1.6.1 removed parameters location, maxloc, technology, maxtech as all the information is stored the txt string

Definition at line 995 of file enum.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_copy_string(), ast_debug, ast_free, ast_search_dns(), errno, format_numeric_domain(), txt_context::txt, and txt_callback().

Referenced by function_txtcidname().

996 {
997  struct txt_context context;
998  char *domain;
999  int ret;
1000  int autoservice = 0;
1001 
1002  ast_debug(4, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);
1003 
1004  domain = format_numeric_domain(number, suffix);
1005  if (!domain) {
1006  return -1;
1007  }
1008 
1009  if (chan) {
1010  /* DNS might take a while, so service the channel while we're blocked */
1011  autoservice = !ast_autoservice_start(chan);
1012  }
1013 
1014  ret = ast_search_dns(&context, domain, C_IN, T_TXT, txt_callback);
1015  if (ret > 0) {
1017  } else {
1018  ast_debug(2, "No such number found in ENUM: %s (%s)\n", domain, strerror(errno));
1019  }
1020 
1021  if (autoservice) {
1022  ast_autoservice_stop(chan);
1023  }
1024 
1025  ast_free(domain);
1026  return 0;
1027 }
char txt[1024]
Definition: enum.c:146
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
int ast_search_dns(void *context, const char *dname, int class, int type, int(*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
Perform DNS lookup (used by DNS, enum and SRV lookups)
Definition: dns.c:493
Domain data structure.
Definition: sip.h:888
int txtlen
Definition: enum.c:147
Number structure.
Definition: app_followme.c:154
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static char * format_numeric_domain(const char *number, const char *suffix)
Definition: enum.c:955
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int errno
static int txt_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Callback for TXT record lookup, /ol version.
Definition: enum.c:151
#define ast_free(a)
Definition: astmm.h:182
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116