00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 #include "asterisk.h"
00049
00050 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 329471 $")
00051
00052 #include <sys/socket.h>
00053 #include <netinet/in.h>
00054 #include <arpa/nameser.h>
00055 #ifdef __APPLE__
00056 #if __APPLE_CC__ >= 1495
00057 #include <arpa/nameser_compat.h>
00058 #endif
00059 #endif
00060 #include <resolv.h>
00061 #include <ctype.h>
00062 #include <regex.h>
00063
00064 #include "asterisk/enum.h"
00065 #include "asterisk/dns.h"
00066 #include "asterisk/channel.h"
00067 #include "asterisk/config.h"
00068 #include "asterisk/utils.h"
00069 #include "asterisk/manager.h"
00070
00071 #ifdef __APPLE__
00072 #undef T_NAPTR
00073 #define T_NAPTR 35
00074 #endif
00075
00076 #ifdef __APPLE__
00077 #undef T_TXT
00078 #define T_TXT 16
00079 #endif
00080
00081 static char ienum_branchlabel[32] = "i";
00082
00083 #define ENUMLOOKUP_BLR_CC 0
00084 #define ENUMLOOKUP_BLR_TXT 1
00085 #define ENUMLOOKUP_BLR_EBL 2
00086 static int ebl_alg = ENUMLOOKUP_BLR_CC;
00087
00088
00089 #define T_EBL 65300
00090
00091 AST_MUTEX_DEFINE_STATIC(enumlock);
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 static int cclen(const char *number)
00107 {
00108 int cc;
00109 char digits[3] = "";
00110
00111 if (!number || (strlen(number) < 3)) {
00112 return 0;
00113 }
00114
00115 strncpy(digits, number, 2);
00116
00117 if (!sscanf(digits, "%30d", &cc)) {
00118 return 0;
00119 }
00120
00121 if (cc / 10 == 1 || cc / 10 == 7)
00122 return 1;
00123
00124 if (cc == 20 || cc == 27 || (cc >= 30 && cc <= 34) || cc == 36 ||
00125 cc == 39 || cc == 40 || cc == 41 || (cc >= 40 && cc <= 41) ||
00126 (cc >= 43 && cc <= 49) || (cc >= 51 && cc <= 58) ||
00127 (cc >= 60 && cc <= 66) || cc == 81 || cc == 82 || cc == 84 ||
00128 cc == 86 || (cc >= 90 && cc <= 95) || cc == 98) {
00129 return 2;
00130 }
00131
00132 return 3;
00133 }
00134
00135 struct txt_context {
00136 char txt[1024];
00137 int txtlen;
00138 };
00139
00140
00141 static int txt_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
00142 {
00143 struct txt_context *c = context;
00144 unsigned int i;
00145
00146 c->txt[0] = 0;
00147 c->txtlen = 0;
00148
00149 if (answer == NULL) {
00150 return 0;
00151 }
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 i = *answer++;
00162 len -= 1;
00163
00164 if (i > len) {
00165 ast_log(LOG_WARNING, "txt_callback: malformed TXT record.\n");
00166 return 0;
00167 }
00168
00169 if (i >= sizeof(c->txt)) {
00170 ast_log(LOG_WARNING, "txt_callback: TXT record too long.\n");
00171 i = sizeof(c->txt) - 1;
00172 }
00173
00174 ast_copy_string(c->txt, (char *)answer, i + 1);
00175 c->txtlen = i;
00176
00177 return 1;
00178 }
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 static int blr_txt(const char *cc, const char *suffix)
00192 {
00193 struct txt_context context;
00194 char domain[128] = "";
00195 char *p1, *p2;
00196 int ret;
00197
00198 ast_mutex_lock(&enumlock);
00199
00200 ast_verb(4, "blr_txt() cc='%s', suffix='%s', c_bl='%s'\n", cc, suffix, ienum_branchlabel);
00201
00202 if (sizeof(domain) < (strlen(cc) * 2 + strlen(ienum_branchlabel) + strlen(suffix) + 2)) {
00203 ast_mutex_unlock(&enumlock);
00204 ast_log(LOG_WARNING, "ERROR: string sizing in blr_txt.\n");
00205 return -1;
00206 }
00207
00208 p1 = domain + snprintf(domain, sizeof(domain), "%s.", ienum_branchlabel);
00209 ast_mutex_unlock(&enumlock);
00210
00211 for (p2 = (char *) cc + strlen(cc) - 1; p2 >= cc; p2--) {
00212 if (isdigit(*p2)) {
00213 *p1++ = *p2;
00214 *p1++ = '.';
00215 }
00216 }
00217 strcat(p1, suffix);
00218
00219 ast_verb(4, "blr_txt() FQDN for TXT record: %s, cc was %s\n", domain, cc);
00220
00221 ret = ast_search_dns(&context, domain, C_IN, T_TXT, txt_callback);
00222
00223 if (ret > 0) {
00224 ret = atoi(context.txt);
00225
00226 if ((ret >= 0) && (ret < 20)) {
00227 ast_verb(3, "blr_txt() BLR TXT record for %s is %d (apex: %s)\n", cc, ret, suffix);
00228 return ret;
00229 }
00230 }
00231
00232 ast_verb(3, "blr_txt() BLR TXT record for %s not found (apex: %s)\n", cc, suffix);
00233
00234 return -1;
00235 }
00236
00237 struct ebl_context {
00238 unsigned char pos;
00239 char separator[256];
00240 int sep_len;
00241 char apex[256];
00242 int apex_len;
00243 };
00244
00245
00246 static int ebl_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
00247 {
00248 struct ebl_context *c = context;
00249 unsigned int i;
00250
00251 c->pos = 0;
00252 c->separator[0] = 0;
00253 c->sep_len = 0;
00254 c->apex[0] = 0;
00255 c->apex_len = 0;
00256
00257 if (answer == NULL) {
00258 return 0;
00259 }
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 c->pos = *answer++;
00278 len -= 1;
00279
00280 if ((c->pos > 15) || len < 2) {
00281 ast_log(LOG_WARNING, "ebl_callback: malformed EBL record.\n");
00282 return 0;
00283 }
00284
00285 i = *answer++;
00286 len -= 1;
00287 if (i > len) {
00288 ast_log(LOG_WARNING, "ebl_callback: malformed EBL record.\n");
00289 return 0;
00290 }
00291
00292 ast_copy_string(c->separator, (char *)answer, i + 1);
00293 c->sep_len = i;
00294
00295 answer += i;
00296 len -= i;
00297
00298 if ((i = dn_expand((unsigned char *)fullanswer, (unsigned char *)answer + len,
00299 (unsigned char *)answer, c->apex, sizeof(c->apex) - 1)) < 0) {
00300 ast_log(LOG_WARNING, "Failed to expand hostname\n");
00301 return 0;
00302 }
00303 c->apex[i] = 0;
00304 c->apex_len = i;
00305
00306 return 1;
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 static int blr_ebl(const char *cc, const char *suffix, char *separator, int sep_len, char* apex, int apex_len)
00321 {
00322 struct ebl_context context;
00323 char domain[128] = "";
00324 char *p1,*p2;
00325 int ret;
00326
00327 ast_mutex_lock(&enumlock);
00328
00329 ast_verb(4, "blr_ebl() cc='%s', suffix='%s', c_bl='%s'\n", cc, suffix, ienum_branchlabel);
00330
00331 if (sizeof(domain) < (strlen(cc) * 2 + strlen(ienum_branchlabel) + strlen(suffix) + 2)) {
00332 ast_mutex_unlock(&enumlock);
00333 ast_log(LOG_WARNING, "ERROR: string sizing in blr_EBL.\n");
00334 return -1;
00335 }
00336
00337 p1 = domain + snprintf(domain, sizeof(domain), "%s.", ienum_branchlabel);
00338 ast_mutex_unlock(&enumlock);
00339
00340 for (p2 = (char *) cc + strlen(cc) - 1; p2 >= cc; p2--) {
00341 if (isdigit(*p2)) {
00342 *p1++ = *p2;
00343 *p1++ = '.';
00344 }
00345 }
00346 strcat(p1, suffix);
00347
00348 ast_verb(4, "blr_ebl() FQDN for EBL record: %s, cc was %s\n", domain, cc);
00349
00350 ret = ast_search_dns(&context, domain, C_IN, T_EBL, ebl_callback);
00351 if (ret > 0) {
00352 ret = context.pos;
00353
00354 if ((ret >= 0) && (ret < 20)) {
00355 ast_verb(3, "blr_txt() BLR EBL record for %s is %d/%s/%s)\n", cc, ret, context.separator, context.apex);
00356 ast_copy_string(separator, context.separator, sep_len);
00357 ast_copy_string(apex, context.apex, apex_len);
00358 return ret;
00359 }
00360 }
00361 ast_verb(3, "blr_txt() BLR EBL record for %s not found (apex: %s)\n", cc, suffix);
00362 return -1;
00363 }
00364
00365
00366 static unsigned int parse_ie(char *data, unsigned int maxdatalen, unsigned char *src, unsigned int srclen)
00367 {
00368 unsigned int len, olen;
00369
00370 len = olen = (unsigned int) src[0];
00371 src++;
00372 srclen--;
00373
00374 if (len > srclen) {
00375 ast_log(LOG_WARNING, "ENUM parsing failed: Wanted %d characters, got %d\n", len, srclen);
00376 return -1;
00377 }
00378
00379 if (len > maxdatalen)
00380 len = maxdatalen;
00381 memcpy(data, src, len);
00382
00383 return olen + 1;
00384 }
00385
00386
00387 static int parse_naptr(unsigned char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, unsigned char *naptrinput)
00388 {
00389 char tech_return[80];
00390 char *oanswer = (char *)answer;
00391 char flags[512] = "";
00392 char services[512] = "";
00393 char *p;
00394 char regexp[512] = "";
00395 char repl[512] = "";
00396 char tempdst[512] = "";
00397 char errbuff[512] = "";
00398 char delim;
00399 char *delim2;
00400 char *pattern, *subst, *d;
00401 int res;
00402 int regexp_len, rc;
00403 static const int max_bt = 10;
00404 int size, matchindex;
00405 size_t d_len = sizeof(tempdst) - 1;
00406 regex_t preg;
00407 regmatch_t pmatch[max_bt];
00408
00409 tech_return[0] = '\0';
00410 dst[0] = '\0';
00411
00412 if (len < sizeof(struct naptr)) {
00413 ast_log(LOG_WARNING, "NAPTR record length too short\n");
00414 return -1;
00415 }
00416 answer += sizeof(struct naptr);
00417 len -= sizeof(struct naptr);
00418 if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) {
00419 ast_log(LOG_WARNING, "Failed to get flags from NAPTR record\n");
00420 return -1;
00421 } else {
00422 answer += res;
00423 len -= res;
00424 }
00425
00426 if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) {
00427 ast_log(LOG_WARNING, "Failed to get services from NAPTR record\n");
00428 return -1;
00429 } else {
00430 answer += res;
00431 len -= res;
00432 }
00433 if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0) {
00434 ast_log(LOG_WARNING, "Failed to get regexp from NAPTR record\n");
00435 return -1;
00436 } else {
00437 answer += res;
00438 len -= res;
00439 }
00440
00441 if ((res = dn_expand((unsigned char *)oanswer, (unsigned char *)answer + len, (unsigned char *)answer, repl, sizeof(repl) - 1)) < 0) {
00442 ast_log(LOG_WARNING, "Failed to expand hostname\n");
00443 return -1;
00444 }
00445
00446 ast_debug(3, "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
00447 naptrinput, flags, services, regexp, repl);
00448
00449
00450 if (tolower(flags[0]) != 'u') {
00451 ast_log(LOG_WARNING, "NAPTR Flag must be 'U' or 'u'.\n");
00452 return -1;
00453 }
00454
00455 p = strstr(services, "e2u+");
00456 if (p == NULL)
00457 p = strstr(services, "E2U+");
00458 if (p){
00459 p = p + 4;
00460 if (strchr(p, ':')){
00461 p = strchr(p, ':') + 1;
00462 }
00463 ast_copy_string(tech_return, p, sizeof(tech_return));
00464 } else {
00465
00466 p = strstr(services, "+e2u");
00467 if (p == NULL)
00468 p = strstr(services, "+E2U");
00469 if (p) {
00470 *p = 0;
00471 p = strchr(services, ':');
00472 if (p)
00473 *p = 0;
00474 ast_copy_string(tech_return, services, sizeof(tech_return));
00475 }
00476 }
00477
00478 regexp_len = strlen(regexp);
00479 if (regexp_len < 7) {
00480 ast_log(LOG_WARNING, "Regex too short to be meaningful.\n");
00481 return -1;
00482 }
00483
00484
00485
00486 delim = regexp[0];
00487 delim2 = strchr(regexp + 1, delim);
00488 if ((delim2 == NULL) || (regexp[regexp_len - 1] != delim)) {
00489 ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n", regexp);
00490 return -1;
00491 } else if (strchr((delim2 + 1), delim) == NULL) {
00492 ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n", regexp);
00493 return -1;
00494 }
00495 pattern = regexp + 1;
00496 *delim2 = 0;
00497 subst = delim2 + 1;
00498 regexp[regexp_len - 1] = 0;
00499
00500
00501
00502
00503
00504 if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) {
00505 ast_log(LOG_WARNING, "NAPTR Regex compilation error (regex = \"%s\").\n", regexp);
00506 return -1;
00507 }
00508
00509 if (preg.re_nsub > ARRAY_LEN(pmatch)) {
00510 ast_log(LOG_WARNING, "NAPTR Regex compilation error: too many subs.\n");
00511 regfree(&preg);
00512 return -1;
00513 }
00514
00515
00516 if ((rc = regexec(&preg, (char *) naptrinput, max_bt, pmatch, 0))) {
00517 regerror(rc, &preg, errbuff, sizeof(errbuff));
00518 ast_log(LOG_WARNING, "NAPTR Regex match failed. Reason: %s\n", errbuff);
00519 regfree(&preg);
00520 return -1;
00521 }
00522 regfree(&preg);
00523
00524 d = tempdst;
00525 d_len--;
00526
00527
00528
00529
00530
00531
00532 while (*subst && (d_len > 0)) {
00533 if ((subst[0] == '\\') && isdigit(subst[1])) {
00534 matchindex = (int) (subst[1] - '0');
00535 if (matchindex >= ARRAY_LEN(pmatch)) {
00536 ast_log(LOG_WARNING, "Error during regex substitution. Invalid pmatch index.\n");
00537 return -1;
00538 }
00539
00540 size = pmatch[matchindex].rm_eo - pmatch[matchindex].rm_so;
00541 if (size > d_len) {
00542 ast_log(LOG_WARNING, "Not enough space during NAPTR regex substitution.\n");
00543 return -1;
00544 }
00545
00546 if ((strlen((char *) naptrinput) >= pmatch[matchindex].rm_eo) && (pmatch[matchindex].rm_so <= pmatch[matchindex].rm_eo)) {
00547 memcpy(d, (naptrinput + (int) pmatch[matchindex].rm_so), size);
00548 d_len -= size;
00549 subst += 2;
00550 d += size;
00551 } else {
00552 ast_log(LOG_WARNING, "Error during regex substitution. Invalid backreference index.\n");
00553 return -1;
00554 }
00555 } else if (isprint(*subst)) {
00556 *d++ = *subst++;
00557 d_len--;
00558 } else {
00559 ast_log(LOG_WARNING, "Error during regex substitution.\n");
00560 return -1;
00561 }
00562 }
00563 *d = 0;
00564 ast_copy_string((char *) dst, tempdst, dstsize);
00565 dst[dstsize - 1] = '\0';
00566
00567 if (*tech != '\0'){
00568 if (!strncasecmp(tech, "ALL", techsize)){
00569 return 0;
00570 }
00571 if (!strncasecmp(tech_return, tech, sizeof(tech_return) < techsize ? sizeof(tech_return): techsize)){
00572 ast_copy_string(tech, tech_return, techsize);
00573 return 0;
00574 } else {
00575 return 1;
00576 }
00577 }
00578
00579
00580 ast_copy_string(tech, tech_return, techsize);
00581
00582 return 0;
00583 }
00584
00585
00586 #define ENUMLOOKUP_OPTIONS_COUNT 1
00587
00588 #define ENUMLOOKUP_OPTIONS_ISN 2
00589
00590 #define ENUMLOOKUP_OPTIONS_IENUM 4
00591
00592 #define ENUMLOOKUP_OPTIONS_DIRECT 8
00593
00594
00595 static int enum_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
00596 {
00597 struct enum_context *c = context;
00598 void *p = NULL;
00599 int res;
00600
00601 res = parse_naptr((unsigned char *)c->dst, c->dstlen, c->tech, c->techlen, answer, len, (unsigned char *)c->naptrinput);
00602
00603 if (res < 0) {
00604 ast_log(LOG_WARNING, "Failed to parse naptr\n");
00605 return -1;
00606 } else if ((res == 0) && !ast_strlen_zero(c->dst)) {
00607 if (c->options & ENUMLOOKUP_OPTIONS_COUNT) {
00608 c->count++;
00609 snprintf(c->dst, c->dstlen, "%d", c->count);
00610 } else {
00611 if ((p = ast_realloc(c->naptr_rrs, sizeof(*c->naptr_rrs) * (c->naptr_rrs_count + 1)))) {
00612 c->naptr_rrs = p;
00613 memcpy(&c->naptr_rrs[c->naptr_rrs_count].naptr, answer, sizeof(c->naptr_rrs->naptr));
00614 c->naptr_rrs[c->naptr_rrs_count].result = ast_strdup(c->dst);
00615 c->naptr_rrs[c->naptr_rrs_count].tech = ast_strdup(c->tech);
00616 c->naptr_rrs[c->naptr_rrs_count].sort_pos = c->naptr_rrs_count;
00617 c->naptr_rrs_count++;
00618 }
00619 c->dst[0] = 0;
00620 }
00621 return 0;
00622 }
00623
00624 return 0;
00625 }
00626
00627
00628 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)
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
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_debug(2, "num='%s', tech='%s', suffix='%s', options='%s', record=%d\n", number, tech, suffix, options, record);
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
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
00675 if ((p3 = strchr(naptrinput, '*'))) {
00676 *p3='\0';
00677 }
00678
00679 context->naptrinput = naptrinput;
00680 context->dst = dst;
00681 context->dstlen = dstlen;
00682 context->tech = tech;
00683 context->techlen = techlen;
00684 context->options = 0;
00685 context->position = record > 0 ? record : 1;
00686 context->count = 0;
00687 context->naptr_rrs = NULL;
00688 context->naptr_rrs_count = 0;
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699 if (options != NULL) {
00700 if (strchr(options,'s')) {
00701 context->options |= ENUMLOOKUP_OPTIONS_ISN;
00702 } else if (strchr(options,'i')) {
00703 context->options |= ENUMLOOKUP_OPTIONS_IENUM;
00704 } else if (strchr(options,'d')) {
00705 context->options |= ENUMLOOKUP_OPTIONS_DIRECT;
00706 }
00707 if (strchr(options,'c')) {
00708 context->options |= ENUMLOOKUP_OPTIONS_COUNT;
00709 }
00710 if (strchr(number,'*')) {
00711 context->options |= ENUMLOOKUP_OPTIONS_ISN;
00712 }
00713 }
00714 ast_debug(2, "ENUM options(%s): pos=%d, options='%d'\n", options, context->position, context->options);
00715 ast_debug(1, "n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
00716 number, tech, suffix, context->options, context->position);
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734 ast_copy_string(left, number, sizeof(left));
00735 middle[0] = '\0';
00736
00737
00738
00739 ast_copy_string(apex, suffix, sizeof(apex));
00740
00741 if ((context->options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
00742 *p1++ = '\0';
00743 ast_copy_string(left, number, sizeof(left));
00744 ast_copy_string(middle, p1, sizeof(middle) - 1);
00745 strcat(middle, ".");
00746 ast_debug(2, "ISN ENUM: left=%s, middle='%s'\n", left, middle);
00747
00748 } else if (context->options & ENUMLOOKUP_OPTIONS_DIRECT) {
00749 left[0] = 0;
00750 ast_copy_string(middle, number, sizeof(middle) - 1);
00751 strcat(middle, ".");
00752 ast_debug(2, "DIRECT ENUM: middle='%s'\n", middle);
00753
00754 } else if (context->options & ENUMLOOKUP_OPTIONS_IENUM) {
00755 int sdl = 0;
00756 char cc[8];
00757 char sep[256], n_apex[256];
00758 int cc_len = cclen(number);
00759 sdl = cc_len;
00760 ast_mutex_lock(&enumlock);
00761 ast_copy_string(sep, ienum_branchlabel, sizeof(sep));
00762 ast_mutex_unlock(&enumlock);
00763
00764 switch (ebl_alg) {
00765 case ENUMLOOKUP_BLR_EBL:
00766 ast_copy_string(cc, number, cc_len);
00767 sdl = blr_ebl(cc, suffix, sep, sizeof(sep) - 1, n_apex, sizeof(n_apex) - 1);
00768
00769 if (sdl >= 0) {
00770 ast_copy_string(apex, n_apex, sizeof(apex));
00771 ast_debug(2, "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
00772 } else {
00773 sdl = cc_len;
00774 }
00775 break;
00776 case ENUMLOOKUP_BLR_TXT:
00777 ast_copy_string(cc, number, cc_len);
00778 sdl = blr_txt(cc, suffix);
00779
00780 if (sdl < 0) {
00781 sdl = cc_len;
00782 }
00783 break;
00784
00785 case ENUMLOOKUP_BLR_CC:
00786 default:
00787 sdl = cc_len;
00788 break;
00789 }
00790
00791 if (sdl > strlen(number)) {
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
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_debug(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
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_debug(2, "profiling: %s, %s, %" PRIi64 " 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
00865 for (k = 0; k < context->naptr_rrs_count; k++) {
00866 for (i = 0; i < context->naptr_rrs_count; i++) {
00867
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
00906 if (!argcontext) {
00907 for (k = 0; k < context->naptr_rrs_count; k++) {
00908 ast_free(context->naptr_rrs[k].result);
00909 ast_free(context->naptr_rrs[k].tech);
00910 }
00911 ast_free(context->naptr_rrs);
00912 ast_free(context);
00913 } else {
00914 *argcontext = context;
00915 }
00916
00917 return ret;
00918 }
00919
00920 int ast_get_txt(struct ast_channel *chan, const char *number, char *txt, int txtlen, char *suffix)
00921 {
00922 struct txt_context context;
00923 char tmp[259 + 512];
00924 int pos = strlen(number) - 1;
00925 int newpos = 0;
00926 int ret = -1;
00927
00928 ast_debug(4, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);
00929
00930 if (chan && ast_autoservice_start(chan) < 0) {
00931 return -1;
00932 }
00933
00934 if (pos > 128) {
00935 pos = 128;
00936 }
00937
00938 while (pos >= 0) {
00939 if (isdigit(number[pos])) {
00940 tmp[newpos++] = number[pos];
00941 tmp[newpos++] = '.';
00942 }
00943 pos--;
00944 }
00945
00946 ast_copy_string(&tmp[newpos], suffix, sizeof(tmp) - newpos);
00947
00948 if (ret < 0) {
00949 ast_debug(2, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno));
00950 ret = 0;
00951 } else {
00952 ast_copy_string(txt, context.txt, txtlen);
00953 }
00954 if (chan) {
00955 ret |= ast_autoservice_stop(chan);
00956 }
00957 return ret;
00958 }
00959
00960
00961 static int private_enum_init(int reload)
00962 {
00963 struct ast_config *cfg;
00964 const char *string;
00965 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00966
00967 if ((cfg = ast_config_load2("enum.conf", "enum", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
00968 return 0;
00969 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
00970 return 0;
00971 }
00972
00973
00974 ast_mutex_lock(&enumlock);
00975 if (cfg) {
00976 if ((string = ast_variable_retrieve(cfg, "ienum", "branchlabel"))) {
00977 ast_copy_string(ienum_branchlabel, string, sizeof(ienum_branchlabel));
00978 }
00979
00980 if ((string = ast_variable_retrieve(cfg, "ienum", "ebl_alg"))) {
00981 ebl_alg = ENUMLOOKUP_BLR_CC;
00982
00983 if (!strcasecmp(string, "txt"))
00984 ebl_alg = ENUMLOOKUP_BLR_TXT;
00985 else if (!strcasecmp(string, "ebl"))
00986 ebl_alg = ENUMLOOKUP_BLR_EBL;
00987 else if (!strcasecmp(string, "cc"))
00988 ebl_alg = ENUMLOOKUP_BLR_CC;
00989 else
00990 ast_log(LOG_WARNING, "No valid parameter for ienum/ebl_alg.\n");
00991 }
00992 ast_config_destroy(cfg);
00993 }
00994 ast_mutex_unlock(&enumlock);
00995 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Enum\r\nStatus: Enabled\r\nMessage: ENUM reload Requested\r\n");
00996 return 0;
00997 }
00998
00999 int ast_enum_init(void)
01000 {
01001 return private_enum_init(0);
01002 }
01003
01004 int ast_enum_reload(void)
01005 {
01006 return private_enum_init(1);
01007 }