Thu Apr 28 2011 16:57:09

Asterisk developer's documentation


enum.c File Reference

ENUM Support for Asterisk. More...

#include "asterisk.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <ctype.h>
#include <regex.h>
#include "asterisk/enum.h"
#include "asterisk/dns.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
#include "asterisk/manager.h"
Include dependency graph for enum.c:

Go to the source code of this file.

Data Structures

struct  ebl_context
struct  txt_context

Defines

#define ENUMLOOKUP_BLR_CC   0
#define ENUMLOOKUP_BLR_EBL   2
#define ENUMLOOKUP_BLR_TXT   1
#define ENUMLOOKUP_OPTIONS_COUNT   1
#define ENUMLOOKUP_OPTIONS_DIRECT   8
#define ENUMLOOKUP_OPTIONS_IENUM   4
#define ENUMLOOKUP_OPTIONS_ISN   2
#define T_EBL   65300

Functions

int ast_enum_init (void)
int ast_enum_reload (void)
int ast_get_enum (struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, 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 txtlen, char *suffix)
 Lookup DNS TXT record (used by app TXTCIDnum)
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.
static int blr_txt (const char *cc, const char *suffix)
 Determine the branch location record as stored in a TXT record.
static int cclen (const char *number)
 Determine the length of a country code when given an E.164 string.
static int ebl_callback (void *context, unsigned char *answer, int len, unsigned char *fullanswer)
 Callback for EBL record lookup.
static int enum_callback (void *context, unsigned char *answer, int len, unsigned char *fullanswer)
 Callback from ENUM lookup function.
static unsigned int parse_ie (char *data, unsigned int maxdatalen, unsigned char *src, unsigned int srclen)
 Parse NAPTR record information elements.
static int parse_naptr (unsigned char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, unsigned char *naptrinput)
 Parse DNS NAPTR record used in ENUM ---.
static int private_enum_init (int reload)
 Initialize the ENUM support subsystem.
static int txt_callback (void *context, unsigned char *answer, int len, unsigned char *fullanswer)
 Callback for TXT record lookup, /ol version.

Variables

static int ebl_alg = ENUMLOOKUP_BLR_CC
static ast_mutex_t enumlock = AST_MUTEX_INIT_VALUE
static char ienum_branchlabel [32] = "i"

Detailed Description

ENUM Support for Asterisk.

Author:
Mark Spencer <markster@digium.com>
  • Funding provided by nic.at
Enum standards
Possible improvement
Todo:

Implement a caching mechanism for multile enum lookups

The service type selection needs to be redone.

Definition in file enum.c.


Define Documentation

#define ENUMLOOKUP_BLR_CC   0

Definition at line 83 of file enum.c.

Referenced by ast_get_enum(), and private_enum_init().

#define ENUMLOOKUP_BLR_EBL   2

Definition at line 85 of file enum.c.

Referenced by ast_get_enum(), and private_enum_init().

#define ENUMLOOKUP_BLR_TXT   1

Definition at line 84 of file enum.c.

Referenced by ast_get_enum(), and private_enum_init().

#define ENUMLOOKUP_OPTIONS_COUNT   1

Definition at line 586 of file enum.c.

Referenced by ast_get_enum(), and enum_callback().

#define ENUMLOOKUP_OPTIONS_DIRECT   8

Definition at line 592 of file enum.c.

Referenced by ast_get_enum().

#define ENUMLOOKUP_OPTIONS_IENUM   4

Definition at line 590 of file enum.c.

Referenced by ast_get_enum().

#define ENUMLOOKUP_OPTIONS_ISN   2

Definition at line 588 of file enum.c.

Referenced by ast_get_enum().

#define T_EBL   65300

Definition at line 89 of file enum.c.

Referenced by blr_ebl().


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;
}
static int blr_ebl ( const char *  cc,
const char *  suffix,
char *  separator,
int  sep_len,
char *  apex,
int  apex_len 
) [static]

Evaluate the I-ENUM branch as stored in an EBL record.

Definition at line 320 of file enum.c.

