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