Thu Sep 7 01:03:27 2017

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

Referenced by ast_get_enum(), and private_enum_init().

#define ENUMLOOKUP_BLR_EBL   2

Definition at line 89 of file enum.c.

Referenced by ast_get_enum(), and private_enum_init().

#define ENUMLOOKUP_BLR_TXT   1

Definition at line 88 of file enum.c.

Referenced by ast_get_enum(), and private_enum_init().

#define ENUMLOOKUP_OPTIONS_COUNT   1

Definition at line 590 of file enum.c.

Referenced by ast_get_enum(), and enum_callback().

#define ENUMLOOKUP_OPTIONS_DIRECT   8

Definition at line 596 of file enum.c.

Referenced by ast_get_enum().

#define ENUMLOOKUP_OPTIONS_IENUM   4

Definition at line 594 of file enum.c.

Referenced by ast_get_enum().

#define ENUMLOOKUP_OPTIONS_ISN   2

Definition at line 592 of file enum.c.

Referenced by ast_get_enum().

#define T_EBL   65300

Definition at line 93 of file enum.c.

Referenced by blr_ebl().


Function Documentation

int ast_enum_init ( void   ) 

Definition at line 1006 of file enum.c.

References private_enum_init().

Referenced by main().

01007 {
01008    return private_enum_init(0);
01009 }

int ast_enum_reload ( void   ) 

Definition at line 1011 of file enum.c.

References private_enum_init().

01012 {
01013    return private_enum_init(1);
01014 }

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

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

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

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

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

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

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

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

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

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

Definition at line 110 of file enum.c.

Referenced by ast_get_enum().

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

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

Callback for EBL record lookup.

Definition at line 250 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().

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

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

Callback from ENUM lookup function.

Definition at line 599 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().

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

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

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

Referenced by parse_naptr().

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

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

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

Referenced by enum_callback().

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

static int private_enum_init ( int  reload  )  [static]

Initialize the ENUM support subsystem.

Definition at line 968 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, manager_event, and string.

Referenced by ast_enum_init(), and ast_enum_reload().

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

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

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

Referenced by blr_txt().

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


Variable Documentation

int ebl_alg = ENUMLOOKUP_BLR_CC [static]

Definition at line 90 of file enum.c.

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

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


Generated on 7 Sep 2017 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1