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 = { PTHREAD_MUTEX_INITIALIZER , 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
Todo:
The service type selection needs to be redone.

Definition in file enum.c.


Define Documentation

#define ENUMLOOKUP_BLR_CC   0

Definition at line 94 of file enum.c.

Referenced by ast_get_enum(), and private_enum_init().

#define ENUMLOOKUP_BLR_EBL   2

Definition at line 96 of file enum.c.

Referenced by ast_get_enum(), and private_enum_init().

#define ENUMLOOKUP_BLR_TXT   1

Definition at line 95 of file enum.c.

Referenced by ast_get_enum(), and private_enum_init().

#define ENUMLOOKUP_OPTIONS_COUNT   1

Definition at line 597 of file enum.c.

Referenced by ast_get_enum(), and enum_callback().

#define ENUMLOOKUP_OPTIONS_DIRECT   8

Definition at line 603 of file enum.c.

Referenced by ast_get_enum().

#define ENUMLOOKUP_OPTIONS_IENUM   4

Definition at line 601 of file enum.c.

Referenced by ast_get_enum().

#define ENUMLOOKUP_OPTIONS_ISN   2

Definition at line 599 of file enum.c.

Referenced by ast_get_enum().

#define T_EBL   65300

Definition at line 100 of file enum.c.

Referenced by blr_ebl().


Function Documentation

int ast_enum_init ( void   ) 

Definition at line 1013 of file enum.c.

References private_enum_init().

Referenced by main().

01014 {
01015    return private_enum_init(0);
01016 }

int ast_enum_reload ( void   ) 

Definition at line 1018 of file enum.c.

References private_enum_init().

01019 {
01020    return private_enum_init(1);
01021 }

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 639 of file enum.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_copy_string(), ast_debug, ast_free, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_search_dns(), ast_strlen_zero, ast_tvdiff_ms(), ast_tvnow(), blr_ebl(), blr_txt(), cclen(), context, enum_context::count, enum_context::dst, enum_context::dstlen, enum_callback(), enumlock, ENUMLOOKUP_BLR_CC, ENUMLOOKUP_BLR_EBL, ENUMLOOKUP_BLR_TXT, ENUMLOOKUP_OPTIONS_COUNT, ENUMLOOKUP_OPTIONS_DIRECT, ENUMLOOKUP_OPTIONS_IENUM, ENUMLOOKUP_OPTIONS_ISN, errno, LOG_WARNING, enum_naptr_rr::naptr, enum_context::naptr_rrs, enum_context::naptr_rrs_count, enum_context::naptrinput, NULL, 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, enum_context::techlen, and tmp().

Referenced by enum_query_read(), and function_enum().

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

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 935 of file enum.c.

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

Referenced by function_txtcidname().

00936 {
00937    struct txt_context context;
00938    char tmp[259 + 512];
00939    int pos = strlen(number) - 1;
00940    int newpos = 0;
00941    int ret = -1;
00942 
00943    ast_debug(4, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);
00944 
00945    if (chan && ast_autoservice_start(chan) < 0) {
00946       return -1;
00947    }
00948 
00949    if (pos > 128) {
00950       pos = 128;
00951    }
00952 
00953    while (pos >= 0) {
00954       if (isdigit(number[pos])) {
00955          tmp[newpos++] = number[pos];
00956          tmp[newpos++] = '.';
00957       }
00958       pos--;
00959    }
00960 
00961    ast_copy_string(&tmp[newpos], suffix, sizeof(tmp) - newpos);
00962 
00963    if (ret < 0) {
00964       ast_debug(2, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno));
00965       ret = 0;
00966    } else {
00967       ast_copy_string(txt, context.txt, txtlen);
00968    }
00969    if (chan) {
00970       ret |= ast_autoservice_stop(chan);
00971    }
00972    return ret;
00973 }

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

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

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

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

static int cclen ( const char *  number  )  [static]

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

Definition at line 117 of file enum.c.

Referenced by ast_get_enum().

