63#include <sys/socket.h> 
   64#include <netinet/in.h> 
   65#include <arpa/nameser.h> 
   67#include <arpa/nameser_compat.h> 
   93#define ENUMLOOKUP_BLR_CC       0 
   94#define ENUMLOOKUP_BLR_TXT      1 
   95#define ENUMLOOKUP_BLR_EBL      2 
  125    strncpy(digits, 
number, 2);
 
  127    if (!sscanf(digits, 
"%30d", &cc)) {
 
  131    if (cc / 10 == 1 || cc / 10 == 7)
 
  134    if (cc == 20 || cc == 27 || (cc >= 30 && cc <= 34) || cc == 36 ||
 
  135        cc == 39 || cc == 40 || cc == 41 || (cc >= 40 && cc <= 41) ||
 
  136        (cc >= 43 && cc <= 49) || (cc >= 51 && cc <= 58) ||
 
  137        (cc >= 60 && cc <= 66) || cc == 81 || cc == 82 || cc == 84 ||
 
  138        cc == 86 || (cc >= 90 && cc <= 95) || cc == 98) {
 
 
  179    if (i >= 
sizeof(
c->txt)) {  
 
  181        i = 
sizeof(
c->txt) - 1;
 
 
  201static int blr_txt(
const char *cc, 
const char *suffix)
 
  204    char domain[128] = 
"";
 
  212    if (
sizeof(domain) < (strlen(cc) * 2 + strlen(
ienum_branchlabel) + strlen(suffix) + 2)) {
 
  221    for (p2 = (
char *) cc + strlen(cc) - 1; p2 >= cc; p2--) {
 
  229    ast_verb(4, 
"blr_txt() FQDN for TXT record: %s, cc was %s\n", domain, cc);
 
  234        ret = atoi(context.txt);
 
  236        if ((ret >= 0) && (ret < 20)) {
 
  237            ast_verb(3, 
"blr_txt() BLR TXT record for %s is %d (apex: %s)\n", cc, ret, suffix);
 
  242    ast_verb(3, 
"blr_txt() BLR TXT record for %s not found (apex: %s)\n", cc, suffix);
 
 
  290    if ((
c->pos > 15) || 
len < 2) { 
 
  308    if ((i = dn_expand((
unsigned char *)fullanswer, (
unsigned char *)
answer + 
len,
 
  309                (
unsigned char *)
answer, 
c->apex, 
sizeof(
c->apex) - 1)) < 0) {
 
 
  333    char domain[128] = 
"";
 
  341    if (
sizeof(domain) < (strlen(cc) * 2 + strlen(
ienum_branchlabel) + strlen(suffix) + 2)) {
 
  350    for (p2 = (
char *) cc + strlen(cc) - 1; p2 >= cc; p2--) {
 
  358    ast_verb(4, 
"blr_ebl() FQDN for EBL record: %s, cc was %s\n", domain, cc);
 
  364        if ((ret >= 0) && (ret < 20)) {
 
  365            ast_verb(3, 
"blr_txt() BLR EBL record for %s is %d/%s/%s)\n", cc, ret, context.separator, context.apex);
 
  371    ast_verb(3, 
"blr_txt() BLR EBL record for %s not found (apex: %s)\n", cc, suffix);
 
 
  376static unsigned int parse_ie(
char *data, 
unsigned int maxdatalen, 
unsigned char *src, 
unsigned int srclen)
 
  378    unsigned int len, olen;
 
  380    len = olen = (
unsigned int) src[0];
 
  389    if (
len > maxdatalen)
 
  391    memcpy(data, src, 
len);
 
 
  397static int parse_naptr(
unsigned char *dst, 
int dstsize, 
char *tech, 
int techsize, 
unsigned char *
answer, 
int len, 
unsigned char *naptrinput)
 
  399    char tech_return[80];
 
  400    char *oanswer = (
char *)
answer;
 
  401    char flags[512] = 
"";
 
  402    char services[512] = 
"";
 
  404    char regexp[512] = 
"";
 
  406    char tempdst[512] = 
"";
 
  407    char errbuff[512] = 
"";
 
  410    char *pattern, *subst, *
d;
 
  413    static const int max_bt = 10; 
 
  414    int size, matchindex; 
 
  415    size_t d_len = 
sizeof(tempdst) - 1;
 
  417    int re_flags = REG_EXTENDED | REG_NEWLINE;
 
  418    regmatch_t pmatch[max_bt];
 
  420    tech_return[0] = 
'\0';
 
  452    if ((res = dn_expand((
unsigned char *)oanswer, (
unsigned char *)
answer + 
len, (
unsigned char *)
answer, repl, 
sizeof(repl) - 1)) < 0) {
 
  457    ast_debug(3, 
"NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
 
  458        naptrinput, flags, services, regexp, repl);
 
  461    if (tolower(flags[0]) != 
'u') {
 
  466    p = strstr(services, 
"e2u+");
 
  468        p = strstr(services, 
"E2U+");
 
  472            p = strchr(p, 
':') + 1;
 
  477        p = strstr(services, 
"+e2u");
 
  479            p = strstr(services, 
"+E2U");
 
  482            p = strchr(services, 
':');
 
  489    regexp_len = strlen(regexp);
 
  490    if (regexp_len < 7) {
 
  498    delim2 = strchr(regexp + 1, delim);
 
  500        || ((regexp[regexp_len - 1] != 
'i' || regexp[regexp_len - 2] != delim)
 
  501            && regexp[regexp_len - 1] != delim)) {
 
  504    } 
else if (strchr((delim2 + 1), delim) == 
NULL) { 
 
  512    if (regexp[regexp_len - 1] == 
'i') {
 
  513        re_flags |= REG_ICASE;
 
  516    pattern = regexp + 1;   
 
  519    regexp[regexp_len - 1] = 0; 
 
  525    if (regcomp(&preg, pattern, re_flags)) {
 
  537    if ((rc = regexec(&preg, (
char *) naptrinput, max_bt, pmatch, 0))) {
 
  538        regerror(rc, &preg, errbuff, 
sizeof(errbuff));
 
  553    while (*subst && (d_len > 0)) {
 
  554        if ((subst[0] == 
'\\') && isdigit(subst[1])) { 
 
  555            matchindex = (int) (subst[1] - 
'0');
 
  561            size = pmatch[matchindex].rm_eo - pmatch[matchindex].rm_so;
 
  567            if ((strlen((
char *) naptrinput) >= pmatch[matchindex].rm_eo) && (pmatch[matchindex].rm_so <= pmatch[matchindex].rm_eo)) {
 
  568                memcpy(
d, (naptrinput + (
int) pmatch[matchindex].rm_so), size);  
 
  573                ast_log(
LOG_WARNING, 
"Error during regex substitution. Invalid backreference index.\n");
 
  576        } 
else if (isprint(*subst)) {
 
  586    dst[dstsize - 1] = 
'\0';
 
  589        if (!strncasecmp(tech, 
"ALL", techsize)){
 
  592        if (!strncasecmp(tech_return, tech, 
sizeof(tech_return) < techsize ? 
sizeof(tech_return): techsize)){
 
 
  607#define ENUMLOOKUP_OPTIONS_COUNT       1 
  609#define ENUMLOOKUP_OPTIONS_ISN      2 
  611#define ENUMLOOKUP_OPTIONS_IENUM    4 
  613#define ENUMLOOKUP_OPTIONS_DIRECT   8 
  630            snprintf(
c->dst, 
c->dstlen, 
"%d", 
c->count);
 
  632            if ((p = 
ast_realloc(
c->naptr_rrs, 
sizeof(*
c->naptr_rrs) * (
c->naptr_rrs_count + 1)))) {
 
  634                memcpy(&
c->naptr_rrs[
c->naptr_rrs_count].naptr, 
answer, 
sizeof(
c->naptr_rrs->naptr));
 
  635                c->naptr_rrs[
c->naptr_rrs_count].result = 
ast_strdup(
c->dst);
 
  637                c->naptr_rrs[
c->naptr_rrs_count].sort_pos = 
c->naptr_rrs_count;
 
  638                c->naptr_rrs_count++;
 
 
  667    struct timeval time_start, time_end;
 
  674    ast_debug(2, 
"num='%s', tech='%s', suffix='%s', options='%s', record=%u\n", 
number, tech, suffix, 
options, record);
 
  692    if (!(context = 
ast_calloc(1, 
sizeof(*context)))) {
 
  696    if ((p3 = strchr(naptrinput, 
'*'))) {
 
  700    context->naptrinput = naptrinput;   
 
  702    context->dstlen = dstlen;
 
  703    context->tech = tech;
 
  704    context->techlen = techlen;
 
  705    context->options = 0;
 
  706    context->position = record > 0 ? record : 1;
 
  708    context->naptr_rrs = 
NULL;
 
  709    context->naptr_rrs_count = 0;
 
  723        } 
else if (strchr(
options,
'i')) {
 
  725        } 
else if (strchr(
options,
'd')) {
 
  735    ast_debug(2, 
"ENUM options(%s): pos=%d, options='%d'\n", 
options, context->position, context->options);
 
  736    ast_debug(1, 
"n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
 
  737            number, tech, suffix, context->options, context->position);
 
  767        ast_debug(2, 
"ISN ENUM: left=%s, middle='%s'\n", left, middle);
 
  773        ast_debug(2, 
"DIRECT ENUM:  middle='%s'\n", middle);
 
  778        char sep[256], n_apex[256];
 
  788            sdl = 
blr_ebl(cc, suffix, sep, 
sizeof(sep) - 1, n_apex, 
sizeof(n_apex) - 1);
 
  792                ast_debug(2, 
"EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
 
  812        if (sdl > strlen(
number)) { 
 
  825        if ((sdl * 2 + strlen(middle) + 2) > 
sizeof(middle)) {
 
  831        p1 = middle + strlen(middle);
 
  832        for (p2 = (
char *) 
number + sdl - 1; p2 >= 
number; p2--) {
 
  840        ast_debug(2, 
"I-ENUM: cclen=%d, left=%s, middle='%s', apex='%s'\n", cc_len, left, middle, apex);
 
  843    if (strlen(left) * 2 + 2 > 
sizeof(domain)) {
 
  851    for (p2 = left + strlen(left); p2 >= left; p2--) {
 
  864    spaceleft = 
sizeof(tmp) - 2;
 
  866    spaceleft -= strlen(domain);
 
  869        strncat(tmp, middle, spaceleft);
 
  870        spaceleft -= strlen(middle);
 
  873    strncat(tmp,apex,spaceleft);
 
  878    ast_debug(2, 
"profiling: %s, %s, %" PRIi64 
" ms\n",
 
  879            (ret == 0) ? 
"OK" : 
"FAIL", tmp, 
ast_tvdiff_ms(time_end, time_start));
 
  882        ast_debug(1, 
"No such number found: %s (%s)\n", tmp, strerror(
errno));
 
  883        context->naptr_rrs_count = -1;
 
  890        for (k = 0; k < context->naptr_rrs_count; k++) {
 
  891            for (i = 0; i < context->naptr_rrs_count; i++) {
 
  893                if ((ntohs(context->naptr_rrs[k].naptr.order) < ntohs(context->naptr_rrs[i].naptr.order)
 
  894                     && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
 
  895                     || (ntohs(context->naptr_rrs[k].naptr.order) > ntohs(context->naptr_rrs[i].naptr.order)
 
  896                     && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
 
  897                    z = context->naptr_rrs[k].sort_pos;
 
  898                    context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
 
  899                    context->naptr_rrs[i].sort_pos = z;
 
  902                if (ntohs(context->naptr_rrs[k].naptr.order) == ntohs(context->naptr_rrs[i].naptr.order)) {
 
  903                    if ((ntohs(context->naptr_rrs[k].naptr.pref) < ntohs(context->naptr_rrs[i].naptr.pref)
 
  904                         && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
 
  905                         || (ntohs(context->naptr_rrs[k].naptr.pref) > ntohs(context->naptr_rrs[i].naptr.pref)
 
  906                         && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
 
  907                        z = context->naptr_rrs[k].sort_pos;
 
  908                        context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
 
  909                        context->naptr_rrs[i].sort_pos = z;
 
  914        for (k = 0; k < context->naptr_rrs_count; k++) {
 
  915            if (context->naptr_rrs[k].sort_pos == context->position - 1) {
 
  924        snprintf(context->dst, context->dstlen, 
"%d", context->naptr_rrs_count + context->count);
 
  932        for (k = 0; k < context->naptr_rrs_count; k++) {
 
  933            ast_free(context->naptr_rrs[k].result);
 
  934            ast_free(context->naptr_rrs[k].tech);
 
  939        *argcontext = context;
 
 
  958    size_t suffix_length;
 
  959    size_t number_length = strlen(
number);
 
  960    const char *src = 
number + number_length - 1;
 
  963        suffix = 
"e164.arpa";
 
  966    suffix_length = strlen(suffix);
 
  985        if (*suffix == 
'.') {
 
  986            memcpy(dst, &suffix[1], suffix_length);
 
  988            memcpy(dst, suffix, suffix_length + 1);
 
 
 1000    int autoservice = 0;
 
 1002    ast_debug(4, 
"ast_get_txt: Number = '%s', suffix = '%s'\n", 
number, suffix);
 
 1018        ast_debug(2, 
"No such number found in ENUM: %s (%s)\n", domain, strerror(
errno));
 
 
 1052            if (!strcasecmp(
string, 
"txt"))
 
 1054            else if (!strcasecmp(
string, 
"ebl"))
 
 1056            else if (!strcasecmp(
string, 
"cc"))
 
 
 1088    .
requires = 
"extconfig",
 
Asterisk main include file. File version handling, generic pbx functions.
#define ast_realloc(p, len)
A wrapper for realloc()
#define ast_strdup(str)
A wrapper for strdup()
#define ast_calloc(num, len)
A wrapper for calloc()
#define ast_malloc(len)
A wrapper for malloc()
static int answer(void *data)
General Asterisk PBX channel definitions.
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
DNS support for Asterisk.
int ast_search_dns(void *context, const char *dname, int class, int type, int(*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
Perform DNS lookup (used by DNS, enum and SRV lookups)
static int private_enum_init(int reload)
Initialize the ENUM support subsystem.
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 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 txt_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Callback for TXT record lookup, /ol version.
#define ENUMLOOKUP_BLR_TXT
static char ienum_branchlabel[32]
#define ENUMLOOKUP_BLR_CC
static unsigned int parse_ie(char *data, unsigned int maxdatalen, unsigned char *src, unsigned int srclen)
Parse NAPTR record information elements.
static int ebl_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Callback for EBL record lookup.
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.
static int reload_module(void)
#define ENUMLOOKUP_OPTIONS_COUNT
static char * format_numeric_domain(const char *number, const char *suffix)
#define ENUMLOOKUP_BLR_EBL
static int enum_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Callback from ENUM lookup function.
static int cclen(const char *number)
Determine the length of a country code when given an E.164 string.
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 ast_mutex_t enumlock
#define ENUMLOOKUP_OPTIONS_ISN
static int blr_txt(const char *cc, const char *suffix)
Determine the branch location record as stored in a TXT record.
static int load_module(void)
#define ENUMLOOKUP_OPTIONS_IENUM
static int unload_module(void)
#define ENUMLOOKUP_OPTIONS_DIRECT
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Configuration File Parser.
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
#define CONFIG_STATUS_FILEMISSING
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
@ CONFIG_FLAG_FILEUNCHANGED
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_verb(level,...)
#define ast_mutex_unlock(a)
#define ast_mutex_lock(a)
#define AST_MUTEX_DEFINE_STATIC(mutex)
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
Asterisk module definitions.
@ AST_MODFLAG_GLOBAL_SYMBOLS
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_FAILURE
Module could not be loaded properly.
@ AST_MODULE_LOAD_SUCCESS
static force_inline int attribute_pure ast_strlen_zero(const char *s)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Main Channel structure associated with a channel.
Structure used to handle boolean flags.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().