References ebl_context::apex, ast_copy_string(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_search_dns(), ast_verb, ebl_callback(), enumlock, LOG_WARNING, ebl_context::pos, ebl_context::separator, and T_EBL.

Referenced by ast_get_enum().

{
   struct ebl_context context;
   char domain[128] = "";
   char *p1,*p2;
   int ret;

   ast_mutex_lock(&enumlock);

   ast_verb(4, "blr_ebl()  cc='%s', suffix='%s', c_bl='%s'\n", cc, suffix, ienum_branchlabel);

   if (sizeof(domain) < (strlen(cc) * 2 + strlen(ienum_branchlabel) + strlen(suffix) + 2)) {
      ast_mutex_unlock(&enumlock);
      ast_log(LOG_WARNING, "ERROR: string sizing in blr_EBL.\n");
      return -1;
   }

   p1 = domain + snprintf(domain, sizeof(domain), "%s.", ienum_branchlabel);
   ast_mutex_unlock(&enumlock);

   for (p2 = (char *) cc + strlen(cc) - 1; p2 >= cc; p2--) {
      if (isdigit(*p2)) {
         *p1++ = *p2;
         *p1++ = '.';
      }
   }
   strcat(p1, suffix);

   ast_verb(4, "blr_ebl() FQDN for EBL record: %s, cc was %s\n", domain, cc);

   ret = ast_search_dns(&context, domain, C_IN, T_EBL, ebl_callback);
   if (ret > 0) {
      ret = context.pos;

      if ((ret >= 0) && (ret < 20)) {
         ast_verb(3, "blr_txt() BLR EBL record for %s is %d/%s/%s)\n", cc, ret, context.separator, context.apex);
         ast_copy_string(separator, context.separator, sep_len);
         ast_copy_string(apex, context.apex, apex_len);
         return ret;
      }
   }
   ast_verb(3, "blr_txt() BLR EBL record for %s not found (apex: %s)\n", cc, suffix);
   return -1;
}
static int blr_txt ( const char *  cc,
const char *  suffix 
) [static]

Determine the branch location record as stored in a TXT record.

Definition at line 191 of file enum.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_search_dns(), ast_verb, enumlock, LOG_WARNING, txt_context::txt, and txt_callback().

Referenced by ast_get_enum().

{
   struct txt_context context;
   char domain[128] = "";
   char *p1, *p2;
   int ret;

   ast_mutex_lock(&enumlock);

   ast_verb(4, "blr_txt()  cc='%s', suffix='%s', c_bl='%s'\n", cc, suffix, ienum_branchlabel);

   if (sizeof(domain) < (strlen(cc) * 2 + strlen(ienum_branchlabel) + strlen(suffix) + 2)) {
      ast_mutex_unlock(&enumlock);
      ast_log(LOG_WARNING, "ERROR: string sizing in blr_txt.\n");
      return -1;
   }

   p1 = domain + snprintf(domain, sizeof(domain), "%s.", ienum_branchlabel);
   ast_mutex_unlock(&enumlock);

   for (p2 = (char *) cc + strlen(cc) - 1; p2 >= cc; p2--) {
      if (isdigit(*p2)) {
         *p1++ = *p2;
         *p1++ = '.';
      }
   }
   strcat(p1, suffix);

   ast_verb(4, "blr_txt() FQDN for TXT record: %s, cc was %s\n", domain, cc);

   ret = ast_search_dns(&context, domain, C_IN, T_TXT, txt_callback);

   if (ret > 0) {
      ret = atoi(context.txt);

      if ((ret >= 0) && (ret < 20)) {
         ast_verb(3, "blr_txt() BLR TXT record for %s is %d (apex: %s)\n", cc, ret, suffix);
         return ret;
      }
   }
   
   ast_verb(3, "blr_txt() BLR TXT record for %s not found (apex: %s)\n", cc, suffix);

   return -1;
}
static int cclen ( const char *  number) [static]

Determine the length of a country code when given an E.164 string.

Definition at line 106 of file enum.c.

Referenced by ast_get_enum().

{
   int cc;
   char digits[3] = "";

   if (!number || (strlen(number) < 3)) {
      return 0;
   }

   strncpy(digits, number, 2);
   
   if (!sscanf(digits, "%30d", &cc)) {
      return 0;
   }

   if (cc / 10 == 1 || cc / 10 == 7)
         return 1;

   if (cc == 20 || cc == 27 || (cc >= 30 && cc <= 34) || cc == 36 ||
       cc == 39 || cc == 40 || cc == 41 || (cc >= 40 && cc <= 41) ||
       (cc >= 43 && cc <= 49) || (cc >= 51 && cc <= 58) ||
       (cc >= 60 && cc <= 66) || cc == 81 || cc == 82 || cc == 84 ||
       cc == 86 || (cc >= 90 && cc <= 95) || cc == 98) {
      return 2;
   }

   return 3;
}
static int ebl_callback ( void *  context,
unsigned char *  answer,
int  len,
unsigned char *  fullanswer 
) [static]

Callback for EBL record lookup.

Definition at line 246 of file enum.c.

References ebl_context::apex, ebl_context::apex_len, ast_copy_string(), ast_log(), context, LOG_WARNING, ebl_context::pos, ebl_context::sep_len, and ebl_context::separator.

Referenced by blr_ebl().

{
   struct ebl_context *c = context;
   unsigned int i;

   c->pos = 0; /* default to empty */
   c->separator[0] = 0;
   c->sep_len = 0;
   c->apex[0] = 0;   
   c->apex_len = 0;

   if (answer == NULL) {
      return 0;
   }

   /* draft-lendl-enum-branch-location-record-00
    *
    *      0  1  2  3  4  5  6  7
    *    +--+--+--+--+--+--+--+--+
    *    |       POSITION        |
    *    +--+--+--+--+--+--+--+--+
    *    /       SEPARATOR       /
    *    +--+--+--+--+--+--+--+--+
    *    /         APEX          /
    *    +--+--+--+--+--+--+--+--+
    *
    *  where POSITION is a single byte, SEPARATOR is a <character-string>
    *  and APEX is a <domain-name>. 
    * 
    */

   c->pos = *answer++;
   len -= 1;

   if ((c->pos > 15) || len < 2) {  /* illegal packet */
      ast_log(LOG_WARNING, "ebl_callback: malformed EBL record.\n");
      return 0;
   }

   i = *answer++;
   len -= 1;
   if (i > len) { /* illegal packet */
      ast_log(LOG_WARNING, "ebl_callback: malformed EBL record.\n");
      return 0;
   }

   ast_copy_string(c->separator, (char *)answer, i + 1);
   c->sep_len = i;

   answer += i;
   len -= i;

   if ((i = dn_expand((unsigned char *)fullanswer, (unsigned char *)answer + len, 
            (unsigned char *)answer, c->apex, sizeof(c->apex) - 1)) < 0) {
      ast_log(LOG_WARNING, "Failed to expand hostname\n");
      return 0;
   }
   c->apex[i] = 0;
   c->apex_len = i;

   return 1;
}
static int enum_callback ( void *  context,
unsigned char *  answer,
int  len,
unsigned char *  fullanswer 
) [static]

Callback from ENUM lookup function.

Definition at line 595 of file enum.c.

References ast_log(), ast_realloc, ast_strdup, ast_strlen_zero(), context, enum_context::count, enum_context::dst, enum_context::dstlen, ENUMLOOKUP_OPTIONS_COUNT, LOG_WARNING, enum_naptr_rr::naptr, enum_context::naptr_rrs, enum_context::naptr_rrs_count, enum_context::naptrinput, enum_context::options, parse_naptr(), enum_naptr_rr::result, enum_naptr_rr::sort_pos, enum_naptr_rr::tech, enum_context::tech, and enum_context::techlen.

Referenced by ast_get_enum().

{
   struct enum_context *c = context;
   void *p = NULL;
   int res;

   res = parse_naptr((unsigned char *)c->dst, c->dstlen, c->tech, c->techlen, answer, len, (unsigned char *)c->naptrinput);

   if (res < 0) {
      ast_log(LOG_WARNING, "Failed to parse naptr\n");
      return -1;
   } else if ((res == 0) && !ast_strlen_zero(c->dst)) { /* ok, we got needed NAPTR */
      if (c->options & ENUMLOOKUP_OPTIONS_COUNT) { /* counting RRs */
         c->count++;
         snprintf(c->dst, c->dstlen, "%d", c->count);
      } else  {
         if ((p = ast_realloc(c->naptr_rrs, sizeof(*c->naptr_rrs) * (c->naptr_rrs_count + 1)))) {
            c->naptr_rrs = p;
            memcpy(&c->naptr_rrs[c->naptr_rrs_count].naptr, answer, sizeof(c->naptr_rrs->naptr));
            c->naptr_rrs[c->naptr_rrs_count].result = ast_strdup(c->dst);
            c->naptr_rrs[c->naptr_rrs_count].tech = ast_strdup(c->tech);
            c->naptr_rrs[c->naptr_rrs_count].sort_pos = c->naptr_rrs_count;
            c->naptr_rrs_count++;
         }
         c->dst[0] = 0;
      }
      return 0;
   }

   return 0;
}
static unsigned int parse_ie ( char *  data,
unsigned int  maxdatalen,
unsigned char *  src,
unsigned int  srclen 
) [static]

Parse NAPTR record information elements.

Definition at line 366 of file enum.c.

References ast_log(), len(), and LOG_WARNING.

Referenced by parse_naptr().

{
   unsigned int len, olen;

   len = olen = (unsigned int) src[0];
   src++;
   srclen--;

   if (len > srclen) {
      ast_log(LOG_WARNING, "ENUM parsing failed: Wanted %d characters, got %d\n", len, srclen);
      return -1;
   }

   if (len > maxdatalen)
      len = maxdatalen;
   memcpy(data, src, len);

   return olen + 1;
}
static int parse_naptr ( unsigned char *  dst,
int  dstsize,
char *  tech,
int  techsize,
unsigned char *  answer,
int  len,
unsigned char *  naptrinput 
) [static]

Parse DNS NAPTR record used in ENUM ---.

Definition at line 387 of file enum.c.

References ARRAY_LEN, ast_copy_string(), ast_debug, ast_log(), LOG_WARNING, and parse_ie().

Referenced by enum_callback().

{
   char tech_return[80];
   char *oanswer = (char *)answer;
   char flags[512] = "";
   char services[512] = "";
   char *p;
   char regexp[512] = "";
   char repl[512] = "";
   char tempdst[512] = "";
   char errbuff[512] = "";
   char delim;
   char *delim2;
   char *pattern, *subst, *d;
   int res;
   int regexp_len, rc;
   static const int max_bt = 10; /* max num of regexp backreference allowed, must remain 10 to guarantee a valid backreference index */
   int size, matchindex; /* size is the size of the backreference sub. */
   size_t d_len = sizeof(tempdst) - 1;
   regex_t preg;
   regmatch_t pmatch[max_bt];

   tech_return[0] = '\0';
   dst[0] = '\0';

   if (len < sizeof(struct naptr)) {
      ast_log(LOG_WARNING, "NAPTR record length too short\n");
      return -1;
   }
   answer += sizeof(struct naptr);
   len -= sizeof(struct naptr);
   if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) {
      ast_log(LOG_WARNING, "Failed to get flags from NAPTR record\n");
      return -1;
   } else {
      answer += res;
      len -= res;
   }

   if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) {
      ast_log(LOG_WARNING, "Failed to get services from NAPTR record\n");
      return -1;
   } else {
      answer += res;
      len -= res;
   }
   if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0) {
      ast_log(LOG_WARNING, "Failed to get regexp from NAPTR record\n");
      return -1;
   } else {
      answer += res;
      len -= res;
   }

   if ((res = dn_expand((unsigned char *)oanswer, (unsigned char *)answer + len, (unsigned char *)answer, repl, sizeof(repl) - 1)) < 0) {
      ast_log(LOG_WARNING, "Failed to expand hostname\n");
      return -1;
   }

   ast_debug(3, "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
      naptrinput, flags, services, regexp, repl);


   if (tolower(flags[0]) != 'u') {
      ast_log(LOG_WARNING, "NAPTR Flag must be 'U' or 'u'.\n");
      return -1;
   }

   p = strstr(services, "e2u+");
   if (p == NULL)
      p = strstr(services, "E2U+");
   if (p){
      p = p + 4;
      if (strchr(p, ':')){
         p = strchr(p, ':') + 1;
      }
      ast_copy_string(tech_return, p, sizeof(tech_return));
   } else {

      p = strstr(services, "+e2u");
      if (p == NULL)
         p = strstr(services, "+E2U");
      if (p) {
         *p = 0;
         p = strchr(services, ':');
         if (p)
            *p = 0;
         ast_copy_string(tech_return, services, sizeof(tech_return));
      }
   }

   regexp_len = strlen(regexp);
   if (regexp_len < 7) {
      ast_log(LOG_WARNING, "Regex too short to be meaningful.\n");
      return -1;
   }

   /* this takes the first character of the regexp (which is a delimiter) 
    * and uses that character to find the index of the second delimiter */
   delim = regexp[0];
   delim2 = strchr(regexp + 1, delim);
   if ((delim2 == NULL) || (regexp[regexp_len - 1] != delim)) {  /* is the second delimiter found, and is the end of the regexp a delimiter */
      ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n", regexp);
      return -1;
   } else if (strchr((delim2 + 1), delim) == NULL) { /* if the second delimiter is found, make sure there is a third instance.  this could be the end one instead of the middle */
      ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n", regexp);
      return -1;
   }
   pattern = regexp + 1;   /* pattern is the regex without the begining and ending delimiter */
   *delim2 = 0;    /* zero out the middle delimiter */
   subst   = delim2 + 1; /* dst substring is everything after the second delimiter. */
   regexp[regexp_len - 1] = 0; /* zero out the last delimiter */

