Tue Aug 20 16:35:02 2013

Asterisk developer's documentation


enum.h File Reference

DNS and ENUM functions. More...

#include "asterisk/channel.h"

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 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=%d\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 }


Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1