00118 {
00119    int cc;
00120    char digits[3] = "";
00121 
00122    if (!number || (strlen(number) < 3)) {
00123       return 0;
00124    }
00125 
00126    strncpy(digits, number, 2);
00127 
00128    if (!sscanf(digits, "%30d", &cc)) {
00129       return 0;
00130    }
00131 
00132    if (cc / 10 == 1 || cc / 10 == 7)
00133       return 1;
00134 
00135    if (cc == 20 || cc == 27 || (cc >= 30 && cc <= 34) || cc == 36 ||
00136        cc == 39 || cc == 40 || cc == 41 || (cc >= 40 && cc <= 41) ||
00137        (cc >= 43 && cc <= 49) || (cc >= 51 && cc <= 58) ||
00138        (cc >= 60 && cc <= 66) || cc == 81 || cc == 82 || cc == 84 ||
00139        cc == 86 || (cc >= 90 && cc <= 95) || cc == 98) {
00140       return 2;
00141    }
00142 
00143    return 3;
00144 }

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

Callback for EBL record lookup.

Definition at line 257 of file enum.c.

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

Referenced by blr_ebl().

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

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

Callback from ENUM lookup function.

Definition at line 606 of file enum.c.

References ast_log, ast_realloc, ast_strdup, ast_strlen_zero, c, 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, NULL, 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().

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

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 377 of file enum.c.

References ast_log, len(), and LOG_WARNING.

Referenced by parse_naptr().

00378 {
00379    unsigned int len, olen;
00380 
00381    len = olen = (unsigned int) src[0];
00382    src++;
00383    srclen--;
00384 
00385    if (len > srclen) {
00386       ast_log(LOG_WARNING, "ENUM parsing failed: Wanted %u characters, got %u\n", len, srclen);
00387       return -1;
00388    }
00389 
00390    if (len > maxdatalen)
00391       len = maxdatalen;
00392    memcpy(data, src, len);
00393 
00394    return olen + 1;
00395 }

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 398 of file enum.c.

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

Referenced by enum_callback().

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

static int private_enum_init ( int  reload  )  [static]

Initialize the ENUM support subsystem.

Definition at line 976 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, LOG_WARNING, and string.

Referenced by ast_enum_init(), and ast_enum_reload().

00977 {
00978    struct ast_config *cfg;
00979    const char *string;
00980    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00981 
00982    if ((cfg = ast_config_load2("enum.conf", "enum", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
00983       return 0;
00984    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
00985       return 0;
00986    }
00987 
00988    /* Destroy existing list */
00989    ast_mutex_lock(&enumlock);
00990    if (cfg) {
00991       if ((string = ast_variable_retrieve(cfg, "ienum", "branchlabel"))) {
00992          ast_copy_string(ienum_branchlabel, string, sizeof(ienum_branchlabel));
00993       }
00994 
00995       if ((string = ast_variable_retrieve(cfg, "ienum", "ebl_alg"))) {
00996          ebl_alg = ENUMLOOKUP_BLR_CC; /* default */
00997 
00998          if (!strcasecmp(string, "txt"))
00999             ebl_alg = ENUMLOOKUP_BLR_TXT;
01000          else if (!strcasecmp(string, "ebl"))
01001             ebl_alg = ENUMLOOKUP_BLR_EBL;
01002          else if (!strcasecmp(string, "cc"))
01003             ebl_alg = ENUMLOOKUP_BLR_CC;
01004          else
01005             ast_log(LOG_WARNING, "No valid parameter for ienum/ebl_alg.\n");
01006       }
01007       ast_config_destroy(cfg);
01008    }
01009    ast_mutex_unlock(&enumlock);
01010    return 0;
01011 }

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 152 of file enum.c.

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

Referenced by blr_txt().

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


Variable Documentation

int ebl_alg = ENUMLOOKUP_BLR_CC [static]

Definition at line 97 of file enum.c.

ast_mutex_t enumlock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Definition at line 102 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 92 of file enum.c.


Generated on Thu Apr 16 06:30:52 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6