Thu Oct 11 06:48:46 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"

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_t) PTHREAD_MUTEX_INITIALIZER )
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
Todo:
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().

00998 {
00999    return private_enum_init(0);
01000 }

int ast_enum_reload ( void   ) 

Definition at line 1002 of file enum.c.

References private_enum_init().

01003 {
01004    return private_enum_init(1);
01005 }

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

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_verb(2, "ast_get_enum(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    if((p3 = strchr(naptrinput, '*'))) {
00675       *p3='\0';      
00676    }
00677 
00678    context->naptrinput = naptrinput;   /* The number */
00679    context->dst = dst;        /* Return string */
00680    context->dstlen = dstlen;
00681    context->tech = tech;
00682    context->techlen = techlen;
00683    context->options = 0;
00684    context->position = record > 0 ? record : 1;
00685    context->count = 0;
00686    context->naptr_rrs = NULL;
00687    context->naptr_rrs_count = 0;
00688 
00689    /*
00690     * Process options:
00691     *
00692     *    c  Return count, not URI
00693     *    i  Use infrastructure ENUM 
00694     *    s  Do ISN transformation
00695     *    d  Direct DNS query: no reversing.
00696     *
00697     */
00698    if (options != NULL) {
00699       if (strchr(options,'s')) {
00700          context->options |= ENUMLOOKUP_OPTIONS_ISN;
00701       } else if (strchr(options,'i')) {
00702          context->options |= ENUMLOOKUP_OPTIONS_IENUM;
00703       } else if (strchr(options,'d')) {
00704          context->options |= ENUMLOOKUP_OPTIONS_DIRECT;
00705       }
00706       if (strchr(options,'c')) {
00707          context->options |= ENUMLOOKUP_OPTIONS_COUNT;
00708       }
00709       if (strchr(number,'*')) {
00710          context->options |= ENUMLOOKUP_OPTIONS_ISN;
00711       }
00712    }
00713    ast_verb(2, "ENUM options(%s): pos=%d, options='%d'\n", options, context->position, context->options);
00714    ast_debug(1, "ast_get_enum(): n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
00715          number, tech, suffix, context->options, context->position);
00716 
00717    /*
00718     * This code does more than simple RFC3261 ENUM. All these rewriting 
00719     * schemes have in common that they build the FQDN for the NAPTR lookup
00720     * by concatenating
00721     *    - a number which needs be flipped and "."-seperated   (left)
00722     *    - some fixed string              (middle)
00723     *    - an Apex.                 (apex)
00724     *
00725     * The RFC3261 ENUM is: left=full number, middle="", apex=from args.
00726     * ISN:  number = "middle*left", apex=from args
00727     * I-ENUM: EBL parameters build the split, can change apex
00728     * Direct: left="", middle=argument, apex=from args
00729     *
00730     */
00731 
00732    /* default: the whole number will be flipped, no middle domain component */
00733    ast_copy_string(left, number, sizeof(left));
00734    middle[0] = '\0';
00735    /*
00736     * I-ENUM can change the apex, thus we copy it 
00737     */
00738    ast_copy_string(apex, suffix, sizeof(apex));
00739    /* ISN rewrite */
00740    if ((context->options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
00741       *p1++ = '\0';
00742       ast_copy_string(left, number, sizeof(left));
00743       ast_copy_string(middle, p1, sizeof(middle) - 1);
00744       strcat(middle, ".");
00745 
00746       ast_verb(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  
00753       ast_verb(2, "DIRECT ENUM:  middle='%s'\n", middle);
00754    /* Infrastructure ENUM rewrite */
00755    } else if (context->options & ENUMLOOKUP_OPTIONS_IENUM) {
00756       int sdl = 0;
00757       char cc[8];
00758       char sep[256], n_apex[256];
00759       int cc_len = cclen(number);
00760       sdl = cc_len;
00761       ast_mutex_lock(&enumlock);
00762       ast_copy_string(sep, ienum_branchlabel, sizeof(sep)); /* default */
00763       ast_mutex_unlock(&enumlock);
00764 
00765       switch (ebl_alg) {
00766       case ENUMLOOKUP_BLR_EBL:
00767          ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
00768          sdl = blr_ebl(cc, suffix, sep, sizeof(sep) - 1, n_apex, sizeof(n_apex) - 1);
00769 
00770          if (sdl >= 0) {
00771             ast_copy_string(apex, n_apex, sizeof(apex));
00772             ast_verb(2, "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
00773          } else {
00774             sdl = cc_len;
00775          }
00776          break;
00777       case ENUMLOOKUP_BLR_TXT:
00778          ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
00779          sdl = blr_txt(cc, suffix);
00780 
00781          if (sdl < 0) 
00782             sdl = cc_len;
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_verb(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_verb(2, "ast_get_enum() profiling: %s, %s, %d 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    if (!argcontext) {
00906       for (k = 0; k < context->naptr_rrs_count; k++) {
00907          ast_free(context->naptr_rrs[k].result);
00908          ast_free(context->naptr_rrs[k].tech);
00909       }
00910       ast_free(context->naptr_rrs);
00911       ast_free(context);
00912    } else
00913       *argcontext = context;
00914 
00915    return ret;
00916 }

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

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

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

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

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

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.

ast_mutex_t enumlock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [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.


Generated on Thu Oct 11 06:48:46 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6