enum.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*
  2. * ENUM Support for Asterisk
  3. *
  4. * Copyright (C) 2003 Digium
  5. *
  6. * Written by Mark Spencer <markster@digium.com>
  7. *
  8. * Funding provided by nic.at
  9. *
  10. * Distributed under the terms of the GNU GPL
  11. *
  12. */
  13. #include <sys/types.h>
  14. #include <sys/socket.h>
  15. #include <netinet/in.h>
  16. #include <arpa/nameser.h>
  17. #if __APPLE_CC__ >= 1495
  18. #include <arpa/nameser_compat.h>
  19. #endif
  20. #include <resolv.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <ctype.h>
  24. #include <regex.h>
  25. #include <unistd.h>
  26. #include <errno.h>
  27. #include <asterisk/logger.h>
  28. #include <asterisk/options.h>
  29. #include <asterisk/enum.h>
  30. #include <asterisk/dns.h>
  31. #include <asterisk/channel.h>
  32. #include <asterisk/config.h>
  33. #include <asterisk/utils.h>
  34. #ifdef __APPLE__
  35. #undef T_NAPTR
  36. #define T_NAPTR 35
  37. #endif
  38. #ifdef __APPLE__
  39. #undef T_TXT
  40. #define T_TXT 16
  41. #endif
  42. #define TOPLEV "e164.arpa."
  43. static struct enum_search {
  44. char toplev[512];
  45. struct enum_search *next;
  46. } *toplevs;
  47. static int enumver = 0;
  48. AST_MUTEX_DEFINE_STATIC(enumlock);
  49. struct naptr {
  50. unsigned short order;
  51. unsigned short pref;
  52. } __attribute__ ((__packed__));
  53. static int parse_ie(unsigned char *data, int maxdatalen, unsigned char *src, int srclen)
  54. {
  55. int len, olen;
  56. len = olen = (int)src[0];
  57. src++;
  58. srclen--;
  59. if (len > srclen) {
  60. ast_log(LOG_WARNING, "Want %d, got %d\n", len, srclen);
  61. return -1;
  62. }
  63. if (len > maxdatalen)
  64. len = maxdatalen;
  65. memcpy(data, src, len);
  66. return olen + 1;
  67. }
  68. static int parse_naptr(unsigned char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, char *naptrinput)
  69. {
  70. unsigned char *oanswer = answer;
  71. unsigned char flags[512] = "";
  72. unsigned char services[512] = "";
  73. unsigned char regexp[512] = "";
  74. unsigned char repl[512] = "";
  75. unsigned char temp[512] = "";
  76. unsigned char delim;
  77. unsigned char *delim2;
  78. unsigned char *pattern, *subst, *d;
  79. int res;
  80. int regexp_len, size, backref;
  81. int d_len = sizeof(temp) - 1;
  82. regex_t preg;
  83. regmatch_t pmatch[9];
  84. dst[0] = '\0';
  85. if (len < sizeof(struct naptr)) {
  86. ast_log(LOG_WARNING, "Length too short\n");
  87. return -1;
  88. }
  89. answer += sizeof(struct naptr);
  90. len -= sizeof(struct naptr);
  91. if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) {
  92. ast_log(LOG_WARNING, "Failed to get flags\n");
  93. return -1;
  94. } else { answer += res; len -= res; }
  95. if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) {
  96. ast_log(LOG_WARNING, "Failed to get services\n");
  97. return -1;
  98. } else { answer += res; len -= res; }
  99. if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0)
  100. return -1; else { answer += res; len -= res; }
  101. if ((res = dn_expand(oanswer,answer + len,answer, repl, sizeof(repl) - 1)) < 0) {
  102. ast_log(LOG_WARNING, "Failed to expand hostname\n");
  103. return -1;
  104. }
  105. ast_log(LOG_DEBUG, "input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
  106. naptrinput, flags, services, regexp, repl);
  107. if (tolower(flags[0]) != 'u') {
  108. ast_log(LOG_WARNING, "Flag must be 'U' or 'u'.\n");
  109. return -1;
  110. }
  111. if ((!strncasecmp(services, "e2u+sip", 7)) ||
  112. (!strncasecmp(services, "sip+e2u", 7))) {
  113. strncpy(tech, "sip", techsize -1);
  114. } else if ((!strncasecmp(services, "e2u+h323", 8)) ||
  115. (!strncasecmp(services, "h323+e2u", 8))) {
  116. strncpy(tech, "h323", techsize -1);
  117. } else if ((!strncasecmp(services, "e2u+x-iax2", 10)) ||
  118. (!strncasecmp(services, "e2u+iax2", 8)) ||
  119. (!strncasecmp(services, "iax2+e2u", 8))) {
  120. strncpy(tech, "iax2", techsize -1);
  121. } else if ((!strncasecmp(services, "e2u+x-iax", 9)) ||
  122. (!strncasecmp(services, "e2u+iax", 7)) ||
  123. (!strncasecmp(services, "iax+e2u", 7))) {
  124. strncpy(tech, "iax", techsize -1);
  125. } else if ((!strncasecmp(services, "e2u+tel", 7)) ||
  126. (!strncasecmp(services, "tel+e2u", 7))) {
  127. strncpy(tech, "tel", techsize -1);
  128. } else if (!strncasecmp(services, "e2u+voice:", 10)) {
  129. strncpy(tech, services+10, techsize -1);
  130. } else {
  131. ast_log(LOG_DEBUG,
  132. "Services must be e2u+${tech}, ${tech}+e2u, or e2u+voice: where $tech is from (sip, h323, tel, iax, iax2). \n");
  133. return 0;
  134. }
  135. /* DEDBUGGING STUB
  136. strncpy(regexp, "!^\\+43(.*)$!\\1@bla.fasel!", sizeof(regexp) - 1);
  137. */
  138. regexp_len = strlen(regexp);
  139. if (regexp_len < 7) {
  140. ast_log(LOG_WARNING, "Regex too short to be meaningful.\n");
  141. return -1;
  142. }
  143. delim = regexp[0];
  144. delim2 = strchr(regexp + 1, delim);
  145. if ((delim2 == NULL) || (regexp[regexp_len-1] != delim)) {
  146. ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n",regexp);
  147. return -1;
  148. }
  149. pattern = regexp + 1;
  150. *delim2 = 0;
  151. subst = delim2 + 1;
  152. regexp[regexp_len-1] = 0;
  153. #if 0
  154. printf("Pattern: %s\n", pattern);
  155. printf("Subst: %s\n", subst);
  156. #endif
  157. /*
  158. * now do the regex wizardry.
  159. */
  160. if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) {
  161. ast_log(LOG_WARNING, "Regex compilation error (regex = \"%s\").\n",regexp);
  162. return -1;
  163. }
  164. if (preg.re_nsub > 9) {
  165. ast_log(LOG_WARNING, "Regex compilation error: too many subs.\n");
  166. regfree(&preg);
  167. return -1;
  168. }
  169. if (regexec(&preg, naptrinput, 9, pmatch, 0)) {
  170. ast_log(LOG_WARNING, "Regex match failed.\n");
  171. regfree(&preg);
  172. return -1;
  173. }
  174. regfree(&preg);
  175. d = temp; d_len--;
  176. while( *subst && (d_len > 0) ) {
  177. if ((subst[0] == '\\') && isdigit(subst[1]) && (pmatch[subst[1]-'0'].rm_so != -1)) {
  178. backref = subst[1]-'0';
  179. size = pmatch[backref].rm_eo - pmatch[backref].rm_so;
  180. if (size > d_len) {
  181. ast_log(LOG_WARNING, "Not enough space during regex substitution.\n");
  182. return -1;
  183. }
  184. memcpy(d, naptrinput + pmatch[backref].rm_so, size);
  185. d += size;
  186. d_len -= size;
  187. subst += 2;
  188. } else if (isprint(*subst)) {
  189. *d++ = *subst++;
  190. d_len--;
  191. } else {
  192. ast_log(LOG_WARNING, "Error during regex substitution.\n");
  193. return -1;
  194. }
  195. }
  196. *d = 0;
  197. strncpy(dst, temp, dstsize - 1);
  198. dst[dstsize - 1] = '\0';
  199. return 0;
  200. }
  201. struct enum_context {
  202. char *dst;
  203. int dstlen;
  204. char *tech;
  205. int techlen;
  206. char *txt;
  207. int txtlen;
  208. char *naptrinput;
  209. };
  210. static int txt_callback(void *context, u_char *answer, int len, u_char *fullanswer)
  211. {
  212. struct enum_context *c = (struct enum_context *)context;
  213. #if 0
  214. printf("ENUMTXT Called\n");
  215. #endif
  216. if (answer == NULL) {
  217. c->txt = NULL;
  218. c->txtlen = 0;
  219. return 0;
  220. }
  221. /* skip over first byte, as for some reason it's a vertical tab character */
  222. answer += 1;
  223. len -= 1;
  224. /* answer is not null-terminated, but should be */
  225. /* this is safe to do, as answer has extra bytes on the end we can
  226. safely overwrite with a null */
  227. answer[len] = '\0';
  228. /* now increment len so that len includes the null, so that we can
  229. compare apples to apples */
  230. len +=1;
  231. /* finally, copy the answer into c->txt */
  232. strncpy(c->txt, answer, len < c->txtlen ? len-1 : (c->txtlen)-1);
  233. /* just to be safe, let's make sure c->txt is null terminated */
  234. c->txt[(c->txtlen)-1] = '\0';
  235. return 1;
  236. }
  237. static int enum_callback(void *context, u_char *answer, int len, u_char *fullanswer)
  238. {
  239. struct enum_context *c = (struct enum_context *)context;
  240. if (parse_naptr(c->dst, c->dstlen, c->tech, c->techlen, answer, len, c->naptrinput)) {
  241. ast_log(LOG_WARNING, "Failed to parse naptr :(\n");
  242. return -1;
  243. }
  244. if (!ast_strlen_zero(c->dst))
  245. return 1;
  246. return 0;
  247. }
  248. int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen)
  249. {
  250. struct enum_context context;
  251. char tmp[259 + 512];
  252. char naptrinput[512] = "+";
  253. int pos = strlen(number) - 1;
  254. int newpos = 0;
  255. int ret = -1;
  256. struct enum_search *s = NULL;
  257. int version = -1;
  258. strncat(naptrinput, number, sizeof(naptrinput) - 2);
  259. context.naptrinput = naptrinput;
  260. context.dst = dst;
  261. context.dstlen = dstlen;
  262. context.tech = tech;
  263. context.techlen = techlen;
  264. if (pos > 128)
  265. pos = 128;
  266. while(pos >= 0) {
  267. tmp[newpos++] = number[pos--];
  268. tmp[newpos++] = '.';
  269. }
  270. if (chan && ast_autoservice_start(chan) < 0)
  271. return -1;
  272. for(;;) {
  273. ast_mutex_lock(&enumlock);
  274. if (version != enumver) {
  275. /* Ooh, a reload... */
  276. s = toplevs;
  277. version = enumver;
  278. } else {
  279. s = s->next;
  280. }
  281. if (s) {
  282. strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1);
  283. }
  284. ast_mutex_unlock(&enumlock);
  285. if (!s)
  286. break;
  287. ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
  288. if (ret > 0)
  289. break;
  290. }
  291. if (ret < 0) {
  292. ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno));
  293. ret = 0;
  294. }
  295. if (chan)
  296. ret |= ast_autoservice_stop(chan);
  297. return ret;
  298. }
  299. int ast_get_txt(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char *txt, int txtlen)
  300. {
  301. struct enum_context context;
  302. char tmp[259 + 512];
  303. char naptrinput[512] = "+";
  304. int pos = strlen(number) - 1;
  305. int newpos = 0;
  306. int ret = -1;
  307. struct enum_search *s = NULL;
  308. int version = -1;
  309. strncat(naptrinput, number, sizeof(naptrinput) - 2);
  310. context.naptrinput = naptrinput;
  311. context.dst = dst;
  312. context.dstlen = dstlen;
  313. context.tech = tech;
  314. context.techlen = techlen;
  315. context.txt = txt;
  316. context.txtlen = txtlen;
  317. if (pos > 128)
  318. pos = 128;
  319. while(pos >= 0) {
  320. tmp[newpos++] = number[pos--];
  321. tmp[newpos++] = '.';
  322. }
  323. if (chan && ast_autoservice_start(chan) < 0)
  324. return -1;
  325. for(;;) {
  326. ast_mutex_lock(&enumlock);
  327. if (version != enumver) {
  328. /* Ooh, a reload... */
  329. s = toplevs;
  330. version = enumver;
  331. } else {
  332. s = s->next;
  333. }
  334. if (s) {
  335. strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1);
  336. }
  337. ast_mutex_unlock(&enumlock);
  338. if (!s)
  339. break;
  340. ret = ast_search_dns(&context, tmp, C_IN, T_TXT, txt_callback);
  341. if (ret > 0)
  342. break;
  343. }
  344. if (ret < 0) {
  345. ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno));
  346. ret = 0;
  347. }
  348. if (chan)
  349. ret |= ast_autoservice_stop(chan);
  350. return ret;
  351. }
  352. static struct enum_search *enum_newtoplev(char *s)
  353. {
  354. struct enum_search *tmp;
  355. tmp = malloc(sizeof(struct enum_search));
  356. if (tmp) {
  357. memset(tmp, 0, sizeof(struct enum_search));
  358. strncpy(tmp->toplev, s, sizeof(tmp->toplev) - 1);
  359. }
  360. return tmp;
  361. }
  362. int ast_enum_init(void)
  363. {
  364. struct ast_config *cfg;
  365. struct enum_search *s, *sl;
  366. struct ast_variable *v;
  367. /* Destroy existing list */
  368. ast_mutex_lock(&enumlock);
  369. s = toplevs;
  370. while(s) {
  371. sl = s;
  372. s = s->next;
  373. free(sl);
  374. }
  375. toplevs = NULL;
  376. cfg = ast_load("enum.conf");
  377. if (cfg) {
  378. sl = NULL;
  379. v = ast_variable_browse(cfg, "general");
  380. while(v) {
  381. if (!strcasecmp(v->name, "search")) {
  382. s = enum_newtoplev(v->value);
  383. if (s) {
  384. if (sl)
  385. sl->next = s;
  386. else
  387. toplevs = s;
  388. sl = s;
  389. }
  390. }
  391. v = v->next;
  392. }
  393. ast_destroy(cfg);
  394. } else {
  395. toplevs = enum_newtoplev(TOPLEV);
  396. }
  397. enumver++;
  398. ast_mutex_unlock(&enumlock);
  399. return 0;
  400. }
  401. int ast_enum_reload(void)
  402. {
  403. return ast_enum_init();
  404. }