Thu Oct 11 06:48:46 2012

Asterisk developer's documentation


enum.h File Reference

DNS and ENUM functions. More...

#include "asterisk/channel.h"

Include dependency graph for enum.h:

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  enum_context
struct  enum_naptr_rr
struct  naptr

Functions

int ast_enum_init (void)
int ast_enum_reload (void)
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.
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).


Detailed Description

DNS and ENUM functions.

Definition in file enum.h.


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 }


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