Sat Mar 10 01:55:21 2012

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"

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 = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static char ienum_branchlabel [32] = "i"


Detailed Description

ENUM Support for Asterisk.

Author:
Mark Spencer <markster@digium.com>
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 999 of file enum.c.

References private_enum_init().

Referenced by main().

01000 {
01001    return private_enum_init(0);
01002 }

int ast_enum_reload ( void   ) 

Definition at line 1004 of file enum.c.

References private_enum_init().

01005 {
01006    return private_enum_init(1);
01007 }

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:
chan Channel
number E164 number with or without the leading +
location Number returned (or SIP uri)
maxloc Max length
technology Technology (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
maxtech Max length
suffix Zone suffix (WARNING: No defaults here any more)
options Options '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
record The position of required RR in the answer list
argcontext Argument for caching results into an enum_context pointer (NULL is used for not caching)
Return values:
1 if found
0 if not found
-1 on hangup

Definition at line 628 of file enum.c.

References ast_autoservice_start(), 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_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, and enum_context::naptrinput.

Referenced by enum_query_read(), and function_enum().

00629 {
00630    struct enum_context *context;
00631    char tmp[512];
00632    char domain[256];
00633    char left[128];
00634    char middle[128];
00635    char naptrinput[128];
00636    char apex[128] = "";
00637    int ret = -1;
00638    /* for ISN rewrite */
00639    char *p1 = NULL;
00640    char *p2 = NULL;
00641    char *p3 = NULL;
00642    int k = 0;
00643    int i = 0;
00644    int z = 0;
00645    int spaceleft = 0;
00646    struct timeval time_start, time_end;
00647 
00648    if (ast_strlen_zero(suffix)) {
00649       ast_log(LOG_WARNING, "ast_get_enum need a suffix parameter now.\n");
00650       return -1;
00651    }
00652 
00653    ast_debug(2, "num='%s', tech='%s', suffix='%s', options='%s', record=%d\n", number, tech, suffix, options, record);
00654 
00655 /*
00656   We don't need that any more, that "n" preceding the number has been replaced by a flag
00657   in the options paramter.
00658    ast_copy_string(naptrinput, number, sizeof(naptrinput));
00659 */
00660 /*
00661  * The "number" parameter includes a leading '+' if it's a full E.164 number (and not ISN)
00662  * We need to preserve that as the regex inside NAPTRs expect the +.
00663  *
00664  * But for the domain generation, the '+' is a nuissance, so we get rid of it.
00665 */
00666    ast_copy_string(naptrinput, number[0] == 'n' ? number + 1 : number, sizeof(naptrinput));
00667    if (number[0] == '+') {
00668       number++;
00669    }
00670 
00671    if (!(context = ast_calloc(1, sizeof(*context)))) {
00672       return -1;
00673    }
00674 
00675    if ((p3 = strchr(naptrinput, '*'))) {
00676       *p3='\0';
00677    }
00678 
00679    context->naptrinput = naptrinput;   /* The number */
00680    context->dst = dst;        /* Return string */
00681    context->dstlen = dstlen;
00682    context->tech = tech;
00683    context->techlen = techlen;
00684    context->options = 0;
00685    context->position = record > 0 ? record : 1;
00686    context->count = 0;
00687    context->naptr_rrs = NULL;
00688    context->naptr_rrs_count = 0;
00689 
00690    /*
00691     * Process options:
00692     *
00693     *    c  Return count, not URI
00694     *    i  Use infrastructure ENUM 
00695     *    s  Do ISN transformation
00696     *    d  Direct DNS query: no reversing.
00697     *
00698     */
00699    if (options != NULL) {
00700       if (strchr(options,'s')) {
00701          context->options |= ENUMLOOKUP_OPTIONS_ISN;
00702       } else if (strchr(options,'i')) {
00703          context->options |= ENUMLOOKUP_OPTIONS_IENUM;
00704       } else if (strchr(options,'d')) {
00705          context->options |= ENUMLOOKUP_OPTIONS_DIRECT;
00706       }
00707       if (strchr(options,'c')) {
00708          context->options |= ENUMLOOKUP_OPTIONS_COUNT;
00709       }
00710       if (strchr(number,'*')) {
00711          context->options |= ENUMLOOKUP_OPTIONS_ISN;
00712       }
00713    }
00714    ast_debug(2, "ENUM options(%s): pos=%d, options='%d'\n", options, context->position, context->options);
00715    ast_debug(1, "n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
00716          number, tech, suffix, context->options, context->position);
00717 
00718    /*
00719     * This code does more than simple RFC3261 ENUM. All these rewriting 
00720     * schemes have in common that they build the FQDN for the NAPTR lookup
00721     * by concatenating
00722     *    - a number which needs be flipped and "."-seperated   (left)
00723     *    - some fixed string              (middle)
00724     *    - an Apex.                 (apex)
00725     *
00726     * The RFC3261 ENUM is: left=full number, middle="", apex=from args.
00727     * ISN:  number = "middle*left", apex=from args
00728     * I-ENUM: EBL parameters build the split, can change apex
00729     * Direct: left="", middle=argument, apex=from args
00730     *
00731     */
00732 
00733    /* default: the whole number will be flipped, no middle domain component */
00734    ast_copy_string(left, number, sizeof(left));
00735    middle[0] = '\0';
00736    /*
00737     * I-ENUM can change the apex, thus we copy it 
00738     */
00739    ast_copy_string(apex, suffix, sizeof(apex));
00740    /* ISN rewrite */
00741    if ((context->options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
00742       *p1++ = '\0';
00743       ast_copy_string(left, number, sizeof(left));
00744       ast_copy_string(middle, p1, sizeof(middle) - 1);
00745       strcat(middle, ".");
00746       ast_debug(2, "ISN ENUM: left=%s, middle='%s'\n", left, middle);
00747    /* Direct DNS lookup rewrite */
00748    } else if (context->options & ENUMLOOKUP_OPTIONS_DIRECT) {
00749       left[0] = 0; /* nothing to flip around */
00750       ast_copy_string(middle, number, sizeof(middle) - 1);
00751       strcat(middle, ".");
00752       ast_debug(2, "DIRECT ENUM:  middle='%s'\n", middle);
00753    /* Infrastructure ENUM rewrite */
00754    } else if (context->options & ENUMLOOKUP_OPTIONS_IENUM) {
00755       int sdl = 0;
00756       char cc[8];
00757       char sep[256], n_apex[256];
00758       int cc_len = cclen(number);
00759       sdl = cc_len;
00760       ast_mutex_lock(&enumlock);
00761       ast_copy_string(sep, ienum_branchlabel, sizeof(sep)); /* default */
00762       ast_mutex_unlock(&enumlock);
00763 
00764       switch (ebl_alg) {
00765       case ENUMLOOKUP_BLR_EBL:
00766          ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
00767          sdl = blr_ebl(cc, suffix, sep, sizeof(sep) - 1, n_apex, sizeof(n_apex) - 1);
00768 
00769          if (sdl >= 0) {
00770             ast_copy_string(apex, n_apex, sizeof(apex));
00771             ast_debug(2, "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
00772          } else {
00773             sdl = cc_len;
00774          }
00775          break;
00776       case ENUMLOOKUP_BLR_TXT:
00777          ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
00778          sdl = blr_txt(cc, suffix);
00779 
00780          if (sdl < 0) {
00781             sdl = cc_len;
00782          }
00783          break;
00784 
00785       case ENUMLOOKUP_BLR_CC: /* BLR is at the country-code level */
00786       default:
00787          sdl = cc_len;
00788          break;
00789       }
00790 
00791       if (sdl > strlen(number)) {   /* Number too short for this sdl? */
00792          ast_log(LOG_WARNING, "I-ENUM: subdomain location %d behind number %s\n", sdl, number);
00793          return 0;
00794       }
00795       ast_copy_string(left, number + sdl, sizeof(left));
00796 
00797       ast_mutex_lock(&enumlock);
00798       ast_copy_string(middle, sep, sizeof(middle) - 1);
00799       strcat(middle, ".");
00800       ast_mutex_unlock(&enumlock);
00801 
00802       /* check the space we need for middle */
00803       if ((sdl * 2 + strlen(middle) + 2) > sizeof(middle)) {
00804          ast_log(LOG_WARNING, "ast_get_enum: not enough space for I-ENUM rewrite.\n");
00805          return -1;
00806       }
00807 
00808       p1 = middle + strlen(middle);
00809       for (p2 = (char *) number + sdl - 1; p2 >= number; p2--) {
00810          if (isdigit(*p2)) {
00811             *p1++ = *p2;
00812             *p1++ = '.';
00813          }
00814       }
00815       *p1 = '\0';
00816 
00817       ast_debug(2, "I-ENUM: cclen=%d, left=%s, middle='%s', apex='%s'\n", cc_len, left, middle, apex);
00818    }
00819 
00820    if (strlen(left) * 2 + 2 > sizeof(domain)) {
00821       ast_log(LOG_WARNING, "string to long in ast_get_enum\n");
00822       return -1;
00823    }
00824 
00825    /* flip left into domain */
00826    p1 = domain;
00827    for (p2 = left + strlen(left); p2 >= left; p2--) {
00828       if (isdigit(*p2)) {
00829          *p1++ = *p2;
00830          *p1++ = '.';
00831       }
00832    }
00833    *p1 = '\0';
00834 
00835    if (chan && ast_autoservice_start(chan) < 0) {
00836       ast_free(context);
00837       return -1;
00838    }
00839 
00840    spaceleft = sizeof(tmp) - 2;
00841    ast_copy_string(tmp, domain, spaceleft);
00842    spaceleft -= strlen(domain);
00843 
00844    if (*middle) {
00845       strncat(tmp, middle, spaceleft);
00846       spaceleft -= strlen(middle);
00847    }
00848 
00849    strncat(tmp,apex,spaceleft);
00850    time_start = ast_tvnow();
00851    ret = ast_search_dns(context, tmp, C_IN, T_NAPTR, enum_callback);
00852    time_end = ast_tvnow();
00853 
00854    ast_debug(2, "profiling: %s, %s, %" PRIi64 " ms\n",
00855          (ret == 0) ? "OK" : "FAIL", tmp, ast_tvdiff_ms(time_end, time_start));
00856 
00857    if (ret < 0) {
00858       ast_debug(1, "No such number found: %s (%s)\n", tmp, strerror(errno));
00859       strcpy(dst, "0");
00860       ret = 0;
00861    }
00862 
00863    if (context->naptr_rrs_count >= context->position && ! (context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
00864       /* sort array by NAPTR order/preference */
00865       for (k = 0; k < context->naptr_rrs_count; k++) {
00866          for (i = 0; i < context->naptr_rrs_count; i++) {
00867             /* use order first and then preference to compare */
00868             if ((ntohs(context->naptr_rrs[k].naptr.order) < ntohs(context->naptr_rrs[i].naptr.order)
00869                  && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
00870                  || (ntohs(context->naptr_rrs[k].naptr.order) > ntohs(context->naptr_rrs[i].naptr.order)
00871                  && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
00872                z = context->naptr_rrs[k].sort_pos;
00873                context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
00874                context->naptr_rrs[i].sort_pos = z;
00875                continue;
00876             }
00877             if (ntohs(context->naptr_rrs[k].naptr.order) == ntohs(context->naptr_rrs[i].naptr.order)) {
00878                if ((ntohs(context->naptr_rrs[k].naptr.pref) < ntohs(context->naptr_rrs[i].naptr.pref)
00879                     && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
00880                     || (ntohs(context->naptr_rrs[k].naptr.pref) > ntohs(context->naptr_rrs[i].naptr.pref)
00881                     && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
00882                   z = context->naptr_rrs[k].sort_pos;
00883                   context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
00884                   context->naptr_rrs[i].sort_pos = z;
00885                }
00886             }
00887          }
00888       }
00889       for (k = 0; k < context->naptr_rrs_count; k++) {
00890          if (context->naptr_rrs[k].sort_pos == context->position - 1) {
00891             ast_copy_string(context->dst, context->naptr_rrs[k].result, dstlen);
00892             ast_copy_string(context->tech, context->naptr_rrs[k].tech, techlen);
00893             break;
00894          }
00895       }
00896    } else if (!(context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
00897       context->dst[0] = 0;
00898    } else if ((context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
00899       snprintf(context->dst, context->dstlen, "%d", context->count);
00900    }
00901 
00902    if (chan) {
00903       ret |= ast_autoservice_stop(chan);
00904    }
00905 
00906    if (!argcontext) {
00907       for (k = 0; k < context->naptr_rrs_count; k++) {
00908          ast_free(context->naptr_rrs[k].result);
00909          ast_free(context->naptr_rrs[k].tech);
00910       }
00911       ast_free(context->naptr_rrs);
00912       ast_free(context);
00913    } else {
00914       *argcontext = context;
00915    }
00916 
00917    return ret;
00918 }

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:
chan Channel
number E164 number with or without the leading +
txt Text string (return value)
maxtxt Max length of "txt"
suffix Zone 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 920 of file enum.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_copy_string(), ast_debug, context, and errno.

Referenced by function_txtcidname().

00921 {
00922    struct txt_context context;
00923    char tmp[259 + 512];
00924    int pos = strlen(number) - 1;
00925    int newpos = 0;
00926    int ret = -1;
00927 
00928    ast_debug(4, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);
00929 
00930    if (chan && ast_autoservice_start(chan) < 0) {
00931       return -1;
00932    }
00933  
00934    if (pos > 128) {
00935       pos = 128;
00936    }
00937 
00938    while (pos >= 0) {
00939       if (isdigit(number[pos])) {
00940          tmp[newpos++] = number[pos];
00941          tmp[newpos++] = '.';
00942       }
00943       pos--;
00944    }
00945 
00946    ast_copy_string(&tmp[newpos], suffix, sizeof(tmp) - newpos);
00947 
00948    if (ret < 0) {
00949       ast_debug(2, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno));
00950       ret = 0;
00951    } else {
00952       ast_copy_string(txt, context.txt, txtlen);
00953    }
00954    if (chan) {
00955       ret |= ast_autoservice_stop(chan);
00956    }
00957    return ret;
00958 }

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 ast_copy_string(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_search_dns(), ast_verb, context, ebl_callback(), enumlock, LOG_WARNING, and T_EBL.

Referenced by ast_get_enum().

00321 {
00322    struct ebl_context context;
00323    char domain[128] = "";
00324    char *p1,*p2;
00325    int ret;
00326 
00327    ast_mutex_lock(&enumlock);
00328 
00329    ast_verb(4, "blr_ebl()  cc='%s', suffix='%s', c_bl='%s'\n", cc, suffix, ienum_branchlabel);
00330 
00331    if (sizeof(domain) < (strlen(cc) * 2 + strlen(ienum_branchlabel) + strlen(suffix) + 2)) {
00332       ast_mutex_unlock(&enumlock);
00333       ast_log(LOG_WARNING, "ERROR: string sizing in blr_EBL.\n");
00334       return -1;
00335    }
00336 
00337    p1 = domain + snprintf(domain, sizeof(domain), "%s.", ienum_branchlabel);
00338    ast_mutex_unlock(&enumlock);
00339 
00340    for (p2 = (char *) cc + strlen(cc) - 1; p2 >= cc; p2--) {
00341       if (isdigit(*p2)) {
00342          *p1++ = *p2;
00343          *p1++ = '.';
00344       }
00345    }
00346    strcat(p1, suffix);
00347 
00348    ast_verb(4, "blr_ebl() FQDN for EBL record: %s, cc was %s\n", domain, cc);
00349 
00350    ret = ast_search_dns(&context, domain, C_IN, T_EBL, ebl_callback);
00351    if (ret > 0) {
00352       ret = context.pos;
00353 
00354       if ((ret >= 0) && (ret < 20)) {
00355          ast_verb(3, "blr_txt() BLR EBL record for %s is %d/%s/%s)\n", cc, ret, context.separator, context.apex);
00356          ast_copy_string(separator, context.separator, sep_len);
00357          ast_copy_string(apex, context.apex, apex_len);
00358          return ret;
00359       }
00360    }
00361    ast_verb(3, "blr_txt() BLR EBL record for %s not found (apex: %s)\n", cc, suffix);
00362    return -1;
00363 }

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, context, enumlock, LOG_WARNING, and txt_callback().

Referenced by ast_get_enum().

00192 {
00193    struct txt_context context;
00194    char domain[128] = "";
00195    char *p1, *p2;
00196    int ret;
00197 
00198    ast_mutex_lock(&enumlock);
00199 
00200    ast_verb(4, "blr_txt()  cc='%s', suffix='%s', c_bl='%s'\n", cc, suffix, ienum_branchlabel);
00201 
00202    if (sizeof(domain) < (strlen(cc) * 2 + strlen(ienum_branchlabel) + strlen(suffix) + 2)) {
00203       ast_mutex_unlock(&enumlock);
00204       ast_log(LOG_WARNING, "ERROR: string sizing in blr_txt.\n");
00205       return -1;
00206    }
00207 
00208    p1 = domain + snprintf(domain, sizeof(domain), "%s.", ienum_branchlabel);
00209    ast_mutex_unlock(&enumlock);
00210 
00211    for (p2 = (char *) cc + strlen(cc) - 1; p2 >= cc; p2--) {
00212       if (isdigit(*p2)) {
00213          *p1++ = *p2;
00214          *p1++ = '.';
00215       }
00216    }
00217    strcat(p1, suffix);
00218 
00219    ast_verb(4, "blr_txt() FQDN for TXT record: %s, cc was %s\n", domain, cc);
00220 
00221    ret = ast_search_dns(&context, domain, C_IN, T_TXT, txt_callback);
00222 
00223    if (ret > 0) {
00224       ret = atoi(context.txt);
00225 
00226       if ((ret >= 0) && (ret < 20)) {
00227          ast_verb(3, "blr_txt() BLR TXT record for %s is %d (apex: %s)\n", cc, ret, suffix);
00228          return ret;
00229       }
00230    }
00231    
00232    ast_verb(3, "blr_txt() BLR TXT record for %s not found (apex: %s)\n", cc, suffix);
00233 
00234    return -1;
00235 }

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

00107 {
00108    int cc;
00109    char digits[3] = "";
00110 
00111    if (!number || (strlen(number) < 3)) {
00112       return 0;
00113    }
00114 
00115    strncpy(digits, number, 2);
00116    
00117    if (!sscanf(digits, "%30d", &cc)) {
00118       return 0;
00119    }
00120 
00121    if (cc / 10 == 1 || cc / 10 == 7)
00122          return 1;
00123 
00124    if (cc == 20 || cc == 27 || (cc >= 30 && cc <= 34) || cc == 36 ||
00125        cc == 39 || cc == 40 || cc == 41 || (cc >= 40 && cc <= 41) ||
00126        (cc >= 43 && cc <= 49) || (cc >= 51 && cc <= 58) ||
00127        (cc >= 60 && cc <= 66) || cc == 81 || cc == 82 || cc == 84 ||
00128        cc == 86 || (cc >= 90 && cc <= 95) || cc == 98) {
00129       return 2;
00130    }
00131 
00132    return 3;
00133 }

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(), LOG_WARNING, ebl_context::pos, ebl_context::sep_len, and ebl_context::separator.

Referenced by blr_ebl().

00247 {
00248    struct ebl_context *c = context;
00249    unsigned int i;
00250 
00251    c->pos = 0; /* default to empty */
00252    c->separator[0] = 0;
00253    c->sep_len = 0;
00254    c->apex[0] = 0;   
00255    c->apex_len = 0;
00256 
00257    if (answer == NULL) {
00258       return 0;
00259    }
00260 
00261    /* draft-lendl-enum-branch-location-record-00
00262     *
00263     *      0  1  2  3  4  5  6  7
00264     *    +--+--+--+--+--+--+--+--+
00265     *    |       POSITION        |
00266     *    +--+--+--+--+--+--+--+--+
00267     *    /       SEPARATOR       /
00268     *    +--+--+--+--+--+--+--+--+
00269     *    /         APEX          /
00270     *    +--+--+--+--+--+--+--+--+
00271     *
00272     *  where POSITION is a single byte, SEPARATOR is a <character-string>
00273     *  and APEX is a <domain-name>. 
00274     * 
00275     */
00276 
00277    c->pos = *answer++;
00278    len -= 1;
00279 
00280    if ((c->pos > 15) || len < 2) {  /* illegal packet */
00281       ast_log(LOG_WARNING, "ebl_callback: malformed EBL record.\n");
00282       return 0;
00283    }
00284 
00285    i = *answer++;
00286    len -= 1;
00287    if (i > len) { /* illegal packet */
00288       ast_log(LOG_WARNING, "ebl_callback: malformed EBL record.\n");
00289       return 0;
00290    }
00291 
00292    ast_copy_string(c->separator, (char *)answer, i + 1);
00293    c->sep_len = i;
00294 
00295    answer += i;
00296    len -= i;
00297 
00298    if ((i = dn_expand((unsigned char *)fullanswer, (unsigned char *)answer + len, 
00299             (unsigned char *)answer, c->apex, sizeof(c->apex) - 1)) < 0) {
00300       ast_log(LOG_WARNING, "Failed to expand hostname\n");
00301       return 0;
00302    }
00303    c->apex[i] = 0;
00304    c->apex_len = i;
00305 
00306    return 1;
00307 }

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(), 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().

00596 {
00597    struct enum_context *c = context;
00598    void *p = NULL;
00599    int res;
00600 
00601    res = parse_naptr((unsigned char *)c->dst, c->dstlen, c->tech, c->techlen, answer, len, (unsigned char *)c->naptrinput);
00602 
00603    if (res < 0) {
00604       ast_log(LOG_WARNING, "Failed to parse naptr\n");
00605       return -1;
00606    } else if ((res == 0) && !ast_strlen_zero(c->dst)) { /* ok, we got needed NAPTR */
00607       if (c->options & ENUMLOOKUP_OPTIONS_COUNT) { /* counting RRs */
00608          c->count++;
00609          snprintf(c->dst, c->dstlen, "%d", c->count);
00610       } else  {
00611          if ((p = ast_realloc(c->naptr_rrs, sizeof(*c->naptr_rrs) * (c->naptr_rrs_count + 1)))) {
00612             c->naptr_rrs = p;
00613             memcpy(&c->naptr_rrs[c->naptr_rrs_count].naptr, answer, sizeof(c->naptr_rrs->naptr));
00614             c->naptr_rrs[c->naptr_rrs_count].result = ast_strdup(c->dst);
00615             c->naptr_rrs[c->naptr_rrs_count].tech = ast_strdup(c->tech);
00616             c->naptr_rrs[c->naptr_rrs_count].sort_pos = c->naptr_rrs_count;
00617             c->naptr_rrs_count++;
00618          }
00619          c->dst[0] = 0;
00620       }
00621       return 0;
00622    }
00623 
00624    return 0;
00625 }

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

00367 {
00368    unsigned int len, olen;
00369 
00370    len = olen = (unsigned int) src[0];
00371    src++;
00372    srclen--;
00373 
00374    if (len > srclen) {
00375       ast_log(LOG_WARNING, "ENUM parsing failed: Wanted %d characters, got %d\n", len, srclen);
00376       return -1;
00377    }
00378 
00379    if (len > maxdatalen)
00380       len = maxdatalen;
00381    memcpy(data, src, len);
00382 
00383    return olen + 1;
00384 }

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

00388 {
00389    char tech_return[80];
00390    char *oanswer = (char *)answer;
00391    char flags[512] = "";
00392    char services[512] = "";
00393    char *p;
00394    char regexp[512] = "";
00395    char repl[512] = "";
00396    char tempdst[512] = "";
00397    char errbuff[512] = "";
00398    char delim;
00399    char *delim2;
00400    char *pattern, *subst, *d;
00401    int res;
00402    int regexp_len, rc;
00403    static const int max_bt = 10; /* max num of regexp backreference allowed, must remain 10 to guarantee a valid backreference index */
00404    int size, matchindex; /* size is the size of the backreference sub. */
00405    size_t d_len = sizeof(tempdst) - 1;
00406    regex_t preg;
00407    regmatch_t pmatch[max_bt];
00408 
00409    tech_return[0] = '\0';
00410    dst[0] = '\0';
00411 
00412    if (len < sizeof(struct naptr)) {
00413       ast_log(LOG_WARNING, "NAPTR record length too short\n");
00414       return -1;
00415    }
00416    answer += sizeof(struct naptr);
00417    len -= sizeof(struct naptr);
00418    if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) {
00419       ast_log(LOG_WARNING, "Failed to get flags from NAPTR record\n");
00420       return -1;
00421    } else {
00422       answer += res;
00423       len -= res;
00424    }
00425 
00426    if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) {
00427       ast_log(LOG_WARNING, "Failed to get services from NAPTR record\n");
00428       return -1;
00429    } else {
00430       answer += res;
00431       len -= res;
00432    }
00433    if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0) {
00434       ast_log(LOG_WARNING, "Failed to get regexp from NAPTR record\n");
00435       return -1;
00436    } else {
00437       answer += res;
00438       len -= res;
00439    }
00440 
00441    if ((res = dn_expand((unsigned char *)oanswer, (unsigned char *)answer + len, (unsigned char *)answer, repl, sizeof(repl) - 1)) < 0) {
00442       ast_log(LOG_WARNING, "Failed to expand hostname\n");
00443       return -1;
00444    }
00445 
00446    ast_debug(3, "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
00447       naptrinput, flags, services, regexp, repl);
00448 
00449 
00450    if (tolower(flags[0]) != 'u') {
00451       ast_log(LOG_WARNING, "NAPTR Flag must be 'U' or 'u'.\n");
00452       return -1;
00453    }
00454 
00455    p = strstr(services, "e2u+");
00456    if (p == NULL)
00457       p = strstr(services, "E2U+");
00458    if (p){
00459       p = p + 4;
00460       if (strchr(p, ':')){
00461          p = strchr(p, ':') + 1;
00462       }
00463       ast_copy_string(tech_return, p, sizeof(tech_return));
00464    } else {
00465 
00466       p = strstr(services, "+e2u");
00467       if (p == NULL)
00468          p = strstr(services, "+E2U");
00469       if (p) {
00470          *p = 0;
00471          p = strchr(services, ':');
00472          if (p)
00473             *p = 0;
00474          ast_copy_string(tech_return, services, sizeof(tech_return));
00475       }
00476    }
00477 
00478    regexp_len = strlen(regexp);
00479    if (regexp_len < 7) {
00480       ast_log(LOG_WARNING, "Regex too short to be meaningful.\n");
00481       return -1;
00482    }
00483 
00484    /* this takes the first character of the regexp (which is a delimiter) 
00485     * and uses that character to find the index of the second delimiter */
00486    delim = regexp[0];
00487    delim2 = strchr(regexp + 1, delim);
00488    if ((delim2 == NULL) || (regexp[regexp_len - 1] != delim)) {  /* is the second delimiter found, and is the end of the regexp a delimiter */
00489       ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n", regexp);
00490       return -1;
00491    } 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 */
00492       ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n", regexp);
00493       return -1;
00494    }
00495    pattern = regexp + 1;   /* pattern is the regex without the begining and ending delimiter */
00496    *delim2 = 0;    /* zero out the middle delimiter */
00497    subst   = delim2 + 1; /* dst substring is everything after the second delimiter. */
00498    regexp[regexp_len - 1] = 0; /* zero out the last delimiter */
00499 
00500 /*
00501  * now do the regex wizardry.
00502  */
00503 
00504    if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) {
00505       ast_log(LOG_WARNING, "NAPTR Regex compilation error (regex = \"%s\").\n", regexp);
00506       return -1;
00507    }
00508 
00509    if (preg.re_nsub > ARRAY_LEN(pmatch)) {
00510       ast_log(LOG_WARNING, "NAPTR Regex compilation error: too many subs.\n");
00511       regfree(&preg);
00512       return -1;
00513    }
00514    /* pmatch is an array containing the substring indexes for the regex backreference sub.
00515     * max_bt is the maximum number of backreferences allowed to be stored in pmatch */
00516    if ((rc = regexec(&preg, (char *) naptrinput, max_bt, pmatch, 0))) {
00517       regerror(rc, &preg, errbuff, sizeof(errbuff));
00518       ast_log(LOG_WARNING, "NAPTR Regex match failed. Reason: %s\n", errbuff);
00519       regfree(&preg);
00520       return -1;
00521    }
00522    regfree(&preg);
00523 
00524    d = tempdst;
00525    d_len--;
00526 
00527    /* perform the backreference sub. Search the subst for backreferences,
00528     * when a backreference is found, retrieve the backreferences number.
00529     * use the backreference number as an index for pmatch to retrieve the
00530     * beginning and ending indexes of the substring to insert as the backreference.
00531     * if no backreference is found, continue copying the subst into tempdst */
00532    while (*subst && (d_len > 0)) {
00533       if ((subst[0] == '\\') && isdigit(subst[1])) { /* is this character the beginning of a backreference */
00534          matchindex = (int) (subst[1] - '0');
00535          if (matchindex >= ARRAY_LEN(pmatch)) {
00536             ast_log(LOG_WARNING, "Error during regex substitution. Invalid pmatch index.\n");
00537             return -1;
00538          }
00539          /* pmatch len is 10. we are garanteed a single char 0-9 is a valid index */
00540          size = pmatch[matchindex].rm_eo - pmatch[matchindex].rm_so;
00541          if (size > d_len) {
00542             ast_log(LOG_WARNING, "Not enough space during NAPTR regex substitution.\n");
00543             return -1;
00544          }
00545          /* are the pmatch indexes valid for the input length */
00546          if ((strlen((char *) naptrinput) >= pmatch[matchindex].rm_eo) && (pmatch[matchindex].rm_so <= pmatch[matchindex].rm_eo)) {
00547             memcpy(d, (naptrinput + (int) pmatch[matchindex].rm_so), size);  /* copy input substring into backreference marker */
00548             d_len -= size;
00549             subst += 2;  /* skip over backreference characters to next valid character */
00550             d += size;
00551          } else {
00552             ast_log(LOG_WARNING, "Error during regex substitution. Invalid backreference index.\n");
00553             return -1;
00554          }
00555       } else if (isprint(*subst)) {
00556          *d++ = *subst++;
00557          d_len--;
00558       } else {
00559          ast_log(LOG_WARNING, "Error during regex substitution.\n");
00560          return -1;
00561       }
00562    }
00563    *d = 0;
00564    ast_copy_string((char *) dst, tempdst, dstsize);
00565    dst[dstsize - 1] = '\0';
00566 
00567    if (*tech != '\0'){ /* check if it is requested NAPTR */
00568       if (!strncasecmp(tech, "ALL", techsize)){
00569          return 0; /* return or count any RR */
00570       }
00571       if (!strncasecmp(tech_return, tech, sizeof(tech_return) < techsize ? sizeof(tech_return): techsize)){
00572          ast_copy_string(tech, tech_return, techsize);
00573          return 0; /* we got our RR */
00574       } else { /* go to the next RR in the DNS answer */
00575          return 1;
00576       }
00577    }
00578 
00579    /* tech was not specified, return first parsed RR */
00580    ast_copy_string(tech, tech_return, techsize);
00581 
00582    return 0;
00583 }

static int private_enum_init ( int  reload  )  [static]

Initialize the ENUM support subsystem.

Definition at line 961 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_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, ebl_alg, enumlock, ENUMLOOKUP_BLR_CC, ENUMLOOKUP_BLR_EBL, ENUMLOOKUP_BLR_TXT, EVENT_FLAG_SYSTEM, ienum_branchlabel, LOG_WARNING, manager_event, and string.

Referenced by ast_enum_init(), and ast_enum_reload().

00962 {
00963    struct ast_config *cfg;
00964    const char *string;
00965    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00966 
00967    if ((cfg = ast_config_load2("enum.conf", "enum", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
00968       return 0;
00969    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
00970       return 0;
00971    }
00972 
00973    /* Destroy existing list */
00974    ast_mutex_lock(&enumlock);
00975    if (cfg) {
00976       if ((string = ast_variable_retrieve(cfg, "ienum", "branchlabel"))) {
00977          ast_copy_string(ienum_branchlabel, string, sizeof(ienum_branchlabel));
00978       }
00979 
00980       if ((string = ast_variable_retrieve(cfg, "ienum", "ebl_alg"))) {
00981          ebl_alg = ENUMLOOKUP_BLR_CC; /* default */
00982 
00983          if (!strcasecmp(string, "txt"))
00984             ebl_alg = ENUMLOOKUP_BLR_TXT; 
00985          else if (!strcasecmp(string, "ebl"))
00986             ebl_alg = ENUMLOOKUP_BLR_EBL; 
00987          else if (!strcasecmp(string, "cc"))
00988             ebl_alg = ENUMLOOKUP_BLR_CC; 
00989          else
00990             ast_log(LOG_WARNING, "No valid parameter for ienum/ebl_alg.\n");
00991       }
00992       ast_config_destroy(cfg);
00993    }
00994    ast_mutex_unlock(&enumlock);
00995    manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Enum\r\nStatus: Enabled\r\nMessage: ENUM reload Requested\r\n");
00996    return 0;
00997 }

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(), LOG_WARNING, txt_context::txt, and txt_context::txtlen.

Referenced by blr_txt().

00142 {
00143    struct txt_context *c = context;
00144    unsigned int i;
00145 
00146    c->txt[0] = 0; /* default to empty */
00147    c->txtlen = 0;
00148 
00149    if (answer == NULL) {
00150       return 0;
00151    }
00152 
00153    /* RFC1035: 
00154     *
00155     * <character-string> is a single length octet followed by that number of characters.
00156     * TXT-DATA        One or more <character-string>s.
00157     *
00158     * We only take the first string here.
00159     */
00160 
00161    i = *answer++;
00162    len -= 1;
00163 
00164    if (i > len) { /* illegal packet */
00165       ast_log(LOG_WARNING, "txt_callback: malformed TXT record.\n");
00166       return 0;
00167    }
00168 
00169    if (i >= sizeof(c->txt)) { /* too long? */
00170       ast_log(LOG_WARNING, "txt_callback: TXT record too long.\n");
00171       i = sizeof(c->txt) - 1;
00172    }
00173 
00174    ast_copy_string(c->txt, (char *)answer, i + 1);  /* this handles the \0 termination */
00175    c->txtlen = i;
00176 
00177    return 1;
00178 }


Variable Documentation

int ebl_alg = ENUMLOOKUP_BLR_CC [static]

Definition at line 86 of file enum.c.

Referenced by private_enum_init().

ast_mutex_t enumlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [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.

Referenced by private_enum_init().


Generated on Sat Mar 10 01:55:21 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7