/*
 * now do the regex wizardry.
 */

   if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) {
      ast_log(LOG_WARNING, "NAPTR Regex compilation error (regex = \"%s\").\n", regexp);
      return -1;
   }

   if (preg.re_nsub > ARRAY_LEN(pmatch)) {
      ast_log(LOG_WARNING, "NAPTR Regex compilation error: too many subs.\n");
      regfree(&preg);
      return -1;
   }
   /* pmatch is an array containing the substring indexes for the regex backreference sub.
    * max_bt is the maximum number of backreferences allowed to be stored in pmatch */
   if ((rc = regexec(&preg, (char *) naptrinput, max_bt, pmatch, 0))) {
      regerror(rc, &preg, errbuff, sizeof(errbuff));
      ast_log(LOG_WARNING, "NAPTR Regex match failed. Reason: %s\n", errbuff);
      regfree(&preg);
      return -1;
   }
   regfree(&preg);

   d = tempdst;
   d_len--;

   /* perform the backreference sub. Search the subst for backreferences,
    * when a backreference is found, retrieve the backreferences number.
    * use the backreference number as an index for pmatch to retrieve the
    * beginning and ending indexes of the substring to insert as the backreference.
    * if no backreference is found, continue copying the subst into tempdst */
   while (*subst && (d_len > 0)) {
      if ((subst[0] == '\\') && isdigit(subst[1])) { /* is this character the beginning of a backreference */
         matchindex = (int) (subst[1] - '0');
         if (matchindex >= ARRAY_LEN(pmatch)) {
            ast_log(LOG_WARNING, "Error during regex substitution. Invalid pmatch index.\n");
            return -1;
         }
         /* pmatch len is 10. we are garanteed a single char 0-9 is a valid index */
         size = pmatch[matchindex].rm_eo - pmatch[matchindex].rm_so;
         if (size > d_len) {
            ast_log(LOG_WARNING, "Not enough space during NAPTR regex substitution.\n");
            return -1;
         }
         /* are the pmatch indexes valid for the input length */
         if ((strlen((char *) naptrinput) >= pmatch[matchindex].rm_eo) && (pmatch[matchindex].rm_so <= pmatch[matchindex].rm_eo)) {
            memcpy(d, (naptrinput + (int) pmatch[matchindex].rm_so), size);  /* copy input substring into backreference marker */
            d_len -= size;
            subst += 2;  /* skip over backreference characters to next valid character */
            d += size;
         } else {
            ast_log(LOG_WARNING, "Error during regex substitution. Invalid backreference index.\n");
            return -1;
         }
      } else if (isprint(*subst)) {
         *d++ = *subst++;
         d_len--;
      } else {
         ast_log(LOG_WARNING, "Error during regex substitution.\n");
         return -1;
      }
   }
   *d = 0;
   ast_copy_string((char *) dst, tempdst, dstsize);
   dst[dstsize - 1] = '\0';

   if (*tech != '\0'){ /* check if it is requested NAPTR */
      if (!strncasecmp(tech, "ALL", techsize)){
         return 0; /* return or count any RR */
      }
      if (!strncasecmp(tech_return, tech, sizeof(tech_return) < techsize ? sizeof(tech_return): techsize)){
         ast_copy_string(tech, tech_return, techsize);
         return 0; /* we got our RR */
      } else { /* go to the next RR in the DNS answer */
         return 1;
      }
   }

   /* tech was not specified, return first parsed RR */
   ast_copy_string(tech, tech_return, techsize);

   return 0;
}
static int private_enum_init ( int  reload) [static]

