56 #include <sys/socket.h>
57 #include <netinet/in.h>
58 #include <arpa/nameser.h>
60 #if __APPLE_CC__ >= 1495
61 #include <arpa/nameser_compat.h>
87 #define ENUMLOOKUP_BLR_CC 0
88 #define ENUMLOOKUP_BLR_TXT 1
89 #define ENUMLOOKUP_BLR_EBL 2
115 if (!number || (strlen(number) < 3)) {
119 strncpy(digits, number, 2);
121 if (!sscanf(digits,
"%30d", &cc)) {
125 if (cc / 10 == 1 || cc / 10 == 7)
128 if (cc == 20 || cc == 27 || (cc >= 30 && cc <= 34) || cc == 36 ||
129 cc == 39 || cc == 40 || cc == 41 || (cc >= 40 && cc <= 41) ||
130 (cc >= 43 && cc <= 49) || (cc >= 51 && cc <= 58) ||
131 (cc >= 60 && cc <= 66) || cc == 81 || cc == 82 || cc == 84 ||
132 cc == 86 || (cc >= 90 && cc <= 95) || cc == 98) {
153 if (answer == NULL) {
173 if (i >=
sizeof(c->
txt)) {
175 i =
sizeof(c->
txt) - 1;
195 static int blr_txt(
const char *cc,
const char *suffix)
198 char domain[128] =
"";
204 ast_verb(4,
"blr_txt() cc='%s', suffix='%s', c_bl='%s'\n", cc, suffix, ienum_branchlabel);
206 if (
sizeof(domain) < (strlen(cc) * 2 + strlen(ienum_branchlabel) + strlen(suffix) + 2)) {
212 p1 = domain + snprintf(domain,
sizeof(domain),
"%s.", ienum_branchlabel);
215 for (p2 = (
char *) cc + strlen(cc) - 1; p2 >= cc; p2--) {
223 ast_verb(4,
"blr_txt() FQDN for TXT record: %s, cc was %s\n", domain, cc);
228 ret = atoi(context.
txt);
230 if ((ret >= 0) && (ret < 20)) {
231 ast_verb(3,
"blr_txt() BLR TXT record for %s is %d (apex: %s)\n", cc, ret, suffix);
236 ast_verb(3,
"blr_txt() BLR TXT record for %s not found (apex: %s)\n", cc, suffix);
261 if (answer == NULL) {
284 if ((c->
pos > 15) || len < 2) {
302 if ((i = dn_expand((
unsigned char *)fullanswer, (
unsigned char *)answer + len,
303 (
unsigned char *)answer, c->
apex,
sizeof(c->
apex) - 1)) < 0) {
327 char domain[128] =
"";
333 ast_verb(4,
"blr_ebl() cc='%s', suffix='%s', c_bl='%s'\n", cc, suffix, ienum_branchlabel);
335 if (
sizeof(domain) < (strlen(cc) * 2 + strlen(ienum_branchlabel) + strlen(suffix) + 2)) {
341 p1 = domain + snprintf(domain,
sizeof(domain),
"%s.", ienum_branchlabel);
344 for (p2 = (
char *) cc + strlen(cc) - 1; p2 >= cc; p2--) {
352 ast_verb(4,
"blr_ebl() FQDN for EBL record: %s, cc was %s\n", domain, cc);
358 if ((ret >= 0) && (ret < 20)) {
359 ast_verb(3,
"blr_txt() BLR EBL record for %s is %d/%s/%s)\n", cc, ret, context.
separator, context.
apex);
365 ast_verb(3,
"blr_txt() BLR EBL record for %s not found (apex: %s)\n", cc, suffix);
370 static unsigned int parse_ie(
char *data,
unsigned int maxdatalen,
unsigned char *src,
unsigned int srclen)
372 unsigned int len, olen;
374 len = olen = (
unsigned int) src[0];
379 ast_log(
LOG_WARNING,
"ENUM parsing failed: Wanted %u characters, got %u\n", len, srclen);
383 if (len > maxdatalen)
385 memcpy(data, src, len);
391 static int parse_naptr(
unsigned char *dst,
int dstsize,
char *tech,
int techsize,
unsigned char *answer,
int len,
unsigned char *naptrinput)
393 char tech_return[80];
394 char *oanswer = (
char *)answer;
395 char flags[512] =
"";
396 char services[512] =
"";
398 char regexp[512] =
"";
400 char tempdst[512] =
"";
401 char errbuff[512] =
"";
404 char *pattern, *subst, *d;
407 static const int max_bt = 10;
408 int size, matchindex;
409 size_t d_len =
sizeof(tempdst) - 1;
411 regmatch_t pmatch[max_bt];
413 tech_return[0] =
'\0';
416 if (len <
sizeof(
struct naptr)) {
420 answer +=
sizeof(
struct naptr);
421 len -=
sizeof(
struct naptr);
422 if ((res =
parse_ie(flags,
sizeof(flags) - 1, answer, len)) < 0) {
430 if ((res =
parse_ie(services,
sizeof(services) - 1, answer, len)) < 0) {
437 if ((res =
parse_ie(regexp,
sizeof(regexp) - 1, answer, len)) < 0) {
445 if ((res = dn_expand((
unsigned char *)oanswer, (
unsigned char *)answer + len, (
unsigned char *)answer, repl,
sizeof(repl) - 1)) < 0) {
450 ast_debug(3,
"NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
451 naptrinput, flags, services, regexp, repl);
454 if (tolower(flags[0]) !=
'u') {
459 p = strstr(services,
"e2u+");
461 p = strstr(services,
"E2U+");
465 p = strchr(p,
':') + 1;
470 p = strstr(services,
"+e2u");
472 p = strstr(services,
"+E2U");
475 p = strchr(services,
':');
482 regexp_len = strlen(regexp);
483 if (regexp_len < 7) {
491 delim2 = strchr(regexp + 1, delim);
492 if ((delim2 == NULL) || (regexp[regexp_len - 1] != delim)) {
495 }
else if (strchr((delim2 + 1), delim) == NULL) {
499 pattern = regexp + 1;
502 regexp[regexp_len - 1] = 0;
508 if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) {
520 if ((rc = regexec(&preg, (
char *) naptrinput, max_bt, pmatch, 0))) {
521 regerror(rc, &preg, errbuff,
sizeof(errbuff));
536 while (*subst && (d_len > 0)) {
537 if ((subst[0] ==
'\\') && isdigit(subst[1])) {
538 matchindex = (int) (subst[1] -
'0');
544 size = pmatch[matchindex].rm_eo - pmatch[matchindex].rm_so;
550 if ((strlen((
char *) naptrinput) >= pmatch[matchindex].rm_eo) && (pmatch[matchindex].rm_so <= pmatch[matchindex].rm_eo)) {
551 memcpy(d, (naptrinput + (
int) pmatch[matchindex].rm_so), size);
556 ast_log(
LOG_WARNING,
"Error during regex substitution. Invalid backreference index.\n");
559 }
else if (isprint(*subst)) {
569 dst[dstsize - 1] =
'\0';
572 if (!strncasecmp(tech,
"ALL", techsize)){
575 if (!strncasecmp(tech_return, tech,
sizeof(tech_return) < techsize ?
sizeof(tech_return): techsize)){
590 #define ENUMLOOKUP_OPTIONS_COUNT 1
592 #define ENUMLOOKUP_OPTIONS_ISN 2
594 #define ENUMLOOKUP_OPTIONS_IENUM 4
596 #define ENUMLOOKUP_OPTIONS_DIRECT 8
650 struct timeval time_start, time_end;
657 ast_debug(2,
"num='%s', tech='%s', suffix='%s', options='%s', record=%u\n", number, tech, suffix, options, record);
670 ast_copy_string(naptrinput, number[0] ==
'n' ? number + 1 : number,
sizeof(naptrinput));
671 if (number[0] ==
'+') {
675 if (!(context =
ast_calloc(1,
sizeof(*context)))) {
679 if ((p3 = strchr(naptrinput,
'*'))) {
686 context->
tech = tech;
689 context->
position = record > 0 ? record : 1;
703 if (options != NULL) {
704 if (strchr(options,
's')) {
706 }
else if (strchr(options,
'i')) {
708 }
else if (strchr(options,
'd')) {
711 if (strchr(options,
'c')) {
714 if (strchr(number,
'*')) {
719 ast_debug(1,
"n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
750 ast_debug(2,
"ISN ENUM: left=%s, middle='%s'\n", left, middle);
756 ast_debug(2,
"DIRECT ENUM: middle='%s'\n", middle);
761 char sep[256], n_apex[256];
762 int cc_len =
cclen(number);
771 sdl =
blr_ebl(cc, suffix, sep,
sizeof(sep) - 1, n_apex,
sizeof(n_apex) - 1);
775 ast_debug(2,
"EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
795 if (sdl > strlen(number)) {
796 ast_log(
LOG_WARNING,
"I-ENUM: subdomain location %d behind number %s\n", sdl, number);
808 if ((sdl * 2 + strlen(middle) + 2) >
sizeof(middle)) {
814 p1 = middle + strlen(middle);
815 for (p2 = (
char *) number + sdl - 1; p2 >= number; p2--) {
823 ast_debug(2,
"I-ENUM: cclen=%d, left=%s, middle='%s', apex='%s'\n", cc_len, left, middle, apex);
826 if (strlen(left) * 2 + 2 >
sizeof(domain)) {
834 for (p2 = left + strlen(left); p2 >= left; p2--) {
847 spaceleft =
sizeof(tmp) - 2;
849 spaceleft -= strlen(domain);
852 strncat(tmp, middle, spaceleft);
853 spaceleft -= strlen(middle);
856 strncat(tmp,apex,spaceleft);
861 ast_debug(2,
"profiling: %s, %s, %" PRIi64
" ms\n",
862 (ret == 0) ?
"OK" :
"FAIL", tmp,
ast_tvdiff_ms(time_end, time_start));
865 ast_debug(1,
"No such number found: %s (%s)\n", tmp, strerror(
errno));
931 int pos = strlen(number) - 1;
935 ast_debug(4,
"ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);
946 if (isdigit(number[pos])) {
947 tmp[newpos++] = number[pos];
956 ast_debug(2,
"No such number found in ENUM: %s (%s)\n", tmp, strerror(
errno));
990 if (!strcasecmp(
string,
"txt"))
992 else if (!strcasecmp(
string,
"ebl"))
994 else if (!strcasecmp(
string,
"cc"))
static int enum_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Callback from ENUM lookup function.
Main Channel structure associated with a channel.
#define ENUMLOOKUP_OPTIONS_COUNT
Asterisk main include file. File version handling, generic pbx functions.
const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Gets a variable.
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
static char ienum_branchlabel[32]
struct enum_naptr_rr * naptr_rrs
static int private_enum_init(int reload)
Initialize the ENUM support subsystem.
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 cclen(const char *number)
Determine the length of a country code when given an E.164 string.
static ast_mutex_t enumlock
Configuration File Parser.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define ast_mutex_lock(a)
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
#define ENUMLOOKUP_OPTIONS_DIRECT
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
#define ast_verb(level,...)
void ast_config_destroy(struct ast_config *config)
Destroys a config.
#define ENUMLOOKUP_BLR_CC
#define CONFIG_STATUS_FILEMISSING
#define EVENT_FLAG_SYSTEM
#define ast_debug(level,...)
Log a DEBUG message.
#define ENUMLOOKUP_BLR_EBL
General Asterisk PBX channel definitions.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
int ast_enum_reload(void)
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
static int txt_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Callback for TXT record lookup, /ol version.
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_txt(struct ast_channel *chan, const char *number, char *txt, int maxtxt, char *suffix)
Lookup DNS TXT record (used by app TXTCIDnum)
Structure used to handle boolean flags.
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 —.
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.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define ast_realloc(a, b)
#define ENUMLOOKUP_OPTIONS_IENUM
#define CONFIG_STATUS_FILEINVALID
static char context[AST_MAX_CONTEXT]
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
#define ENUMLOOKUP_OPTIONS_ISN
#define ENUMLOOKUP_BLR_TXT
static int blr_txt(const char *cc, const char *suffix)
Determine the branch location record as stored in a TXT record.
#define AST_MUTEX_DEFINE_STATIC(mutex)
DNS support for Asterisk.
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.
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
#define CONFIG_STATUS_FILEUNCHANGED
#define ast_mutex_unlock(a)