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 #include "asterisk.h"
00044
00045 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 180532 $")
00046
00047 #include <sys/types.h>
00048 #include <sys/socket.h>
00049 #include <netinet/in.h>
00050 #include <arpa/nameser.h>
00051 #if __APPLE_CC__ >= 1495
00052 #include <arpa/nameser_compat.h>
00053 #endif
00054 #include <resolv.h>
00055 #include <stdlib.h>
00056 #include <string.h>
00057 #include <ctype.h>
00058 #include <regex.h>
00059 #include <unistd.h>
00060 #include <errno.h>
00061
00062 #include "asterisk/logger.h"
00063 #include "asterisk/options.h"
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
00070 #ifdef __APPLE__
00071 #undef T_NAPTR
00072 #define T_NAPTR 35
00073 #endif
00074
00075 #ifdef __APPLE__
00076 #undef T_TXT
00077 #define T_TXT 16
00078 #endif
00079
00080 #define TOPLEV "e164.arpa."
00081
00082
00083 static struct enum_search {
00084 char toplev[512];
00085 struct enum_search *next;
00086 } *toplevs;
00087
00088 static int enumver;
00089
00090 AST_MUTEX_DEFINE_STATIC(enumlock);
00091
00092 struct naptr {
00093 unsigned short order;
00094 unsigned short pref;
00095 } __attribute__((__packed__));
00096
00097
00098 static unsigned int parse_ie(char *data, unsigned int maxdatalen, unsigned char *src, unsigned int srclen)
00099 {
00100 unsigned int len, olen;
00101
00102 len = olen = (unsigned int) src[0];
00103 src++;
00104 srclen--;
00105
00106 if (len > srclen) {
00107 ast_log(LOG_WARNING, "ENUM parsing failed: Wanted %d characters, got %d\n", len, srclen);
00108 return -1;
00109 }
00110
00111 if (len > maxdatalen)
00112 len = maxdatalen;
00113 memcpy(data, src, len);
00114
00115 return olen + 1;
00116 }
00117
00118
00119 static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, char *naptrinput)
00120 {
00121 char tech_return[80];
00122 unsigned char *oanswer = answer;
00123 char flags[512] = "";
00124 char services[512] = "";
00125 char *p;
00126 char regexp[512] = "";
00127 char repl[512] = "";
00128 char tempdst[512] = "";
00129 char errbuff[512] = "";
00130 char delim;
00131 char *delim2;
00132 char *pattern, *subst, *d;
00133 int res;
00134 int regexp_len, rc;
00135 int size, matchindex;
00136 int d_len = sizeof(tempdst) - 1;
00137 static const int max_bt = 10;
00138 regex_t preg;
00139 regmatch_t pmatch[max_bt];
00140
00141 tech_return[0] = '\0';
00142
00143 dst[0] = '\0';
00144
00145 if (len < sizeof(struct naptr)) {
00146 ast_log(LOG_WARNING, "NAPTR record length too short\n");
00147 return -1;
00148 }
00149 answer += sizeof(struct naptr);
00150 len -= sizeof(struct naptr);
00151 if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) {
00152 ast_log(LOG_WARNING, "Failed to get flags from NAPTR record\n");
00153 return -1;
00154 } else {
00155 answer += res;
00156 len -= res;
00157 }
00158 if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) {
00159 ast_log(LOG_WARNING, "Failed to get services from NAPTR record\n");
00160 return -1;
00161 } else {
00162 answer += res;
00163 len -= res;
00164 }
00165 if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0) {
00166 ast_log(LOG_WARNING, "Failed to get regexp from NAPTR record\n");
00167 return -1;
00168 } else {
00169 answer += res;
00170 len -= res;
00171 }
00172
00173 if ((res = dn_expand(oanswer, answer + len, answer, repl, sizeof(repl) - 1)) < 0) {
00174 ast_log(LOG_WARNING, "Failed to expand hostname\n");
00175 return -1;
00176 }
00177
00178 if (option_debug > 2)
00179 ast_log(LOG_DEBUG, "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
00180 naptrinput, flags, services, regexp, repl);
00181
00182 if (tolower(flags[0]) != 'u') {
00183 ast_log(LOG_WARNING, "NAPTR Flag must be 'U' or 'u'.\n");
00184 return -1;
00185 }
00186
00187 p = strstr(services, "e2u+");
00188 if (p == NULL)
00189 p = strstr(services, "E2U+");
00190 if (p){
00191 p = p + 4;
00192 if (strchr(p, ':')){
00193 p = strchr(p, ':') + 1;
00194 }
00195 ast_copy_string(tech_return, p, sizeof(tech_return));
00196 } else {
00197
00198 p = strstr(services, "+e2u");
00199 if (p == NULL)
00200 p = strstr(services, "+E2U");
00201 if (p) {
00202 *p = 0;
00203 p = strchr(services, ':');
00204 if (p)
00205 *p = 0;
00206 ast_copy_string(tech_return, services, sizeof(tech_return));
00207 }
00208 }
00209
00210 regexp_len = strlen(regexp);
00211 if (regexp_len < 7) {
00212 ast_log(LOG_WARNING, "Regex too short to be meaningful.\n");
00213 return -1;
00214 }
00215
00216
00217
00218 delim = regexp[0];
00219 delim2 = strchr(regexp + 1, delim);
00220 if ((delim2 == NULL) || (regexp[regexp_len - 1] != delim)) {
00221 ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n", regexp);
00222 return -1;
00223 } else if (strchr((delim2 + 1), delim) == NULL) {
00224 ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n", regexp);
00225 return -1;
00226 }
00227 pattern = regexp + 1;
00228 *delim2 = 0;
00229 subst = delim2 + 1;
00230 regexp[regexp_len - 1] = 0;
00231
00232
00233
00234
00235
00236 if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) {
00237 ast_log(LOG_WARNING, "NAPTR Regex compilation error (regex = \"%s\").\n", regexp);
00238 return -1;
00239 }
00240
00241 if (preg.re_nsub > ARRAY_LEN(pmatch)) {
00242 ast_log(LOG_WARNING, "NAPTR Regex compilation error: too many subs.\n");
00243 regfree(&preg);
00244 return -1;
00245 }
00246
00247
00248 if ((rc = regexec(&preg, (char *) naptrinput, max_bt, pmatch, 0))) {
00249 regerror(rc, &preg, errbuff, sizeof(errbuff));
00250 ast_log(LOG_WARNING, "NAPTR Regex match failed. Reason: %s\n", errbuff);
00251 regfree(&preg);
00252 return -1;
00253 }
00254 regfree(&preg);
00255
00256 d = tempdst;
00257 d_len--;
00258
00259
00260
00261
00262
00263
00264 while (*subst && (d_len > 0)) {
00265 if ((subst[0] == '\\') && isdigit(subst[1])) {
00266 matchindex = (int) (subst[1] - '0');
00267 if (matchindex >= ARRAY_LEN(pmatch)) {
00268 ast_log(LOG_WARNING, "Error during regex substitution. Invalid pmatch index.\n");
00269 return -1;
00270 }
00271
00272 size = pmatch[matchindex].rm_eo - pmatch[matchindex].rm_so;
00273 if (size > d_len) {
00274 ast_log(LOG_WARNING, "Not enough space during NAPTR regex substitution.\n");
00275 return -1;
00276 }
00277
00278 if ((strlen((char *) naptrinput) >= pmatch[matchindex].rm_eo) && (pmatch[matchindex].rm_so <= pmatch[matchindex].rm_eo)) {
00279 memcpy(d, (naptrinput + (int) pmatch[matchindex].rm_so), size);
00280 d_len -= size;
00281 subst += 2;
00282 d += size;
00283 } else {
00284 ast_log(LOG_WARNING, "Error during regex substitution. Invalid backreference index.\n");
00285 return -1;
00286 }
00287 } else if (isprint(*subst)) {
00288 *d++ = *subst++;
00289 d_len--;
00290 } else {
00291 ast_log(LOG_WARNING, "Error during regex substitution.\n");
00292 return -1;
00293 }
00294 }
00295 *d = 0;
00296 ast_copy_string((char *) dst, tempdst, dstsize);
00297 dst[dstsize - 1] = '\0';
00298 if (*tech != '\0'){
00299 if (!strncasecmp(tech, "ALL", techsize)){
00300 return 1;
00301 }
00302 if (!strncasecmp(tech_return, tech, sizeof(tech_return)<techsize?sizeof(tech_return):techsize)){
00303 ast_copy_string(tech, tech_return, techsize);
00304 return 1;
00305 } else {
00306 return 0;
00307 }
00308 }
00309
00310
00311 ast_copy_string(tech, tech_return, techsize);
00312 return 1;
00313 }
00314
00315
00316 #define ENUMLOOKUP_OPTIONS_COUNT 1
00317
00318 struct enum_naptr_rr {
00319 struct naptr naptr;
00320 char *result;
00321 char *tech;
00322 int sort_pos;
00323 };
00324
00325 struct enum_context {
00326 char *dst;
00327 int dstlen;
00328 char *tech;
00329 int techlen;
00330 char *txt;
00331 int txtlen;
00332 char *naptrinput;
00333 int position;
00334 int options;
00335 struct enum_naptr_rr *naptr_rrs;
00336 int naptr_rrs_count;
00337 };
00338
00339
00340 static int txt_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
00341 {
00342 struct enum_context *c = (struct enum_context *)context;
00343
00344 if (answer == NULL) {
00345 c->txt = NULL;
00346 c->txtlen = 0;
00347 return 0;
00348 }
00349
00350
00351 answer += 1;
00352 len -= 1;
00353
00354
00355
00356
00357 answer[len] = '\0';
00358
00359
00360 len +=1;
00361
00362
00363 ast_copy_string(c->txt, (const char *) answer, len < c->txtlen ? len : (c->txtlen));
00364
00365
00366 c->txt[(c->txtlen)-1] = '\0';
00367
00368 return 1;
00369 }
00370
00371
00372 static int enum_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
00373 {
00374 struct enum_context *c = context;
00375 void *p = NULL;
00376 int res;
00377
00378 res = parse_naptr(c->dst, c->dstlen, c->tech, c->techlen, answer, len, c->naptrinput);
00379
00380 if (res < 0) {
00381 ast_log(LOG_WARNING, "Failed to parse naptr :(\n");
00382 return -1;
00383 } else if (res > 0 && !ast_strlen_zero(c->dst)){
00384 if (c->options & ENUMLOOKUP_OPTIONS_COUNT){
00385 c->position++;
00386 snprintf(c->dst, c->dstlen, "%d", c->position);
00387 } else {
00388 if ((p = ast_realloc(c->naptr_rrs, sizeof(*c->naptr_rrs) * (c->naptr_rrs_count + 1)))) {
00389 c->naptr_rrs = p;
00390 memcpy(&c->naptr_rrs[c->naptr_rrs_count].naptr, answer, sizeof(c->naptr_rrs->naptr));
00391 c->naptr_rrs[c->naptr_rrs_count].result = strdup(c->dst);
00392 c->naptr_rrs[c->naptr_rrs_count].tech = strdup(c->tech);
00393 c->naptr_rrs[c->naptr_rrs_count].sort_pos = c->naptr_rrs_count;
00394 c->naptr_rrs_count++;
00395 }
00396 c->dst[0] = 0;
00397 }
00398 return 0;
00399 }
00400
00401 if (c->options & ENUMLOOKUP_OPTIONS_COUNT) {
00402 snprintf(c->dst, c->dstlen, "%d", c->position);
00403 }
00404
00405 return 0;
00406 }
00407
00408
00409 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)
00410 {
00411 struct enum_context context;
00412 char tmp[259 + 512];
00413 char naptrinput[512];
00414 int pos = strlen(number) - 1;
00415 int newpos = 0;
00416 int ret = -1;
00417 struct enum_search *s = NULL;
00418 int version = -1;
00419
00420 char *p1 = NULL;
00421 char *p2 = NULL;
00422 int k = 0;
00423 int i = 0;
00424 int z = 0;
00425
00426 ast_copy_string(naptrinput, number[0] == 'n' ? number+1 : number, sizeof(naptrinput));
00427
00428 context.naptrinput = naptrinput;
00429 context.dst = dst;
00430 context.dstlen = dstlen;
00431 context.tech = tech;
00432 context.techlen = techlen;
00433 context.options = 0;
00434 context.position = record > 0 ? record : 1;
00435 context.naptr_rrs = NULL;
00436 context.naptr_rrs_count = 0;
00437
00438 if (options != NULL) {
00439 if (*options == 'c') {
00440 context.options = ENUMLOOKUP_OPTIONS_COUNT;
00441 context.position = 0;
00442 }
00443 }
00444
00445 ast_log(LOG_DEBUG, "ast_get_enum(): n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
00446 number, tech, suffix, context.options, context.position);
00447
00448 if (pos > 128)
00449 pos = 128;
00450
00451
00452 p1 = strchr(number, '*');
00453
00454 if (number[0] == 'n') {
00455 p1 = NULL;
00456 k = 1;
00457 }
00458
00459 if (p1 != NULL) {
00460 p2 = p1+1;
00461 while (p1 > number){
00462 p1--;
00463 tmp[newpos++] = *p1;
00464 tmp[newpos++] = '.';
00465 }
00466 if (*p2) {
00467 while(*p2 && newpos < 128){
00468 tmp[newpos++] = *p2;
00469 p2++;
00470 }
00471 tmp[newpos++] = '.';
00472 }
00473
00474 } else {
00475 while (pos >= k) {
00476 if (isdigit(number[pos])) {
00477 tmp[newpos++] = number[pos];
00478 tmp[newpos++] = '.';
00479 }
00480 pos--;
00481 }
00482 }
00483
00484 if (chan && ast_autoservice_start(chan) < 0)
00485 return -1;
00486
00487 if(suffix) {
00488 ast_copy_string(tmp + newpos, suffix, sizeof(tmp) - newpos);
00489 ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
00490 ast_log(LOG_DEBUG, "ast_get_enum: ast_search_dns(%s) returned %d\n", tmp, ret);
00491 } else {
00492 ret = -1;
00493 for (;;) {
00494 ast_mutex_lock(&enumlock);
00495 if (version != enumver) {
00496
00497 s = toplevs;
00498 version = enumver;
00499 } else {
00500 s = s->next;
00501 }
00502 ast_mutex_unlock(&enumlock);
00503
00504 if (!s)
00505 break;
00506
00507 ast_copy_string(tmp + newpos, s->toplev, sizeof(tmp) - newpos);
00508 ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
00509 ast_log(LOG_DEBUG, "ast_get_enum: ast_search_dns(%s) returned %d\n", tmp, ret);
00510 if (ret > 0)
00511 break;
00512 }
00513 }
00514
00515 if (ret < 0) {
00516 ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno));
00517 strcpy(dst, "0");
00518 ret = 0;
00519 }
00520
00521 if (context.naptr_rrs_count >= context.position && ! (context.options & ENUMLOOKUP_OPTIONS_COUNT)) {
00522
00523 for (k = 0; k < context.naptr_rrs_count; k++) {
00524 for (i = 0; i < context.naptr_rrs_count; i++) {
00525
00526 if ((ntohs(context.naptr_rrs[k].naptr.order) < ntohs(context.naptr_rrs[i].naptr.order)
00527 && context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos)
00528 || (ntohs(context.naptr_rrs[k].naptr.order) > ntohs(context.naptr_rrs[i].naptr.order)
00529 && context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)){
00530 z = context.naptr_rrs[k].sort_pos;
00531 context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos;
00532 context.naptr_rrs[i].sort_pos = z;
00533 continue;
00534 }
00535 if (ntohs(context.naptr_rrs[k].naptr.order) == ntohs(context.naptr_rrs[i].naptr.order)) {
00536 if ((ntohs(context.naptr_rrs[k].naptr.pref) < ntohs(context.naptr_rrs[i].naptr.pref)
00537 && context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos)
00538 || (ntohs(context.naptr_rrs[k].naptr.pref) > ntohs(context.naptr_rrs[i].naptr.pref)
00539 && context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)){
00540 z = context.naptr_rrs[k].sort_pos;
00541 context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos;
00542 context.naptr_rrs[i].sort_pos = z;
00543 }
00544 }
00545 }
00546 }
00547 for (k = 0; k < context.naptr_rrs_count; k++) {
00548 if (context.naptr_rrs[k].sort_pos == context.position-1) {
00549 ast_copy_string(context.dst, context.naptr_rrs[k].result, dstlen);
00550 ast_copy_string(context.tech, context.naptr_rrs[k].tech, techlen);
00551 break;
00552 }
00553 }
00554 } else if (!(context.options & ENUMLOOKUP_OPTIONS_COUNT)) {
00555 context.dst[0] = 0;
00556 }
00557 if (chan)
00558 ret |= ast_autoservice_stop(chan);
00559
00560 for (k = 0; k < context.naptr_rrs_count; k++) {
00561 free(context.naptr_rrs[k].result);
00562 free(context.naptr_rrs[k].tech);
00563 }
00564
00565 free(context.naptr_rrs);
00566
00567 return ret;
00568 }
00569
00570
00571
00572
00573 int ast_get_txt(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char *txt, int txtlen)
00574 {
00575 struct enum_context context;
00576 char tmp[259 + 512];
00577 char naptrinput[512] = "+";
00578 int pos = strlen(number) - 1;
00579 int newpos = 0;
00580 int ret = -1;
00581 struct enum_search *s = NULL;
00582 int version = -1;
00583
00584 strncat(naptrinput, number, sizeof(naptrinput) - 2);
00585
00586 context.naptrinput = naptrinput;
00587 context.dst = dst;
00588 context.dstlen = dstlen;
00589 context.tech = tech;
00590 context.techlen = techlen;
00591 context.txt = txt;
00592 context.txtlen = txtlen;
00593
00594 if (pos > 128)
00595 pos = 128;
00596 while (pos >= 0) {
00597 tmp[newpos++] = number[pos--];
00598 tmp[newpos++] = '.';
00599 }
00600
00601 if (chan && ast_autoservice_start(chan) < 0)
00602 return -1;
00603
00604 for (;;) {
00605 ast_mutex_lock(&enumlock);
00606 if (version != enumver) {
00607
00608 s = toplevs;
00609 version = enumver;
00610 } else {
00611 s = s->next;
00612 }
00613 if (s) {
00614 ast_copy_string(tmp + newpos, s->toplev, sizeof(tmp) - newpos);
00615 }
00616 ast_mutex_unlock(&enumlock);
00617 if (!s)
00618 break;
00619
00620 ret = ast_search_dns(&context, tmp, C_IN, T_TXT, txt_callback);
00621 if (ret > 0)
00622 break;
00623 }
00624 if (ret < 0) {
00625 if (option_debug > 1)
00626 ast_log(LOG_DEBUG, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno));
00627 ret = 0;
00628 }
00629 if (chan)
00630 ret |= ast_autoservice_stop(chan);
00631 return ret;
00632 }
00633
00634
00635 static struct enum_search *enum_newtoplev(char *s)
00636 {
00637 struct enum_search *tmp;
00638
00639 if ((tmp = ast_calloc(1, sizeof(*tmp)))) {
00640 ast_copy_string(tmp->toplev, s, sizeof(tmp->toplev));
00641 }
00642 return tmp;
00643 }
00644
00645
00646 int ast_enum_init(void)
00647 {
00648 struct ast_config *cfg;
00649 struct enum_search *s, *sl;
00650 struct ast_variable *v;
00651
00652
00653 ast_mutex_lock(&enumlock);
00654 s = toplevs;
00655 while(s) {
00656 sl = s;
00657 s = s->next;
00658 free(sl);
00659 }
00660 toplevs = NULL;
00661 cfg = ast_config_load("enum.conf");
00662 if (cfg) {
00663 sl = NULL;
00664 v = ast_variable_browse(cfg, "general");
00665 while(v) {
00666 if (!strcasecmp(v->name, "search")) {
00667 s = enum_newtoplev(v->value);
00668 if (s) {
00669 if (sl)
00670 sl->next = s;
00671 else
00672 toplevs = s;
00673 sl = s;
00674 }
00675 }
00676 v = v->next;
00677 }
00678 ast_config_destroy(cfg);
00679 } else {
00680 toplevs = enum_newtoplev(TOPLEV);
00681 }
00682 enumver++;
00683 ast_mutex_unlock(&enumlock);
00684 return 0;
00685 }
00686
00687 int ast_enum_reload(void)
00688 {
00689 return ast_enum_init();
00690 }