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