00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <string.h>
00015 #include <fcntl.h>
00016 #include <unistd.h>
00017 #include <stdlib.h>
00018 #include <sys/types.h>
00019 #include <sys/socket.h>
00020 #include <netinet/in.h>
00021 #include <arpa/nameser.h>
00022 #include <resolv.h>
00023 #include <errno.h>
00024 #include <ctype.h>
00025 #include <regex.h>
00026
00027
00028 #include <asterisk/logger.h>
00029 #include <asterisk/options.h>
00030 #include <asterisk/enum.h>
00031 #include <asterisk/channel.h>
00032 #include <asterisk/config.h>
00033
00034 #define MAX_SIZE 4096
00035
00036 #define TOPLEV "e164.arpa."
00037
00038 typedef struct {
00039 unsigned id :16;
00040 #if BYTE_ORDER == BIG_ENDIAN
00041
00042 unsigned qr: 1;
00043 unsigned opcode: 4;
00044 unsigned aa: 1;
00045 unsigned tc: 1;
00046 unsigned rd: 1;
00047
00048 unsigned ra: 1;
00049 unsigned unused :1;
00050 unsigned ad: 1;
00051 unsigned cd: 1;
00052 unsigned rcode :4;
00053 #endif
00054 #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
00055
00056 unsigned rd :1;
00057 unsigned tc :1;
00058 unsigned aa :1;
00059 unsigned opcode :4;
00060 unsigned qr :1;
00061
00062 unsigned rcode :4;
00063 unsigned cd: 1;
00064 unsigned ad: 1;
00065 unsigned unused :1;
00066 unsigned ra :1;
00067 #endif
00068
00069 unsigned qdcount :16;
00070 unsigned ancount :16;
00071 unsigned nscount :16;
00072 unsigned arcount :16;
00073 } dns_HEADER;
00074
00075 static struct enum_search {
00076 char toplev[80];
00077 struct enum_search *next;
00078 } *toplevs;
00079
00080 static int enumver = 0;
00081
00082 static ast_mutex_t enumlock = AST_MUTEX_INITIALIZER;
00083
00084 static int skip_name(unsigned char *s, int len)
00085 {
00086
00087 int x = 0;
00088 while(x < len) {
00089 if (!*s) {
00090 s++;
00091 x++;
00092 break;
00093 }
00094 if (((*s) & 0xc0) == 0xc0) {
00095 s += 2;
00096 x += 2;
00097 break;
00098 }
00099 x += *s + 1;
00100 s += *s + 1;
00101 }
00102 if (x >= len)
00103 return -1;
00104 return x;
00105 }
00106
00107 struct dn_answer {
00108 unsigned short rtype;
00109 unsigned short class;
00110 unsigned int ttl;
00111 unsigned short size;
00112 } __attribute__ ((__packed__));
00113
00114 struct naptr {
00115 unsigned short order;
00116 unsigned short pref;
00117 } __attribute__ ((__packed__));
00118
00119 static int parse_ie(unsigned char *data, int maxdatalen, unsigned char *src, int srclen)
00120 {
00121 int len, olen;
00122 len = olen = (int)src[0];
00123 src++;
00124 srclen--;
00125 if (len > srclen) {
00126 ast_log(LOG_WARNING, "Want %d, got %d\n", len, srclen);
00127 return -1;
00128 }
00129 if (len > maxdatalen)
00130 len = maxdatalen;
00131 memcpy(data, src, len);
00132 return olen + 1;
00133 }
00134
00135 static int parse_naptr(unsigned char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, char *naptrinput)
00136 {
00137 unsigned char *oanswer = answer;
00138 unsigned char flags[80] = "";
00139 unsigned char services[80] = "";
00140 unsigned char regexp[80] = "";
00141 unsigned char repl[80] = "";
00142 unsigned char temp[80] = "";
00143 unsigned char delim;
00144 unsigned char *delim2;
00145 unsigned char *pattern, *subst, *d;
00146 int res;
00147 int regexp_len, size, backref;
00148 int d_len = sizeof(temp) - 1;
00149 regex_t preg;
00150 regmatch_t pmatch[9];
00151
00152
00153 if (len < sizeof(struct naptr)) {
00154 printf("Length too short\n");
00155 return -1;
00156 }
00157 answer += sizeof(struct naptr);
00158 len -= sizeof(struct naptr);
00159 if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) {
00160 ast_log(LOG_WARNING, "Failed to get flags\n");
00161 return -1;
00162 } else { answer += res; len -= res; }
00163 if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) {
00164 ast_log(LOG_WARNING, "Failed to get services\n");
00165 return -1;
00166 } else { answer += res; len -= res; }
00167 if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0)
00168 return -1; else { answer += res; len -= res; }
00169 if ((res = dn_expand(oanswer,answer + len,answer, repl, sizeof(repl) - 1)) < 0) {
00170 ast_log(LOG_WARNING, "Failed to expand hostname\n");
00171 return -1;
00172 }
00173
00174 #if 0
00175 printf("Input: %s\n", naptrinput);
00176 printf("Flags: %s\n", flags);
00177 printf("Services: %s\n", services);
00178 printf("Regexp: %s\n", regexp);
00179 printf("Repl: %s\n", repl);
00180 #endif
00181
00182 if (tolower(flags[0]) != 'u') {
00183 ast_log(LOG_WARNING, "Flag must be 'U' or 'u'.\n");
00184 return -1;
00185 }
00186
00187 if ((!strncasecmp(services, "e2u+sip", 7)) ||
00188 (!strncasecmp(services, "sip+e2u", 7))) {
00189 strncpy(tech, "sip", techsize -1);
00190 } else if ((!strncasecmp(services, "e2u+h323", 7)) ||
00191 (!strncasecmp(services, "h323+e2u", 7))) {
00192 strncpy(tech, "h323", techsize -1);
00193 } else if ((!strncasecmp(services, "e2u+iax", 7)) ||
00194 (!strncasecmp(services, "iax+e2u", 7))) {
00195 strncpy(tech, "iax", techsize -1);
00196 } else if ((!strncasecmp(services, "e2u+iax2", 7)) ||
00197 (!strncasecmp(services, "iax2+e2u", 7))) {
00198 strncpy(tech, "iax2", techsize -1);
00199 } else if ((!strncasecmp(services, "e2u+tel", 7)) ||
00200 (!strncasecmp(services, "tel+e2u", 7))) {
00201 strncpy(tech, "tel", techsize -1);
00202 } else if (strncasecmp(services, "e2u+voice:", 10)) {
00203 ast_log(LOG_WARNING, "Services must be e2u+sip, sip+e2u, e2u+h323, h323+e2u, e2u+iax, iax+e2u, e2u+iax2, iax2+e2u, e2u+tel, tel+e2u or e2u+voice:\n");
00204 return -1;
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 #if 0
00231 printf("Pattern: %s\n", pattern);
00232 printf("Subst: %s\n", subst);
00233 #endif
00234
00235
00236
00237
00238
00239 if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) {
00240 ast_log(LOG_WARNING, "Regex compilation error (regex = \"%s\").\n",regexp);
00241 return -1;
00242 }
00243
00244 if (preg.re_nsub > 9) {
00245 ast_log(LOG_WARNING, "Regex compilation error: too many subs.\n");
00246 regfree(&preg);
00247 return -1;
00248 }
00249
00250 if (regexec(&preg, naptrinput, 9, pmatch, 0)) {
00251 ast_log(LOG_WARNING, "Regex match failed.\n");
00252 regfree(&preg);
00253 return -1;
00254 }
00255 regfree(&preg);
00256
00257 d = temp; d_len--;
00258 while( *subst && (d_len > 0) ) {
00259 if ((subst[0] == '\\') && isdigit(subst[1]) && (pmatch[subst[1]-'0'].rm_so != -1)) {
00260 backref = subst[1]-'0';
00261 size = pmatch[backref].rm_eo - pmatch[backref].rm_so;
00262 if (size > d_len) {
00263 ast_log(LOG_WARNING, "Not enough space during regex substitution.\n");
00264 return -1;
00265 }
00266 memcpy(d, naptrinput + pmatch[backref].rm_so, size);
00267 d += size;
00268 d_len -= size;
00269 subst += 2;
00270 } else if (isprint(*subst)) {
00271 *d++ = *subst++;
00272 d_len--;
00273 } else {
00274 ast_log(LOG_WARNING, "Error during regex substitution.\n");
00275 return -1;
00276 }
00277 }
00278 *d = 0;
00279 strncpy(dst, temp, dstsize);
00280 d = strchr(services, ':');
00281 if (d)
00282 strncpy(tech, d+1, techsize -1);
00283 return 0;
00284 }
00285
00286 static int parse_answer(unsigned char *dst, int dstlen, unsigned char *tech, int techlen, unsigned char *answer, int len, char *naptrinput)
00287 {
00288
00289
00290
00291 int x;
00292 int res;
00293 dns_HEADER *h;
00294 struct dn_answer *ans;
00295 dst[0] = '\0';
00296 tech[0] = '\0';
00297 #if 0
00298 for (x=0;x<len;x++) {
00299 if ((answer[x] < 32) || (answer[x] > 127)) {
00300 if (lastlit)
00301 printf("\"");
00302 printf(" 0x%02x", answer[x]);
00303 lastlit = 0;
00304 } else {
00305 if (!lastlit)
00306 printf(" \"");
00307 printf("%c", answer[x]);
00308 lastlit = 1;
00309 }
00310 }
00311 printf("\n");
00312 #endif
00313 h = (dns_HEADER *)answer;
00314
00315 answer += sizeof(dns_HEADER);
00316 len -= sizeof(dns_HEADER);
00317 #if 0
00318 printf("Query count: %d\n", ntohs(h->qdcount));
00319 #endif
00320 for (x=0;x<ntohs(h->qdcount);x++) {
00321 if ((res = skip_name(answer, len)) < 0) {
00322 ast_log(LOG_WARNING, "Couldn't skip over name\n");
00323 return -1;
00324 }
00325 answer += res;
00326 len -= res;
00327 answer += 4;
00328 len -= 4;
00329 if (len < 0) {
00330 ast_log(LOG_WARNING, "Strange query size\n");
00331 return -1;
00332 }
00333 }
00334 #if 0
00335 printf("Length remaining: %d\n", len);
00336 printf("Answer count: %d\n", ntohs(h->ancount));
00337 printf("Looking for %d/%d\n", C_IN, T_NAPTR);
00338 #endif
00339 for (x=0;x<ntohs(h->ancount);x++) {
00340 if ((res = skip_name(answer, len)) < 0) {
00341 ast_log(LOG_WARNING, "Failed to skip name :(\n");
00342 return -1;
00343 }
00344 answer += res;
00345 len -= res;
00346 ans = (struct dn_answer *)answer;
00347 answer += sizeof(struct dn_answer);
00348 len -= sizeof(struct dn_answer);
00349 if (len < 0)
00350 return -1;
00351 #if 0
00352 printf("Type: %d, class: %d, ttl: %d, length: %d\n", ntohs(ans->rtype), ntohs(ans->class),
00353 ntohl(ans->ttl), ntohs(ans->size));
00354 #endif
00355 len -= ntohs(ans->size);
00356 if (len < 0) {
00357 ast_log(LOG_WARNING, "Length exceeds frame\n");
00358 return -1;
00359 }
00360 if ((ntohs(ans->class) == C_IN) && (ntohs(ans->rtype) == T_NAPTR)) {
00361 if (parse_naptr(dst, dstlen, tech, techlen, answer, ntohs(ans->size), naptrinput))
00362 ast_log(LOG_WARNING, "Failed to parse naptr :(\n");
00363 if (strlen(dst))
00364 return 0;
00365 }
00366 answer += ntohs(ans->size);
00367 }
00368 return 0;
00369 }
00370
00371 int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen)
00372 {
00373 unsigned char answer[MAX_SIZE];
00374 char tmp[259 + 80];
00375 char naptrinput[80] = "+";
00376 int pos = strlen(number) - 1;
00377 int newpos=0;
00378 int res = -1;
00379 int ret = -1;
00380 struct enum_search *s = NULL;
00381 int version = -1;
00382 struct __res_state enumstate;
00383 res_ninit(&enumstate);
00384 if (chan && ast_autoservice_start(chan) < 0)
00385 return -1;
00386
00387 strncat(naptrinput, number, sizeof(naptrinput) - 2);
00388
00389 if (pos > 128)
00390 pos = 128;
00391 while(pos >= 0) {
00392 tmp[newpos++] = number[pos--];
00393 tmp[newpos++] = '.';
00394 }
00395 #if 0
00396 printf("Looking for '%s'\n", tmp);
00397 #endif
00398
00399 for(;;) {
00400 ast_mutex_lock(&enumlock);
00401 if (version != enumver) {
00402
00403 s = toplevs;
00404 version = enumver;
00405 } else {
00406 s = s->next;
00407 }
00408 if (s) {
00409 strcpy(tmp + newpos, s->toplev);
00410 }
00411 ast_mutex_unlock(&enumlock);
00412 if (!s)
00413 break;
00414 res = res_nsearch(&enumstate, tmp, C_IN, T_NAPTR, answer, sizeof(answer));
00415 if (res > 0)
00416 break;
00417 }
00418 if (res > 0) {
00419 if ((res = parse_answer(dst, dstlen, tech, techlen, answer, res, naptrinput))) {
00420 ast_log(LOG_WARNING, "Parse error returned %d\n", res);
00421 ret = 0;
00422 } else {
00423 ast_log(LOG_DEBUG, "Found technology '%s', destination '%s'\n", tech, dst);
00424 ret = 1;
00425 }
00426 } else {
00427 ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno));
00428 ret = 0;
00429 }
00430 if (chan)
00431 ret |= ast_autoservice_stop(chan);
00432 res_nclose(&enumstate);
00433 return ret;
00434 }
00435
00436 static struct enum_search *enum_newtoplev(char *s)
00437 {
00438 struct enum_search *tmp;
00439 tmp = malloc(sizeof(struct enum_search));
00440 if (tmp) {
00441 memset(tmp, 0, sizeof(struct enum_search));
00442 strncpy(tmp->toplev, s, sizeof(tmp->toplev) - 1);
00443 }
00444 return tmp;
00445 }
00446
00447 int ast_enum_init(void)
00448 {
00449 struct ast_config *cfg;
00450 struct enum_search *s, *sl;
00451 struct ast_variable *v;
00452
00453
00454 ast_mutex_lock(&enumlock);
00455 s = toplevs;
00456 while(s) {
00457 sl = s;
00458 s = s->next;
00459 free(sl);
00460 }
00461 toplevs = NULL;
00462 cfg = ast_load("enum.conf");
00463 if (cfg) {
00464 sl = NULL;
00465 v = ast_variable_browse(cfg, "general");
00466 while(v) {
00467 if (!strcasecmp(v->name, "search")) {
00468 s = enum_newtoplev(v->value);
00469 if (s) {
00470 if (sl)
00471 sl->next = s;
00472 else
00473 toplevs = s;
00474 sl = s;
00475 }
00476 }
00477 v = v->next;
00478 }
00479 ast_destroy(cfg);
00480 } else {
00481 toplevs = enum_newtoplev(TOPLEV);
00482 }
00483 enumver++;
00484 ast_mutex_unlock(&enumlock);
00485 return 0;
00486 }
00487
00488 int ast_enum_reload(void)
00489 {
00490 return ast_enum_init();
00491 }