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: 241143 $")
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_verb(2, "ast_get_enum(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 if((p3 = strchr(naptrinput, '*'))) {
00675 *p3='\0';
00676 }
00677
00678 context->naptrinput = naptrinput;
00679 context->dst = dst;
00680 context->dstlen = dstlen;
00681 context->tech = tech;
00682 context->techlen = techlen;
00683 context->options = 0;
00684 context->position = record > 0 ? record : 1;
00685 context->count = 0;
00686 context->naptr_rrs = NULL;
00687 context->naptr_rrs_count = 0;
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698 if (options != NULL) {
00699 if (strchr(options,'s')) {
00700 context->options |= ENUMLOOKUP_OPTIONS_ISN;
00701 } else if (strchr(options,'i')) {
00702 context->options |= ENUMLOOKUP_OPTIONS_IENUM;
00703 } else if (strchr(options,'d')) {
00704 context->options |= ENUMLOOKUP_OPTIONS_DIRECT;
00705 }
00706 if (strchr(options,'c')) {
00707 context->options |= ENUMLOOKUP_OPTIONS_COUNT;
00708 }
00709 if (strchr(number,'*')) {
00710 context->options |= ENUMLOOKUP_OPTIONS_ISN;
00711 }
00712 }
00713 ast_verb(2, "ENUM options(%s): pos=%d, options='%d'\n", options, context->position, context->options);
00714 ast_debug(1, "ast_get_enum(): n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
00715 number, tech, suffix, context->options, context->position);
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733 ast_copy_string(left, number, sizeof(left));
00734 middle[0] = '\0';
00735
00736
00737
00738 ast_copy_string(apex, suffix, sizeof(apex));
00739
00740 if ((context->options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
00741 *p1++ = '\0';
00742 ast_copy_string(left, number, sizeof(left));
00743 ast_copy_string(middle, p1, sizeof(middle) - 1);
00744 strcat(middle, ".");
00745
00746 ast_verb(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
00753 ast_verb(2, "DIRECT ENUM: middle='%s'\n", middle);
00754
00755 } else if (context->options & ENUMLOOKUP_OPTIONS_IENUM) {
00756 int sdl = 0;
00757 char cc[8];
00758 char sep[256], n_apex[256];
00759 int cc_len = cclen(number);
00760 sdl = cc_len;
00761 ast_mutex_lock(&enumlock);
00762 ast_copy_string(sep, ienum_branchlabel, sizeof(sep));
00763 ast_mutex_unlock(&enumlock);
00764
00765 switch (ebl_alg) {
00766 case ENUMLOOKUP_BLR_EBL:
00767 ast_copy_string(cc, number, cc_len);
00768 sdl = blr_ebl(cc, suffix, sep, sizeof(sep) - 1, n_apex, sizeof(n_apex) - 1);
00769
00770 if (sdl >= 0) {
00771 ast_copy_string(apex, n_apex, sizeof(apex));
00772 ast_verb(2, "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
00773 } else {
00774 sdl = cc_len;
00775 }
00776 break;
00777 case ENUMLOOKUP_BLR_TXT:
00778 ast_copy_string(cc, number, cc_len);
00779 sdl = blr_txt(cc, suffix);
00780
00781 if (sdl < 0)
00782 sdl = cc_len;
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_verb(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_verb(2, "ast_get_enum() 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 if (!argcontext) {
00906 for (k = 0; k < context->naptr_rrs_count; k++) {
00907 ast_free(context->naptr_rrs[k].result);
00908 ast_free(context->naptr_rrs[k].tech);
00909 }
00910 ast_free(context->naptr_rrs);
00911 ast_free(context);
00912 } else
00913 *argcontext = context;
00914
00915 return ret;
00916 }
00917
00918 int ast_get_txt(struct ast_channel *chan, const char *number, char *txt, int txtlen, char *suffix)
00919 {
00920 struct txt_context context;
00921 char tmp[259 + 512];
00922 int pos = strlen(number) - 1;
00923 int newpos = 0;
00924 int ret = -1;
00925
00926 ast_debug(4, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);
00927
00928 if (chan && ast_autoservice_start(chan) < 0) {
00929 return -1;
00930 }
00931
00932 if (pos > 128) {
00933 pos = 128;
00934 }
00935
00936 while (pos >= 0) {
00937 if (isdigit(number[pos])) {
00938 tmp[newpos++] = number[pos];
00939 tmp[newpos++] = '.';
00940 }
00941 pos--;
00942 }
00943
00944 ast_copy_string(&tmp[newpos], suffix, sizeof(tmp) - newpos);
00945
00946 if (ret < 0) {
00947 ast_debug(2, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno));
00948 ret = 0;
00949 } else {
00950 ast_copy_string(txt, context.txt, txtlen);
00951 }
00952 if (chan) {
00953 ret |= ast_autoservice_stop(chan);
00954 }
00955 return ret;
00956 }
00957
00958
00959 static int private_enum_init(int reload)
00960 {
00961 struct ast_config *cfg;
00962 const char *string;
00963 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00964
00965 if ((cfg = ast_config_load2("enum.conf", "enum", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
00966 return 0;
00967 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
00968 return 0;
00969 }
00970
00971
00972 ast_mutex_lock(&enumlock);
00973 if (cfg) {
00974 if ((string = ast_variable_retrieve(cfg, "ienum", "branchlabel"))) {
00975 ast_copy_string(ienum_branchlabel, string, sizeof(ienum_branchlabel));
00976 }
00977
00978 if ((string = ast_variable_retrieve(cfg, "ienum", "ebl_alg"))) {
00979 ebl_alg = ENUMLOOKUP_BLR_CC;
00980
00981 if (!strcasecmp(string, "txt"))
00982 ebl_alg = ENUMLOOKUP_BLR_TXT;
00983 else if (!strcasecmp(string, "ebl"))
00984 ebl_alg = ENUMLOOKUP_BLR_EBL;
00985 else if (!strcasecmp(string, "cc"))
00986 ebl_alg = ENUMLOOKUP_BLR_CC;
00987 else
00988 ast_log(LOG_WARNING, "No valid parameter for ienum/ebl_alg.\n");
00989 }
00990 ast_config_destroy(cfg);
00991 }
00992 ast_mutex_unlock(&enumlock);
00993 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Enum\r\nStatus: Enabled\r\nMessage: ENUM reload Requested\r\n");
00994 return 0;
00995 }
00996
00997 int ast_enum_init(void)
00998 {
00999 return private_enum_init(0);
01000 }
01001
01002 int ast_enum_reload(void)
01003 {
01004 return private_enum_init(1);
01005 }