Initialize the ENUM support subsystem.

Definition at line 959 of file enum.c.

References ast_config_destroy(), ast_config_load2(), ast_copy_string(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, enumlock, ENUMLOOKUP_BLR_CC, ENUMLOOKUP_BLR_EBL, ENUMLOOKUP_BLR_TXT, EVENT_FLAG_SYSTEM, LOG_WARNING, and manager_event.

Referenced by ast_enum_init(), and ast_enum_reload().

{
   struct ast_config *cfg;
   const char *string;
   struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };

   if ((cfg = ast_config_load2("enum.conf", "enum", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
      return 0;
   if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
      return 0;
   }

   /* Destroy existing list */
   ast_mutex_lock(&enumlock);
   if (cfg) {
      if ((string = ast_variable_retrieve(cfg, "ienum", "branchlabel"))) {
         ast_copy_string(ienum_branchlabel, string, sizeof(ienum_branchlabel));
      }

      if ((string = ast_variable_retrieve(cfg, "ienum", "ebl_alg"))) {
         ebl_alg = ENUMLOOKUP_BLR_CC; /* default */

         if (!strcasecmp(string, "txt"))
            ebl_alg = ENUMLOOKUP_BLR_TXT; 
         else if (!strcasecmp(string, "ebl"))
            ebl_alg = ENUMLOOKUP_BLR_EBL; 
         else if (!strcasecmp(string, "cc"))
            ebl_alg = ENUMLOOKUP_BLR_CC; 
         else
            ast_log(LOG_WARNING, "No valid parameter for ienum/ebl_alg.\n");
      }
      ast_config_destroy(cfg);
   }
   ast_mutex_unlock(&enumlock);
   manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Enum\r\nStatus: Enabled\r\nMessage: ENUM reload Requested\r\n");
   return 0;
}
static int txt_callback ( void *  context,
unsigned char *  answer,
int  len,
unsigned char *  fullanswer 
) [static]

Callback for TXT record lookup, /ol version.

Definition at line 141 of file enum.c.

References ast_copy_string(), ast_log(), context, LOG_WARNING, txt_context::txt, and txt_context::txtlen.

Referenced by blr_txt().

{
   struct txt_context *c = context;
   unsigned int i;

   c->txt[0] = 0; /* default to empty */
   c->txtlen = 0;

   if (answer == NULL) {
      return 0;
   }

   /* RFC1035: 
    *
    * <character-string> is a single length octet followed by that number of characters.
    * TXT-DATA        One or more <character-string>s.
    *
    * We only take the first string here.
    */

   i = *answer++;
   len -= 1;

   if (i > len) { /* illegal packet */
      ast_log(LOG_WARNING, "txt_callback: malformed TXT record.\n");
      return 0;
   }

   if (i >= sizeof(c->txt)) { /* too long? */
      ast_log(LOG_WARNING, "txt_callback: TXT record too long.\n");
      i = sizeof(c->txt) - 1;
   }

   ast_copy_string(c->txt, (char *)answer, i + 1);  /* this handles the \0 termination */
   c->txtlen = i;

   return 1;
}

Variable Documentation

int ebl_alg = ENUMLOOKUP_BLR_CC [static]

Definition at line 86 of file enum.c.

ast_mutex_t enumlock = AST_MUTEX_INIT_VALUE [static]

Definition at line 91 of file enum.c.

Referenced by ast_get_enum(), blr_ebl(), blr_txt(), and private_enum_init().

char ienum_branchlabel[32] = "i" [static]

Definition at line 81 of file enum.c.