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) | |
DNS and ENUM functions.
Definition in file enum.h.
| int ast_enum_init | ( | void | ) |
Definition at line 999 of file enum.c.
References private_enum_init().
Referenced by main().
{
return private_enum_init(0);
}
| int ast_enum_reload | ( | void | ) |
Definition at line 1004 of file enum.c.
References private_enum_init().
{
return private_enum_init(1);
}
| 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.
| 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) |
| 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(), 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().
{
struct enum_context *context;
char tmp[512];
char domain[256];
char left[128];
char middle[128];
char naptrinput[128];
char apex[128] = "";
int ret = -1;
/* for ISN rewrite */
char *p1 = NULL;
char *p2 = NULL;
char *p3 = NULL;
int k = 0;
int i = 0;
int z = 0;
int spaceleft = 0;
struct timeval time_start, time_end;
if (ast_strlen_zero(suffix)) {
ast_log(LOG_WARNING, "ast_get_enum need a suffix parameter now.\n");
return -1;
}
ast_debug(2, "num='%s', tech='%s', suffix='%s', options='%s', record=%d\n", number, tech, suffix, options, record);
/*
We don't need that any more, that "n" preceding the number has been replaced by a flag
in the options paramter.
ast_copy_string(naptrinput, number, sizeof(naptrinput));
*/
/*
* The "number" parameter includes a leading '+' if it's a full E.164 number (and not ISN)
* We need to preserve that as the regex inside NAPTRs expect the +.
*
* But for the domain generation, the '+' is a nuissance, so we get rid of it.
*/
ast_copy_string(naptrinput, number[0] == 'n' ? number + 1 : number, sizeof(naptrinput));
if (number[0] == '+') {
number++;
}
if (!(context = ast_calloc(1, sizeof(*context)))) {
return -1;
}
if ((p3 = strchr(naptrinput, '*'))) {
*p3='\0';
}
context->naptrinput = naptrinput; /* The number */
context->dst = dst; /* Return string */
context->dstlen = dstlen;
context->tech = tech;
context->techlen = techlen;
context->options = 0;
context->position = record > 0 ? record : 1;
context->count = 0;
context->naptr_rrs = NULL;
context->naptr_rrs_count = 0;
/*
* Process options:
*
* c Return count, not URI
* i Use infrastructure ENUM
* s Do ISN transformation
* d Direct DNS query: no reversing.
*
*/
if (options != NULL) {
if (strchr(options,'s')) {
context->options |= ENUMLOOKUP_OPTIONS_ISN;
} else if (strchr(options,'i')) {
context->options |= ENUMLOOKUP_OPTIONS_IENUM;
} else if (strchr(options,'d')) {
context->options |= ENUMLOOKUP_OPTIONS_DIRECT;
}
if (strchr(options,'c')) {
context->options |= ENUMLOOKUP_OPTIONS_COUNT;
}
if (strchr(number,'*')) {
context->options |= ENUMLOOKUP_OPTIONS_ISN;
}
}
ast_debug(2, "ENUM options(%s): pos=%d, options='%d'\n", options, context->position, context->options);
ast_debug(1, "n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
number, tech, suffix, context->options, context->position);
/*
* This code does more than simple RFC3261 ENUM. All these rewriting
* schemes have in common that they build the FQDN for the NAPTR lookup
* by concatenating
* - a number which needs be flipped and "."-seperated (left)
* - some fixed string (middle)
* - an Apex. (apex)
*
* The RFC3261 ENUM is: left=full number, middle="", apex=from args.
* ISN: number = "middle*left", apex=from args
* I-ENUM: EBL parameters build the split, can change apex
* Direct: left="", middle=argument, apex=from args
*
*/
/* default: the whole number will be flipped, no middle domain component */
ast_copy_string(left, number, sizeof(left));
middle[0] = '\0';
/*
* I-ENUM can change the apex, thus we copy it
*/
ast_copy_string(apex, suffix, sizeof(apex));
/* ISN rewrite */
if ((context->options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
*p1++ = '\0';
ast_copy_string(left, number, sizeof(left));
ast_copy_string(middle, p1, sizeof(middle) - 1);
strcat(middle, ".");
ast_debug(2, "ISN ENUM: left=%s, middle='%s'\n", left, middle);
/* Direct DNS lookup rewrite */
} else if (context->options & ENUMLOOKUP_OPTIONS_DIRECT) {
left[0] = 0; /* nothing to flip around */
ast_copy_string(middle, number, sizeof(middle) - 1);
strcat(middle, ".");
ast_debug(2, "DIRECT ENUM: middle='%s'\n", middle);
/* Infrastructure ENUM rewrite */
} else if (context->options & ENUMLOOKUP_OPTIONS_IENUM) {
int sdl = 0;
char cc[8];
char sep[256], n_apex[256];
int cc_len = cclen(number);
sdl = cc_len;
ast_mutex_lock(&enumlock);
ast_copy_string(sep, ienum_branchlabel, sizeof(sep)); /* default */
ast_mutex_unlock(&enumlock);
switch (ebl_alg) {
case ENUMLOOKUP_BLR_EBL:
ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
sdl = blr_ebl(cc, suffix, sep, sizeof(sep) - 1, n_apex, sizeof(n_apex) - 1);
if (sdl >= 0) {
ast_copy_string(apex, n_apex, sizeof(apex));
ast_debug(2, "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
} else {
sdl = cc_len;
}
break;
case ENUMLOOKUP_BLR_TXT:
ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
sdl = blr_txt(cc, suffix);
if (sdl < 0) {
sdl = cc_len;
}
break;
case ENUMLOOKUP_BLR_CC: /* BLR is at the country-code level */
default:
sdl = cc_len;
break;
}
if (sdl > strlen(number)) { /* Number too short for this sdl? */
ast_log(LOG_WARNING, "I-ENUM: subdomain location %d behind number %s\n", sdl, number);
return 0;
}
ast_copy_string(left, number + sdl, sizeof(left));
ast_mutex_lock(&enumlock);
ast_copy_string(middle, sep, sizeof(middle) - 1);
strcat(middle, ".");
ast_mutex_unlock(&enumlock);
/* check the space we need for middle */
if ((sdl * 2 + strlen(middle) + 2) > sizeof(middle)) {
ast_log(LOG_WARNING, "ast_get_enum: not enough space for I-ENUM rewrite.\n");
return -1;
}
p1 = middle + strlen(middle);
for (p2 = (char *) number + sdl - 1; p2 >= number; p2--) {
if (isdigit(*p2)) {
*p1++ = *p2;
*p1++ = '.';
}
}
*p1 = '\0';
ast_debug(2, "I-ENUM: cclen=%d, left=%s, middle='%s', apex='%s'\n", cc_len, left, middle, apex);
}
if (strlen(left) * 2 + 2 > sizeof(domain)) {
ast_log(LOG_WARNING, "string to long in ast_get_enum\n");
return -1;
}
/* flip left into domain */
p1 = domain;
for (p2 = left + strlen(left); p2 >= left; p2--) {
if (isdigit(*p2)) {
*p1++ = *p2;
*p1++ = '.';
}
}
*p1 = '\0';
if (chan && ast_autoservice_start(chan) < 0) {
ast_free(context);
return -1;
}
spaceleft = sizeof(tmp) - 2;
ast_copy_string(tmp, domain, spaceleft);
spaceleft -= strlen(domain);
if (*middle) {
strncat(tmp, middle, spaceleft);
spaceleft -= strlen(middle);
}
strncat(tmp,apex,spaceleft);
time_start = ast_tvnow();
ret = ast_search_dns(context, tmp, C_IN, T_NAPTR, enum_callback);
time_end = ast_tvnow();
ast_debug(2, "profiling: %s, %s, %" PRIi64 " ms\n",
(ret == 0) ? "OK" : "FAIL", tmp, ast_tvdiff_ms(time_end, time_start));
if (ret < 0) {
ast_debug(1, "No such number found: %s (%s)\n", tmp, strerror(errno));
strcpy(dst, "0");
ret = 0;
}
if (context->naptr_rrs_count >= context->position && ! (context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
/* sort array by NAPTR order/preference */
for (k = 0; k < context->naptr_rrs_count; k++) {
for (i = 0; i < context->naptr_rrs_count; i++) {
/* use order first and then preference to compare */
if ((ntohs(context->naptr_rrs[k].naptr.order) < ntohs(context->naptr_rrs[i].naptr.order)
&& context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
|| (ntohs(context->naptr_rrs[k].naptr.order) > ntohs(context->naptr_rrs[i].naptr.order)
&& context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
z = context->naptr_rrs[k].sort_pos;
context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
context->naptr_rrs[i].sort_pos = z;
continue;
}
if (ntohs(context->naptr_rrs[k].naptr.order) == ntohs(context->naptr_rrs[i].naptr.order)) {
if ((ntohs(context->naptr_rrs[k].naptr.pref) < ntohs(context->naptr_rrs[i].naptr.pref)
&& context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
|| (ntohs(context->naptr_rrs[k].naptr.pref) > ntohs(context->naptr_rrs[i].naptr.pref)
&& context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
z = context->naptr_rrs[k].sort_pos;
context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
context->naptr_rrs[i].sort_pos = z;
}
}
}
}
for (k = 0; k < context->naptr_rrs_count; k++) {
if (context->naptr_rrs[k].sort_pos == context->position - 1) {
ast_copy_string(context->dst, context->naptr_rrs[k].result, dstlen);
ast_copy_string(context->tech, context->naptr_rrs[k].tech, techlen);
break;
}
}
} else if (!(context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
context->dst[0] = 0;
} else if ((context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
snprintf(context->dst, context->dstlen, "%d", context->count);
}
if (chan) {
ret |= ast_autoservice_stop(chan);
}
if (!argcontext) {
for (k = 0; k < context->naptr_rrs_count; k++) {
ast_free(context->naptr_rrs[k].result);
ast_free(context->naptr_rrs[k].tech);
}
ast_free(context->naptr_rrs);
ast_free(context);
} else {
*argcontext = context;
}
return ret;
}
| 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.
| chan | Channel |
| number | E164 number with or without the leading + |
| txt | Text string (return value) |
| maxtxt | Max length of "txt" |
| suffix | Zone suffix |
Definition at line 920 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().
{
struct txt_context context;
char tmp[259 + 512];
int pos = strlen(number) - 1;
int newpos = 0;
int ret = -1;
ast_debug(4, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);
if (chan && ast_autoservice_start(chan) < 0) {
return -1;
}
if (pos > 128) {
pos = 128;
}
while (pos >= 0) {
if (isdigit(number[pos])) {
tmp[newpos++] = number[pos];
tmp[newpos++] = '.';
}
pos--;
}
ast_copy_string(&tmp[newpos], suffix, sizeof(tmp) - newpos);
if (ret < 0) {
ast_debug(2, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno));
ret = 0;
} else {
ast_copy_string(txt, context.txt, txtlen);
}
if (chan) {
ret |= ast_autoservice_stop(chan);
}
return ret;
}