Thu Apr 28 2011 17:16:04

Asterisk developer's documentation


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_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.
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)

Detailed Description

DNS and ENUM functions.

Definition in file enum.h.


Function Documentation

int ast_enum_init ( void  )

Definition at line 997 of file enum.c.

References private_enum_init().

Referenced by main().

{
   return private_enum_init(0);
}
int ast_enum_reload ( void  )

Definition at line 1002 of file enum.c.

References private_enum_init().

{
   return private_enum_init(1);
}
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 628 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(), ast_verb, 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().

{
   struct enum_context *context;
   char tmp[512];
   char domain[256];
   char left[128];
   char middle[128];
   char naptrinput[128];
   char apex[128] = "";
   int ret = -1;
   /* for ISN rewrite */
   char *p1 = NULL;
   char *p2 = NULL;
   char *p3 = NULL;
   int k = 0;
   int i = 0;
   int z = 0;
   int spaceleft = 0;
   struct timeval time_start, time_end;
 
   if (ast_strlen_zero(suffix)) {
      ast_log(LOG_WARNING, "ast_get_enum need a suffix parameter now.\n");
      return -1;
   }

   ast_verb(2, "ast_get_enum(num='%s', tech='%s', suffix='%s', options='%s', record=%d\n", number, tech, suffix, options, record);

/*
  We don't need that any more, that "n" preceding the number has been replaced by a flag
  in the options paramter.
   ast_copy_string(naptrinput, number, sizeof(naptrinput));
*/
/*
 * The "number" parameter includes a leading '+' if it's a full E.164 number (and not ISN)
 * We need to preserve that as the regex inside NAPTRs expect the +.
 *
 * But for the domain generation, the '+' is a nuissance, so we get rid of it.
*/
   ast_copy_string(naptrinput, number[0] == 'n' ? number + 1 : number, sizeof(naptrinput));
   if (number[0] == '+') {
      number++;
   }

   if (!(context = ast_calloc(1, sizeof(*context))))
      return -1;

   if((p3 = strchr(naptrinput, '*'))) {
      *p3='\0';      
   }

   context->naptrinput = naptrinput;   /* The number */
   context->dst = dst;        /* Return string */
   context->dstlen = dstlen;
   context->tech = tech;
   context->techlen = techlen;
   context->options = 0;
   context->position = record > 0 ? record : 1;
   context->count = 0;
   context->naptr_rrs = NULL;
   context->naptr_rrs_count = 0;

   /*
    * Process options:
    *
    *    c  Return count, not URI
    *    i  Use infrastructure ENUM 
    *    s  Do ISN transformation
    *    d  Direct DNS query: no reversing.
    *
    */
   if (options != NULL) {
      if (strchr(options,'s')) {
         context->options |= ENUMLOOKUP_OPTIONS_ISN;
      } else if (strchr(options,'i')) {
         context->options |= ENUMLOOKUP_OPTIONS_IENUM;
      } else if (strchr(options,'d')) {
         context->options |= ENUMLOOKUP_OPTIONS_DIRECT;
      }
      if (strchr(options,'c')) {
         context->options |= ENUMLOOKUP_OPTIONS_COUNT;
      }
      if (strchr(number,'*')) {
         context->options |= ENUMLOOKUP_OPTIONS_ISN;
      }
   }
   ast_verb(2, "ENUM options(%s): pos=%d, options='%d'\n", options, context->position, context->options);
   ast_debug(1, "ast_get_enum(): n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
         number, tech, suffix, context->options, context->position);

   /*
    * This code does more than simple RFC3261 ENUM. All these rewriting 
    * schemes have in common that they build the FQDN for the NAPTR lookup
    * by concatenating
    *    - a number which needs be flipped and "."-seperated   (left)
    *    - some fixed string              (middle)
    *    - an Apex.                 (apex)
    *
    * The RFC3261 ENUM is: left=full number, middle="", apex=from args.
    * ISN:  number = "middle*left", apex=from args
    * I-ENUM: EBL parameters build the split, can change apex
    * Direct: left="", middle=argument, apex=from args
    *
    */

   /* default: the whole number will be flipped, no middle domain component */
   ast_copy_string(left, number, sizeof(left));
   middle[0] = '\0';
   /*
    * I-ENUM can change the apex, thus we copy it 
    */
   ast_copy_string(apex, suffix, sizeof(apex));
   /* ISN rewrite */
   if ((context->options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
      *p1++ = '\0';
      ast_copy_string(left, number, sizeof(left));
      ast_copy_string(middle, p1, sizeof(middle) - 1);
      strcat(middle, ".");

      ast_verb(2, "ISN ENUM: left=%s, middle='%s'\n", left, middle);
   /* Direct DNS lookup rewrite */
   } else if (context->options & ENUMLOOKUP_OPTIONS_DIRECT) {
      left[0] = 0; /* nothing to flip around */
      ast_copy_string(middle, number, sizeof(middle) - 1);
      strcat(middle, ".");
 
      ast_verb(2, "DIRECT ENUM:  middle='%s'\n", middle);
   /* Infrastructure ENUM rewrite */
   } else if (context->options & ENUMLOOKUP_OPTIONS_IENUM) {
      int sdl = 0;
      char cc[8];
      char sep[256], n_apex[256];
      int cc_len = cclen(number);
      sdl = cc_len;
      ast_mutex_lock(&enumlock);
      ast_copy_string(sep, ienum_branchlabel, sizeof(sep)); /* default */
      ast_mutex_unlock(&enumlock);

      switch (ebl_alg) {
      case ENUMLOOKUP_BLR_EBL:
         ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
         sdl = blr_ebl(cc, suffix, sep, sizeof(sep) - 1, n_apex, sizeof(n_apex) - 1);

         if (sdl >= 0) {
            ast_copy_string(apex, n_apex, sizeof(apex));
            ast_verb(2, "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
         } else {
            sdl = cc_len;
         }
         break;
      case ENUMLOOKUP_BLR_TXT:
         ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
         sdl = blr_txt(cc, suffix);

         if (sdl < 0) 
            sdl = cc_len;
         break;

      case ENUMLOOKUP_BLR_CC: /* BLR is at the country-code level */
      default:
         sdl = cc_len;
         break;
      }

      if (sdl > strlen(number)) {   /* Number too short for this sdl? */
         ast_log(LOG_WARNING, "I-ENUM: subdomain location %d behind number %s\n", sdl, number);
         return 0;
      }
      ast_copy_string(left, number + sdl, sizeof(left));

      ast_mutex_lock(&enumlock);
      ast_copy_string(middle, sep, sizeof(middle) - 1);
      strcat(middle, ".");
      ast_mutex_unlock(&enumlock);

      /* check the space we need for middle */
      if ((sdl * 2 + strlen(middle) + 2) > sizeof(middle)) {
         ast_log(LOG_WARNING, "ast_get_enum: not enough space for I-ENUM rewrite.\n");
         return -1;
      }

      p1 = middle + strlen(middle);
      for (p2 = (char *) number + sdl - 1; p2 >= number; p2--) {
         if (isdigit(*p2)) {
            *p1++ = *p2;
            *p1++ = '.';
         }
      }
      *p1 = '\0';

      ast_verb(2, "I-ENUM: cclen=%d, left=%s, middle='%s', apex='%s'\n", cc_len, left, middle, apex);
   }

   if (strlen(left) * 2 + 2 > sizeof(domain)) {
      ast_log(LOG_WARNING, "string to long in ast_get_enum\n");
      return -1;
   }

   /* flip left into domain */
   p1 = domain;
   for (p2 = left + strlen(left); p2 >= left; p2--) {
      if (isdigit(*p2)) {
         *p1++ = *p2;
         *p1++ = '.';
      }
   }
   *p1 = '\0';

   if (chan && ast_autoservice_start(chan) < 0) {
      ast_free(context);
      return -1;
   }

   spaceleft = sizeof(tmp) - 2;
   ast_copy_string(tmp, domain, spaceleft);
   spaceleft -= strlen(domain);

   if (*middle) {
      strncat(tmp, middle, spaceleft);
      spaceleft -= strlen(middle);
   }

   strncat(tmp,apex,spaceleft);
   time_start = ast_tvnow();
   ret = ast_search_dns(context, tmp, C_IN, T_NAPTR, enum_callback);
   time_end = ast_tvnow();

   ast_verb(2, "ast_get_enum() profiling: %s, %s, %d ms\n", 
         (ret == 0) ? "OK" : "FAIL", tmp, ast_tvdiff_ms(time_end, time_start));

   if (ret < 0) {
      ast_debug(1, "No such number found: %s (%s)\n", tmp, strerror(errno));
      strcpy(dst, "0");
      ret = 0;
   }

   if (context->naptr_rrs_count >= context->position && ! (context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
      /* sort array by NAPTR order/preference */
      for (k = 0; k < context->naptr_rrs_count; k++) {
         for (i = 0; i < context->naptr_rrs_count; i++) {
            /* use order first and then preference to compare */
            if ((ntohs(context->naptr_rrs[k].naptr.order) < ntohs(context->naptr_rrs[i].naptr.order)
                 && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
                 || (ntohs(context->naptr_rrs[k].naptr.order) > ntohs(context->naptr_rrs[i].naptr.order)
                 && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
               z = context->naptr_rrs[k].sort_pos;
               context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
               context->naptr_rrs[i].sort_pos = z;
               continue;
            }
            if (ntohs(context->naptr_rrs[k].naptr.order) == ntohs(context->naptr_rrs[i].naptr.order)) {
               if ((ntohs(context->naptr_rrs[k].naptr.pref) < ntohs(context->naptr_rrs[i].naptr.pref)
                    && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
                    || (ntohs(context->naptr_rrs[k].naptr.pref) > ntohs(context->naptr_rrs[i].naptr.pref)
                    && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
                  z = context->naptr_rrs[k].sort_pos;
                  context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
                  context->naptr_rrs[i].sort_pos = z;
               }
            }
         }
      }
      for (k = 0; k < context->naptr_rrs_count; k++) {
         if (context->naptr_rrs[k].sort_pos == context->position - 1) {
            ast_copy_string(context->dst, context->naptr_rrs[k].result, dstlen);
            ast_copy_string(context->tech, context->naptr_rrs[k].tech, techlen);
            break;
         }
      }
   } else if (!(context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
      context->dst[0] = 0;
   } else if ((context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
      snprintf(context->dst,context->dstlen,"%d",context->count);
   }

   if (chan)
      ret |= ast_autoservice_stop(chan);

   if (!argcontext) {
      for (k = 0; k < context->naptr_rrs_count; k++) {
         ast_free(context->naptr_rrs[k].result);
         ast_free(context->naptr_rrs[k].tech);
      }
      ast_free(context->naptr_rrs);
      ast_free(context);
   } else
      *argcontext = context;

   return ret;
}
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 918 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().

{
   struct txt_context context;
   char tmp[259 + 512];
   int pos = strlen(number) - 1;
   int newpos = 0;
   int ret = -1;

   ast_debug(4, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);

   if (chan && ast_autoservice_start(chan) < 0) {
      return -1;
   }
 
   if (pos > 128) {
      pos = 128;
   }

   while (pos >= 0) {
      if (isdigit(number[pos])) {
         tmp[newpos++] = number[pos];
         tmp[newpos++] = '.';
      }
      pos--;
   }

   ast_copy_string(&tmp[newpos], suffix, sizeof(tmp) - newpos);

   if (ret < 0) {
      ast_debug(2, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno));
      ret = 0;
   } else {
      ast_copy_string(txt, context.txt, txtlen);
   }
   if (chan) {
      ret |= ast_autoservice_stop(chan);
   }
   return ret;
}