Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

enum.c

Go to the documentation of this file.
00001 /* 00002 * ENUM Support for Asterisk 00003 * 00004 * Copyright (C) 2003 Digium 00005 * 00006 * Written by Mark Spencer <markster@digium.com> 00007 * 00008 * Funding provided by nic.at 00009 * 00010 * Distributed under the terms of the GNU GPL 00011 * 00012 */ 00013 00014 #include <sys/types.h> 00015 #include <sys/socket.h> 00016 #include <netinet/in.h> 00017 #include <arpa/nameser.h> 00018 #if __APPLE_CC__ >= 1495 00019 #include <arpa/nameser_compat.h> 00020 #endif 00021 #include <resolv.h> 00022 #include <stdlib.h> 00023 #include <string.h> 00024 #include <ctype.h> 00025 #include <regex.h> 00026 #include <unistd.h> 00027 #include <errno.h> 00028 00029 #include <asterisk/logger.h> 00030 #include <asterisk/options.h> 00031 #include <asterisk/enum.h> 00032 #include <asterisk/dns.h> 00033 #include <asterisk/channel.h> 00034 #include <asterisk/config.h> 00035 #include <asterisk/utils.h> 00036 00037 #ifdef __APPLE__ 00038 #undef T_NAPTR 00039 #define T_NAPTR 35 00040 #endif 00041 00042 #ifdef __APPLE__ 00043 #undef T_TXT 00044 #define T_TXT 16 00045 #endif 00046 00047 #define TOPLEV "e164.arpa." 00048 00049 static struct enum_search { 00050 char toplev[80]; 00051 struct enum_search *next; 00052 } *toplevs; 00053 00054 static int enumver = 0; 00055 00056 AST_MUTEX_DEFINE_STATIC(enumlock); 00057 00058 struct naptr { 00059 unsigned short order; 00060 unsigned short pref; 00061 } __attribute__ ((__packed__)); 00062 00063 static int parse_ie(unsigned char *data, int maxdatalen, unsigned char *src, int srclen) 00064 { 00065 int len, olen; 00066 len = olen = (int)src[0]; 00067 src++; 00068 srclen--; 00069 if (len > srclen) { 00070 ast_log(LOG_WARNING, "Want %d, got %d\n", len, srclen); 00071 return -1; 00072 } 00073 if (len > maxdatalen) 00074 len = maxdatalen; 00075 memcpy(data, src, len); 00076 return olen + 1; 00077 } 00078 00079 static int parse_naptr(unsigned char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, char *naptrinput) 00080 { 00081 unsigned char *oanswer = answer; 00082 unsigned char flags[80] = ""; 00083 unsigned char services[80] = ""; 00084 unsigned char regexp[80] = ""; 00085 unsigned char repl[80] = ""; 00086 unsigned char temp[80] = ""; 00087 unsigned char delim; 00088 unsigned char *delim2; 00089 unsigned char *pattern, *subst, *d; 00090 int res; 00091 int regexp_len, size, backref; 00092 int d_len = sizeof(temp) - 1; 00093 regex_t preg; 00094 regmatch_t pmatch[9]; 00095 00096 00097 strcpy(dst, ""); 00098 00099 if (len < sizeof(struct naptr)) { 00100 ast_log(LOG_WARNING, "Length too short\n"); 00101 return -1; 00102 } 00103 answer += sizeof(struct naptr); 00104 len -= sizeof(struct naptr); 00105 if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) { 00106 ast_log(LOG_WARNING, "Failed to get flags\n"); 00107 return -1; 00108 } else { answer += res; len -= res; } 00109 if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) { 00110 ast_log(LOG_WARNING, "Failed to get services\n"); 00111 return -1; 00112 } else { answer += res; len -= res; } 00113 if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0) 00114 return -1; else { answer += res; len -= res; } 00115 if ((res = dn_expand(oanswer,answer + len,answer, repl, sizeof(repl) - 1)) < 0) { 00116 ast_log(LOG_WARNING, "Failed to expand hostname\n"); 00117 return -1; 00118 } 00119 00120 ast_log(LOG_DEBUG, "input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n", 00121 naptrinput, flags, services, regexp, repl); 00122 00123 if (tolower(flags[0]) != 'u') { 00124 ast_log(LOG_WARNING, "Flag must be 'U' or 'u'.\n"); 00125 return -1; 00126 } 00127 00128 if ((!strncasecmp(services, "e2u+sip", 7)) || 00129 (!strncasecmp(services, "sip+e2u", 7))) { 00130 strncpy(tech, "sip", techsize -1); 00131 } else if ((!strncasecmp(services, "e2u+h323", 8)) || 00132 (!strncasecmp(services, "h323+e2u", 8))) { 00133 strncpy(tech, "h323", techsize -1); 00134 } else if ((!strncasecmp(services, "e2u+x-iax2", 10)) || 00135 (!strncasecmp(services, "e2u+iax2", 8)) || 00136 (!strncasecmp(services, "iax2+e2u", 8))) { 00137 strncpy(tech, "iax2", techsize -1); 00138 } else if ((!strncasecmp(services, "e2u+x-iax", 9)) || 00139 (!strncasecmp(services, "e2u+iax", 7)) || 00140 (!strncasecmp(services, "iax+e2u", 7))) { 00141 strncpy(tech, "iax", techsize -1); 00142 } else if ((!strncasecmp(services, "e2u+tel", 7)) || 00143 (!strncasecmp(services, "tel+e2u", 7))) { 00144 strncpy(tech, "tel", techsize -1); 00145 } else if (!strncasecmp(services, "e2u+voice:", 10)) { 00146 strncpy(tech, services+10, techsize -1); 00147 } else { 00148 ast_log(LOG_DEBUG, 00149 "Services must be e2u+${tech}, ${tech}+e2u, or e2u+voice: where $tech is from (sip, h323, tel, iax, iax2). \n"); 00150 return 0; 00151 } 00152 00153 /* DEDBUGGING STUB 00154 strcpy(regexp, "!^\\+43(.*)$!\\1@bla.fasel!"); 00155 */ 00156 00157 regexp_len = strlen(regexp); 00158 if (regexp_len < 7) { 00159 ast_log(LOG_WARNING, "Regex too short to be meaningful.\n"); 00160 return -1; 00161 } 00162 00163 00164 delim = regexp[0]; 00165 delim2 = strchr(regexp + 1, delim); 00166 if ((delim2 == NULL) || (regexp[regexp_len-1] != delim)) { 00167 ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n",regexp); 00168 return -1; 00169 } 00170 00171 pattern = regexp + 1; 00172 *delim2 = 0; 00173 subst = delim2 + 1; 00174 regexp[regexp_len-1] = 0; 00175 00176 #if 0 00177 printf("Pattern: %s\n", pattern); 00178 printf("Subst: %s\n", subst); 00179 #endif 00180 00181 /* 00182 * now do the regex wizardry. 00183 */ 00184 00185 if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) { 00186 ast_log(LOG_WARNING, "Regex compilation error (regex = \"%s\").\n",regexp); 00187 return -1; 00188 } 00189 00190 if (preg.re_nsub > 9) { 00191 ast_log(LOG_WARNING, "Regex compilation error: too many subs.\n"); 00192 regfree(&preg); 00193 return -1; 00194 } 00195 00196 if (regexec(&preg, naptrinput, 9, pmatch, 0)) { 00197 ast_log(LOG_WARNING, "Regex match failed.\n"); 00198 regfree(&preg); 00199 return -1; 00200 } 00201 regfree(&preg); 00202 00203 d = temp; d_len--; 00204 while( *subst && (d_len > 0) ) { 00205 if ((subst[0] == '\\') && isdigit(subst[1]) && (pmatch[subst[1]-'0'].rm_so != -1)) { 00206 backref = subst[1]-'0'; 00207 size = pmatch[backref].rm_eo - pmatch[backref].rm_so; 00208 if (size > d_len) { 00209 ast_log(LOG_WARNING, "Not enough space during regex substitution.\n"); 00210 return -1; 00211 } 00212 memcpy(d, naptrinput + pmatch[backref].rm_so, size); 00213 d += size; 00214 d_len -= size; 00215 subst += 2; 00216 } else if (isprint(*subst)) { 00217 *d++ = *subst++; 00218 d_len--; 00219 } else { 00220 ast_log(LOG_WARNING, "Error during regex substitution.\n"); 00221 return -1; 00222 } 00223 } 00224 *d = 0; 00225 strncpy(dst, temp, dstsize); 00226 return 0; 00227 } 00228 00229 struct enum_context { 00230 char *dst; 00231 int dstlen; 00232 char *tech; 00233 int techlen; 00234 char *txt; 00235 int txtlen; 00236 char *naptrinput; 00237 }; 00238 00239 static int txt_callback(void *context, u_char *answer, int len, u_char *fullanswer) 00240 { 00241 struct enum_context *c = (struct enum_context *)context; 00242 #if 0 00243 printf("ENUMTXT Called\n"); 00244 #endif 00245 00246 if(answer != NULL) 00247 { 00248 c->txtlen = strlen(answer) - 2; 00249 strncpy(c->txt, answer, 255); 00250 c->txt[c->txtlen] = 0; 00251 return 1; 00252 } else { 00253 c->txt = NULL; 00254 c->txtlen = 0; 00255 return 0; 00256 } 00257 } 00258 00259 static int enum_callback(void *context, u_char *answer, int len, u_char *fullanswer) 00260 { 00261 struct enum_context *c = (struct enum_context *)context; 00262 00263 if (parse_naptr(c->dst, c->dstlen, c->tech, c->techlen, answer, len, c->naptrinput)) { 00264 ast_log(LOG_WARNING, "Failed to parse naptr :(\n"); 00265 return -1; 00266 } 00267 00268 if (!ast_strlen_zero(c->dst)) 00269 return 1; 00270 00271 return 0; 00272 } 00273 00274 int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen) 00275 { 00276 struct enum_context context; 00277 char tmp[259 + 80]; 00278 char naptrinput[80] = "+"; 00279 int pos = strlen(number) - 1; 00280 int newpos = 0; 00281 int ret = -1; 00282 struct enum_search *s = NULL; 00283 int version = -1; 00284 00285 strncat(naptrinput, number, sizeof(naptrinput) - 2); 00286 00287 context.naptrinput = naptrinput; 00288 context.dst = dst; 00289 context.dstlen = dstlen; 00290 context.tech = tech; 00291 context.techlen = techlen; 00292 00293 if (pos > 128) 00294 pos = 128; 00295 while(pos >= 0) { 00296 tmp[newpos++] = number[pos--]; 00297 tmp[newpos++] = '.'; 00298 } 00299 00300 if (chan && ast_autoservice_start(chan) < 0) 00301 return -1; 00302 00303 for(;;) { 00304 ast_mutex_lock(&enumlock); 00305 if (version != enumver) { 00306 /* Ooh, a reload... */ 00307 s = toplevs; 00308 version = enumver; 00309 } else { 00310 s = s->next; 00311 } 00312 if (s) { 00313 strcpy(tmp + newpos, s->toplev); 00314 } 00315 ast_mutex_unlock(&enumlock); 00316 if (!s) 00317 break; 00318 ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback); 00319 if (ret > 0) 00320 break; 00321 } 00322 if (ret < 0) { 00323 ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno)); 00324 ret = 0; 00325 } 00326 if (chan) 00327 ret |= ast_autoservice_stop(chan); 00328 return ret; 00329 } 00330 00331 int ast_get_txt(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char *txt, int txtlen) 00332 { 00333 struct enum_context context; 00334 char tmp[259 + 80]; 00335 char naptrinput[80] = "+"; 00336 int pos = strlen(number) - 1; 00337 int newpos = 0; 00338 int ret = -1; 00339 struct enum_search *s = NULL; 00340 int version = -1; 00341 00342 strncat(naptrinput, number, sizeof(naptrinput) - 2); 00343 00344 context.naptrinput = naptrinput; 00345 context.dst = dst; 00346 context.dstlen = dstlen; 00347 context.tech = tech; 00348 context.techlen = techlen; 00349 context.txt = txt; 00350 context.txtlen = txtlen; 00351 00352 if (pos > 128) 00353 pos = 128; 00354 while(pos >= 0) { 00355 tmp[newpos++] = number[pos--]; 00356 tmp[newpos++] = '.'; 00357 } 00358 00359 if (chan && ast_autoservice_start(chan) < 0) 00360 return -1; 00361 00362 for(;;) { 00363 ast_mutex_lock(&enumlock); 00364 if (version != enumver) { 00365 /* Ooh, a reload... */ 00366 s = toplevs; 00367 version = enumver; 00368 } else { 00369 s = s->next; 00370 } 00371 if (s) { 00372 strcpy(tmp + newpos, s->toplev); 00373 } 00374 ast_mutex_unlock(&enumlock); 00375 if (!s) 00376 break; 00377 ret = ast_search_dns(&context, tmp, C_IN, T_TXT, txt_callback); 00378 if (ret > 0) 00379 break; 00380 } 00381 if (ret < 0) { 00382 ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno)); 00383 ret = 0; 00384 } 00385 if (chan) 00386 ret |= ast_autoservice_stop(chan); 00387 return ret; 00388 } 00389 00390 static struct enum_search *enum_newtoplev(char *s) 00391 { 00392 struct enum_search *tmp; 00393 tmp = malloc(sizeof(struct enum_search)); 00394 if (tmp) { 00395 memset(tmp, 0, sizeof(struct enum_search)); 00396 strncpy(tmp->toplev, s, sizeof(tmp->toplev) - 1); 00397 } 00398 return tmp; 00399 } 00400 00401 int ast_enum_init(void) 00402 { 00403 struct ast_config *cfg; 00404 struct enum_search *s, *sl; 00405 struct ast_variable *v; 00406 00407 /* Destroy existing list */ 00408 ast_mutex_lock(&enumlock); 00409 s = toplevs; 00410 while(s) { 00411 sl = s; 00412 s = s->next; 00413 free(sl); 00414 } 00415 toplevs = NULL; 00416 cfg = ast_load("enum.conf"); 00417 if (cfg) { 00418 sl = NULL; 00419 v = ast_variable_browse(cfg, "general"); 00420 while(v) { 00421 if (!strcasecmp(v->name, "search")) { 00422 s = enum_newtoplev(v->value); 00423 if (s) { 00424 if (sl) 00425 sl->next = s; 00426 else 00427 toplevs = s; 00428 sl = s; 00429 } 00430 } 00431 v = v->next; 00432 } 00433 ast_destroy(cfg); 00434 } else { 00435 toplevs = enum_newtoplev(TOPLEV); 00436 } 00437 enumver++; 00438 ast_mutex_unlock(&enumlock); 00439 return 0; 00440 } 00441 00442 int ast_enum_reload(void) 00443 { 00444 return ast_enum_init(); 00445 }

Generated on Sat Jun 12 16:40:58 2004 for Asterisk by doxygen 1.3.7