Wed Jan 8 2020 09:50:11

Asterisk developer's documentation


enum.h File Reference

DNS and ENUM functions. More...

#include "asterisk/channel.h"

Go to the source code of this file.

Data Structures

struct  enum_context
 
struct  enum_naptr_rr
 
struct  naptr
 

Functions

int ast_enum_init (void)
 
int ast_enum_reload (void)
 
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

int ast_enum_init ( void  )

Definition at line 1006 of file enum.c.

References private_enum_init().

Referenced by main().

1007 {
1008  return private_enum_init(0);
1009 }
static int private_enum_init(int reload)
Initialize the ENUM support subsystem.
Definition: enum.c:968
int ast_enum_reload ( void  )

Definition at line 1011 of file enum.c.

References private_enum_init().

1012 {
1013  return private_enum_init(1);
1014 }
static int private_enum_init(int reload)
Initialize the ENUM support subsystem.
Definition: enum.c:968
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 632 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, 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, LOG_WARNING, enum_naptr_rr::naptr, enum_context::naptr_rrs, enum_context::naptr_rrs_count, enum_context::naptrinput, 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, and enum_context::techlen.

Referenced by enum_query_read(), and function_enum().

633 {
634  struct enum_context *context;
635  char tmp[512];
636  char domain[256];
637  char left[128];
638  char middle[128];
639  char naptrinput[128];
640  char apex[128] = "";
641  int ret = -1;
642  /* for ISN rewrite */
643  char *p1 = NULL;
644  char *p2 = NULL;
645  char *p3 = NULL;
646  int k = 0;
647  int i = 0;
648  int z = 0;
649  int spaceleft = 0;
650  struct timeval time_start, time_end;
651 
652  if (ast_strlen_zero(suffix)) {
653  ast_log(LOG_WARNING, "ast_get_enum need a suffix parameter now.\n");
654  return -1;
655  }
656 
657  ast_debug(2, "num='%s', tech='%s', suffix='%s', options='%s', record=%u\n", number, tech, suffix, options, record);
658 
659 /*
660  We don't need that any more, that "n" preceding the number has been replaced by a flag
661  in the options paramter.
662  ast_copy_string(naptrinput, number, sizeof(naptrinput));
663 */
664 /*
665  * The "number" parameter includes a leading '+' if it's a full E.164 number (and not ISN)
666  * We need to preserve that as the regex inside NAPTRs expect the +.
667  *
668  * But for the domain generation, the '+' is a nuissance, so we get rid of it.
669 */
670  ast_copy_string(naptrinput, number[0] == 'n' ? number + 1 : number, sizeof(naptrinput));
671  if (number[0] == '+') {
672  number++;
673  }
674 
675  if (!(context = ast_calloc(1, sizeof(*context)))) {
676  return -1;
677  }
678 
679  if ((p3 = strchr(naptrinput, '*'))) {
680  *p3='\0';
681  }
682 
683  context->naptrinput = naptrinput; /* The number */
684  context->dst = dst; /* Return string */
685  context->dstlen = dstlen;
686  context->tech = tech;
687  context->techlen = techlen;
688  context->options = 0;
689  context->position = record > 0 ? record : 1;
690  context->count = 0;
691  context->naptr_rrs = NULL;
692  context->naptr_rrs_count = 0;
693 
694  /*
695  * Process options:
696  *
697  * c Return count, not URI
698  * i Use infrastructure ENUM
699  * s Do ISN transformation
700  * d Direct DNS query: no reversing.
701  *
702  */
703  if (options != NULL) {
704  if (strchr(options,'s')) {
705  context->options |= ENUMLOOKUP_OPTIONS_ISN;
706  } else if (strchr(options,'i')) {
707  context->options |= ENUMLOOKUP_OPTIONS_IENUM;
708  } else if (strchr(options,'d')) {
710  }
711  if (strchr(options,'c')) {
712  context->options |= ENUMLOOKUP_OPTIONS_COUNT;
713  }
714  if (strchr(number,'*')) {
715  context->options |= ENUMLOOKUP_OPTIONS_ISN;
716  }
717  }
718  ast_debug(2, "ENUM options(%s): pos=%d, options='%d'\n", options, context->position, context->options);
719  ast_debug(1, "n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
720  number, tech, suffix, context->options, context->position);
721 
722  /*
723  * This code does more than simple RFC3261 ENUM. All these rewriting
724  * schemes have in common that they build the FQDN for the NAPTR lookup
725  * by concatenating
726  * - a number which needs be flipped and "."-seperated (left)
727  * - some fixed string (middle)
728  * - an Apex. (apex)
729  *
730  * The RFC3261 ENUM is: left=full number, middle="", apex=from args.
731  * ISN: number = "middle*left", apex=from args
732  * I-ENUM: EBL parameters build the split, can change apex
733  * Direct: left="", middle=argument, apex=from args
734  *
735  */
736 
737  /* default: the whole number will be flipped, no middle domain component */
738  ast_copy_string(left, number, sizeof(left));
739  middle[0] = '\0';
740  /*
741  * I-ENUM can change the apex, thus we copy it
742  */
743  ast_copy_string(apex, suffix, sizeof(apex));
744  /* ISN rewrite */
745  if ((context->options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
746  *p1++ = '\0';
747  ast_copy_string(left, number, sizeof(left));
748  ast_copy_string(middle, p1, sizeof(middle) - 1);
749  strcat(middle, ".");
750  ast_debug(2, "ISN ENUM: left=%s, middle='%s'\n", left, middle);
751  /* Direct DNS lookup rewrite */
752  } else if (context->options & ENUMLOOKUP_OPTIONS_DIRECT) {
753  left[0] = 0; /* nothing to flip around */
754  ast_copy_string(middle, number, sizeof(middle) - 1);
755  strcat(middle, ".");
756  ast_debug(2, "DIRECT ENUM: middle='%s'\n", middle);
757  /* Infrastructure ENUM rewrite */
758  } else if (context->options & ENUMLOOKUP_OPTIONS_IENUM) {
759  int sdl = 0;
760  char cc[8];
761  char sep[256], n_apex[256];
762  int cc_len = cclen(number);
763  sdl = cc_len;
765  ast_copy_string(sep, ienum_branchlabel, sizeof(sep)); /* default */
767 
768  switch (ebl_alg) {
769  case ENUMLOOKUP_BLR_EBL:
770  ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
771  sdl = blr_ebl(cc, suffix, sep, sizeof(sep) - 1, n_apex, sizeof(n_apex) - 1);
772 
773  if (sdl >= 0) {
774  ast_copy_string(apex, n_apex, sizeof(apex));
775  ast_debug(2, "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
776  } else {
777  sdl = cc_len;
778  }
779  break;
780  case ENUMLOOKUP_BLR_TXT:
781  ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
782  sdl = blr_txt(cc, suffix);
783 
784  if (sdl < 0) {
785  sdl = cc_len;
786  }
787  break;
788 
789  case ENUMLOOKUP_BLR_CC: /* BLR is at the country-code level */
790  default:
791  sdl = cc_len;
792  break;
793  }
794 
795  if (sdl > strlen(number)) { /* Number too short for this sdl? */
796  ast_log(LOG_WARNING, "I-ENUM: subdomain location %d behind number %s\n", sdl, number);
797  ast_free(context);
798  return 0;
799  }
800  ast_copy_string(left, number + sdl, sizeof(left));
801 
803  ast_copy_string(middle, sep, sizeof(middle) - 1);
804  strcat(middle, ".");
806 
807  /* check the space we need for middle */
808  if ((sdl * 2 + strlen(middle) + 2) > sizeof(middle)) {
809  ast_log(LOG_WARNING, "ast_get_enum: not enough space for I-ENUM rewrite.\n");
810  ast_free(context);
811  return -1;
812  }
813 
814  p1 = middle + strlen(middle);
815  for (p2 = (char *) number + sdl - 1; p2 >= number; p2--) {
816  if (isdigit(*p2)) {
817  *p1++ = *p2;
818  *p1++ = '.';
819  }
820  }
821  *p1 = '\0';
822 
823  ast_debug(2, "I-ENUM: cclen=%d, left=%s, middle='%s', apex='%s'\n", cc_len, left, middle, apex);
824  }
825 
826  if (strlen(left) * 2 + 2 > sizeof(domain)) {
827  ast_log(LOG_WARNING, "string to long in ast_get_enum\n");
828  ast_free(context);
829  return -1;
830  }
831 
832  /* flip left into domain */
833  p1 = domain;
834  for (p2 = left + strlen(left); p2 >= left; p2--) {
835  if (isdigit(*p2)) {
836  *p1++ = *p2;
837  *p1++ = '.';
838  }
839  }
840  *p1 = '\0';
841 
842  if (chan && ast_autoservice_start(chan) < 0) {
843  ast_free(context);
844  return -1;
845  }
846 
847  spaceleft = sizeof(tmp) - 2;
848  ast_copy_string(tmp, domain, spaceleft);
849  spaceleft -= strlen(domain);
850 
851  if (*middle) {
852  strncat(tmp, middle, spaceleft);
853  spaceleft -= strlen(middle);
854  }
855 
856  strncat(tmp,apex,spaceleft);
857  time_start = ast_tvnow();
858  ret = ast_search_dns(context, tmp, C_IN, T_NAPTR, enum_callback);
859  time_end = ast_tvnow();
860 
861  ast_debug(2, "profiling: %s, %s, %" PRIi64 " ms\n",
862  (ret == 0) ? "OK" : "FAIL", tmp, ast_tvdiff_ms(time_end, time_start));
863 
864  if (ret < 0) {
865  ast_debug(1, "No such number found: %s (%s)\n", tmp, strerror(errno));
866  strcpy(dst, "0");
867  ret = 0;
868  }
869 
870  if (context->naptr_rrs_count >= context->position && ! (context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
871  /* sort array by NAPTR order/preference */
872  for (k = 0; k < context->naptr_rrs_count; k++) {
873  for (i = 0; i < context->naptr_rrs_count; i++) {
874  /* use order first and then preference to compare */
875  if ((ntohs(context->naptr_rrs[k].naptr.order) < ntohs(context->naptr_rrs[i].naptr.order)
876  && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
877  || (ntohs(context->naptr_rrs[k].naptr.order) > ntohs(context->naptr_rrs[i].naptr.order)
878  && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
879  z = context->naptr_rrs[k].sort_pos;
880  context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
881  context->naptr_rrs[i].sort_pos = z;
882  continue;
883  }
884  if (ntohs(context->naptr_rrs[k].naptr.order) == ntohs(context->naptr_rrs[i].naptr.order)) {
885  if ((ntohs(context->naptr_rrs[k].naptr.pref) < ntohs(context->naptr_rrs[i].naptr.pref)
886  && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
887  || (ntohs(context->naptr_rrs[k].naptr.pref) > ntohs(context->naptr_rrs[i].naptr.pref)
888  && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
889  z = context->naptr_rrs[k].sort_pos;
890  context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
891  context->naptr_rrs[i].sort_pos = z;
892  }
893  }
894  }
895  }
896  for (k = 0; k < context->naptr_rrs_count; k++) {
897  if (context->naptr_rrs[k].sort_pos == context->position - 1) {
898  ast_copy_string(context->dst, context->naptr_rrs[k].result, dstlen);
899  ast_copy_string(context->tech, context->naptr_rrs[k].tech, techlen);
900  break;
901  }
902  }
903  } else if (!(context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
904  context->dst[0] = 0;
905  } else if ((context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
906  snprintf(context->dst, context->dstlen, "%d", context->count);
907  }
908 
909  if (chan) {
910  ret |= ast_autoservice_stop(chan);
911  }
912 
913  if (!argcontext) {
914  for (k = 0; k < context->naptr_rrs_count; k++) {
915  ast_free(context->naptr_rrs[k].result);
916  ast_free(context->naptr_rrs[k].tech);
917  }
918  ast_free(context->naptr_rrs);
919  ast_free(context);
920  } else {
921  *argcontext = context;
922  }
923 
924  return ret;
925 }
static int enum_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Callback from ENUM lookup function.
Definition: enum.c:599
#define ENUMLOOKUP_OPTIONS_COUNT
Definition: enum.c:590
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:179
int count
Definition: enum.h:49
static char ienum_branchlabel[32]
Definition: enum.c:85
struct enum_naptr_rr * naptr_rrs
Definition: enum.h:51
#define LOG_WARNING
Definition: logger.h:144
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:259
static int cclen(const char *number)
Determine the length of a country code when given an E.164 string.
Definition: enum.c:110
static ast_mutex_t enumlock
Definition: enum.c:95
static int ebl_alg
Definition: enum.c:90
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:142
#define ast_mutex_lock(a)
Definition: lock.h:155
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:90
#define ENUMLOOKUP_OPTIONS_DIRECT
Definition: enum.c:596
#define ENUMLOOKUP_BLR_CC
Definition: enum.c:87
Number structure.
Definition: app_followme.c:109
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define ENUMLOOKUP_BLR_EBL
Definition: enum.c:89
int techlen
Definition: enum.h:44
char * dst
Definition: enum.h:41
unsigned short order
Definition: enum.h:29
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
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:238
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
#define ast_free(a)
Definition: astmm.h:97
char * result
Definition: enum.h:35
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
int naptr_rrs_count
Definition: enum.h:52
#define ENUMLOOKUP_OPTIONS_IENUM
Definition: enum.c:594
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
char * tech
Definition: enum.h:43
int sort_pos
Definition: enum.h:37
#define ENUMLOOKUP_OPTIONS_ISN
Definition: enum.c:592
int options
Definition: enum.h:50
#define ENUMLOOKUP_BLR_TXT
Definition: enum.c:88
static int blr_txt(const char *cc, const char *suffix)
Determine the branch location record as stored in a TXT record.
Definition: enum.c:195
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:324
#define ast_mutex_unlock(a)
Definition: lock.h:156
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 927 of file enum.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_copy_string(), ast_debug, errno, and txt_context::txt.

Referenced by function_txtcidname().

928 {
929  struct txt_context context;
930  char tmp[259 + 512];
931  int pos = strlen(number) - 1;
932  int newpos = 0;
933  int ret = -1;
934 
935  ast_debug(4, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);
936 
937  if (chan && ast_autoservice_start(chan) < 0) {
938  return -1;
939  }
940 
941  if (pos > 128) {
942  pos = 128;
943  }
944 
945  while (pos >= 0) {
946  if (isdigit(number[pos])) {
947  tmp[newpos++] = number[pos];
948  tmp[newpos++] = '.';
949  }
950  pos--;
951  }
952 
953  ast_copy_string(&tmp[newpos], suffix, sizeof(tmp) - newpos);
954 
955  if (ret < 0) {
956  ast_debug(2, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno));
957  ret = 0;
958  } else {
960  }
961  if (chan) {
962  ret |= ast_autoservice_stop(chan);
963  }
964  return ret;
965 }
char txt[1024]
Definition: enum.c:140
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:179
int txtlen
Definition: enum.c:141
Number structure.
Definition: app_followme.c:109
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:238
int errno
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107