cache.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*
  2. * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License version 2.1
  6. * as published by the Free Software Foundation
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. */
  13. #define _GNU_SOURCE
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <fcntl.h>
  17. #include <time.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include <sys/types.h>
  22. #include <sys/socket.h>
  23. #include <netinet/in.h>
  24. #include <arpa/inet.h>
  25. #include <arpa/nameser.h>
  26. #include <resolv.h>
  27. #include <time.h>
  28. #include <libubox/usock.h>
  29. #include <libubox/uloop.h>
  30. #include <libubox/avl-cmp.h>
  31. #include <libubox/blobmsg_json.h>
  32. #include <libubox/kvlist.h>
  33. #include <libubus.h>
  34. #include "cache.h"
  35. #include "util.h"
  36. #include "dns.h"
  37. #include "interface.h"
  38. static struct uloop_timeout cache_gc;
  39. struct avl_tree services;
  40. static int avl_strcasecmp(const void *k1, const void *k2, void *ptr)
  41. {
  42. return strcasecmp(k1, k2);
  43. }
  44. AVL_TREE(records, avl_strcasecmp, true, NULL);
  45. static void
  46. cache_record_free(struct cache_record *r)
  47. {
  48. DBG(2, "%s %s\n", dns_type_string(r->type), r->record);
  49. avl_delete(&records, &r->avl);
  50. free(r);
  51. }
  52. static void
  53. cache_service_free(struct cache_service *s)
  54. {
  55. DBG(2, "%s\n", s->entry);
  56. avl_delete(&services, &s->avl);
  57. free(s);
  58. }
  59. static int
  60. cache_is_expired(time_t t, uint32_t ttl, int frac)
  61. {
  62. if (monotonic_time() - t >= ttl * frac / 100)
  63. return 1;
  64. return 0;
  65. }
  66. static void
  67. cache_gc_timer(struct uloop_timeout *timeout)
  68. {
  69. struct cache_record *r, *p;
  70. struct cache_service *s, *t;
  71. avl_for_each_element_safe(&records, r, avl, p) {
  72. if (!cache_is_expired(r->time, r->ttl, r->refresh))
  73. continue;
  74. /* Records other than A(AAA) are handled as services */
  75. if (r->type != TYPE_A && r->type != TYPE_AAAA) {
  76. if (cache_is_expired(r->time, r->ttl, 100))
  77. cache_record_free(r);
  78. continue;
  79. }
  80. if (r->refresh >= 100) {
  81. cache_record_free(r);
  82. continue;
  83. }
  84. r->refresh += 50;
  85. dns_send_question(r->iface, (struct sockaddr *)&r->from, r->record, r->type, 0);
  86. }
  87. avl_for_each_element_safe(&services, s, avl, t) {
  88. if (!s->host)
  89. continue;
  90. if (!cache_is_expired(s->time, s->ttl, s->refresh))
  91. continue;
  92. if (s->refresh >= 100) {
  93. cache_service_free(s);
  94. continue;
  95. }
  96. s->refresh += 50;
  97. dns_send_question(s->iface, NULL, s->entry, TYPE_PTR, 0);
  98. }
  99. uloop_timeout_set(timeout, 10000);
  100. }
  101. int
  102. cache_init(void)
  103. {
  104. avl_init(&services, avl_strcasecmp, true, NULL);
  105. cache_gc.cb = cache_gc_timer;
  106. uloop_timeout_set(&cache_gc, 10000);
  107. return 0;
  108. }
  109. void cache_cleanup(struct interface *iface)
  110. {
  111. struct cache_record *r, *p;
  112. struct cache_service *s, *t;
  113. avl_for_each_element_safe(&services, s, avl, t)
  114. if (!iface || iface == s->iface)
  115. cache_service_free(s);
  116. avl_for_each_element_safe(&records, r, avl, p)
  117. if (!iface || iface == r->iface)
  118. cache_record_free(r);
  119. }
  120. void
  121. cache_update(void)
  122. {
  123. struct interface *iface;
  124. vlist_for_each_element(&interfaces, iface, node) {
  125. dns_send_question(iface, NULL, C_DNS_SD, TYPE_ANY, 0);
  126. dns_send_question(iface, NULL, C_DNS_SD, TYPE_PTR, 0);
  127. }
  128. }
  129. static struct cache_service*
  130. cache_service(struct interface *iface, char *entry, int hlen, int ttl)
  131. {
  132. struct cache_service *s, *t;
  133. char *entry_buf;
  134. char *host_buf;
  135. char *type;
  136. avl_for_each_element_safe(&services, s, avl, t)
  137. if (!strcmp(s->entry, entry)) {
  138. s->refresh = 50;
  139. s->time = monotonic_time();
  140. s->ttl = ttl;
  141. return s;
  142. }
  143. s = calloc_a(sizeof(*s),
  144. &entry_buf, strlen(entry) + 1,
  145. &host_buf, hlen ? hlen + 1 : 0);
  146. s->avl.key = s->entry = strcpy(entry_buf, entry);
  147. s->time = monotonic_time();
  148. s->ttl = ttl;
  149. s->iface = iface;
  150. s->refresh = 50;
  151. if (hlen)
  152. s->host = strncpy(host_buf, s->entry, hlen);
  153. type = strstr(entry_buf, "._");
  154. if (type)
  155. type++;
  156. if (type)
  157. s->avl.key = type;
  158. avl_insert(&services, &s->avl);
  159. if (!hlen)
  160. dns_send_question(iface, NULL, entry, TYPE_PTR, interface_multicast(iface));
  161. return s;
  162. }
  163. static struct cache_record*
  164. cache_record_find(char *record, int type, int port, int rdlength, uint8_t *rdata)
  165. {
  166. struct cache_record *l = avl_find_element(&records, record, l, avl);
  167. while (l && !strcmp(l->record, record)) {
  168. struct cache_record *r = l;
  169. l = !avl_is_last(&records, &l->avl) ? avl_next_element(l, avl) : NULL;
  170. if (r->type != type)
  171. continue;
  172. if (r->type == TYPE_TXT || (r->type == TYPE_SRV))
  173. return r;
  174. if (r->port != port)
  175. continue;
  176. if (r->rdlength != rdlength)
  177. continue;
  178. if (!!r->rdata != !!rdata)
  179. continue;
  180. if (!r->rdata || !rdata || memcmp(r->rdata, rdata, rdlength))
  181. continue;
  182. return r;
  183. }
  184. return NULL;
  185. }
  186. int
  187. cache_host_is_known(char *record)
  188. {
  189. struct cache_record *l = avl_find_element(&records, record, l, avl);
  190. while (l && !strcmp(l->record, record)) {
  191. struct cache_record *r = l;
  192. l = !avl_is_last(&records, &l->avl) ? avl_next_element(l, avl) : NULL;
  193. if ((r->type != TYPE_A) && (r->type != TYPE_AAAA))
  194. continue;
  195. return 1;
  196. }
  197. return 0;
  198. }
  199. void cache_answer(struct interface *iface, struct sockaddr *from, uint8_t *base,
  200. int blen, char *name, struct dns_answer *a, uint8_t *rdata,
  201. int flush)
  202. {
  203. struct dns_srv_data *dsd = (struct dns_srv_data *) rdata;
  204. struct cache_record *r;
  205. int port = 0, dlen = 0, tlen = 0, nlen, rdlength;
  206. char *p = NULL;
  207. char *name_buf;
  208. void *rdata_ptr, *txt_ptr;
  209. int host_len = 0;
  210. static char *rdata_buffer = (char *) mdns_buf;
  211. time_t now = monotonic_time();
  212. nlen = strlen(name);
  213. switch (a->type) {
  214. case TYPE_PTR:
  215. if (a->rdlength < 2)
  216. return;
  217. if (dn_expand(base, base + blen, rdata, rdata_buffer, MAX_DATA_LEN) < 0) {
  218. perror("process_answer/dn_expand");
  219. return;
  220. }
  221. DBG(1, "A -> %s %s %s ttl:%d\n", dns_type_string(a->type), name, rdata_buffer, a->ttl);
  222. rdlength = strlen(rdata_buffer);
  223. if (strcmp(C_DNS_SD, name) != 0 &&
  224. nlen + 1 < rdlength && !strcmp(rdata_buffer + rdlength - nlen, name))
  225. host_len = rdlength - nlen - 1;
  226. if (name[0] == '_')
  227. cache_service(iface, rdata_buffer, host_len, a->ttl);
  228. dlen = strlen(rdata_buffer) + 1;
  229. rdata = (uint8_t*)rdata_buffer;
  230. break;
  231. case TYPE_SRV:
  232. if (a->rdlength < 8)
  233. return;
  234. port = be16_to_cpu(dsd->port);
  235. memcpy(rdata_buffer, dsd, sizeof(*dsd));
  236. if (dn_expand(base, base + blen, (const uint8_t*)&dsd[1],
  237. &rdata_buffer[sizeof(*dsd)], MAX_DATA_LEN - sizeof(*dsd)) < 0) {
  238. perror("process_answer/dn_expand");
  239. return;
  240. }
  241. dlen = sizeof(*dsd) + strlen(&rdata_buffer[sizeof(*dsd)]) + 1;
  242. rdata = (uint8_t*)rdata_buffer;
  243. break;
  244. case TYPE_TXT:
  245. rdlength = a->rdlength;
  246. if (rdlength <= 2)
  247. return;
  248. memcpy(rdata_buffer, &rdata[1], rdlength-1);
  249. rdata_buffer[rdlength] = rdata_buffer[rdlength + 1] = '\0';
  250. tlen = rdlength + 1;
  251. p = &rdata_buffer[*rdata];
  252. do {
  253. uint8_t v = *p;
  254. *p = '\0';
  255. if (v && p + v < &rdata_buffer[rdlength])
  256. p += v + 1;
  257. } while (*p);
  258. break;
  259. case TYPE_A:
  260. if (a->rdlength != 4)
  261. return;
  262. dlen = 4;
  263. break;
  264. case TYPE_AAAA:
  265. if (a->rdlength != 16)
  266. return;
  267. dlen = 16;
  268. break;
  269. default:
  270. return;
  271. }
  272. r = cache_record_find(name, a->type, port, dlen, rdata);
  273. if (r) {
  274. if (!a->ttl) {
  275. DBG(1, "D -> %s %s ttl:%d\n", dns_type_string(r->type), r->record, r->ttl);
  276. r->time = now + 1 - r->ttl;
  277. r->refresh = 100;
  278. } else {
  279. r->ttl = a->ttl;
  280. r->time = now;
  281. r->refresh = 50;
  282. DBG(1, "A -> %s %s ttl:%d\n", dns_type_string(r->type), r->record, r->ttl);
  283. }
  284. return;
  285. }
  286. if (!a->ttl)
  287. return;
  288. r = calloc_a(sizeof(*r),
  289. &name_buf, strlen(name) + 1,
  290. &txt_ptr, tlen,
  291. &rdata_ptr, dlen);
  292. r->avl.key = r->record = strcpy(name_buf, name);
  293. r->type = a->type;
  294. r->ttl = a->ttl;
  295. r->port = port;
  296. r->rdlength = dlen;
  297. r->time = now;
  298. r->iface = iface;
  299. if (interface_ipv6(iface))
  300. memcpy(&r->from, from, sizeof(struct sockaddr_in6));
  301. else
  302. memcpy(&r->from, from, sizeof(struct sockaddr_in));
  303. r->refresh = 50;
  304. if (tlen)
  305. r->txt = memcpy(txt_ptr, rdata_buffer, tlen);
  306. if (dlen)
  307. r->rdata = memcpy(rdata_ptr, rdata, dlen);
  308. if (avl_insert(&records, &r->avl))
  309. free(r);
  310. else
  311. DBG(1, "A -> %s %s ttl:%d\n", dns_type_string(r->type), r->record, r->ttl);
  312. }
  313. void
  314. cache_dump_records(struct blob_buf *buf, const char *name, int array,
  315. const char **hostname)
  316. {
  317. struct cache_record *r, *last, *next;
  318. const char *txt;
  319. char buffer[INET6_ADDRSTRLEN];
  320. void *c = NULL;
  321. last = avl_last_element(&records, last, avl);
  322. for (r = avl_find_element(&records, name, r, avl); r; r = next) {
  323. switch (r->type) {
  324. case TYPE_A:
  325. if (!c && array)
  326. c = blobmsg_open_array(buf, "ipv4");
  327. if ((r->rdlength == 4) && inet_ntop(AF_INET, r->rdata, buffer, INET6_ADDRSTRLEN))
  328. blobmsg_add_string(buf, "ipv4", buffer);
  329. break;
  330. }
  331. if (r == last)
  332. break;
  333. next = avl_next_element(r, avl);
  334. if (strcmp(r->record, next->record) != 0)
  335. break;
  336. }
  337. if (c) {
  338. blobmsg_close_array(buf, c);
  339. c = NULL;
  340. }
  341. for (r = avl_find_element(&records, name, r, avl); r; r = next) {
  342. switch (r->type) {
  343. case TYPE_AAAA:
  344. if (!c && array)
  345. c = blobmsg_open_array(buf, "ipv6");
  346. if ((r->rdlength == 16) && inet_ntop(AF_INET6, r->rdata, buffer, INET6_ADDRSTRLEN))
  347. blobmsg_add_string(buf, "ipv6", buffer);
  348. break;
  349. }
  350. if (r == last)
  351. break;
  352. next = avl_next_element(r, avl);
  353. if (strcmp(r->record, next->record) != 0)
  354. break;
  355. }
  356. if (c) {
  357. blobmsg_close_array(buf, c);
  358. c = NULL;
  359. }
  360. for (r = avl_find_element(&records, name, r, avl); r; r = next) {
  361. switch (r->type) {
  362. case TYPE_TXT:
  363. if (r->txt && strlen(r->txt)) {
  364. if (array)
  365. c = blobmsg_open_array(buf, "txt");
  366. txt = r->txt;
  367. do {
  368. blobmsg_add_string(buf, "txt", txt);
  369. txt = &txt[strlen(txt) + 1];
  370. } while (*txt);
  371. if (array)
  372. blobmsg_close_array(buf, c);
  373. }
  374. break;
  375. case TYPE_SRV:
  376. if (r->rdata) {
  377. blobmsg_add_string(buf, "host", (char *)r->rdata + sizeof(struct dns_srv_data));
  378. if (hostname)
  379. *hostname = (char *)r->rdata + sizeof(struct dns_srv_data);
  380. }
  381. if (r->port)
  382. blobmsg_add_u32(buf, "port", r->port);
  383. break;
  384. }
  385. if (r == last)
  386. break;
  387. next = avl_next_element(r, avl);
  388. if (strcmp(r->record, next->record) != 0)
  389. break;
  390. }
  391. }
  392. void
  393. cache_dump_recursive(struct blob_buf *b, const char *name, uint16_t type, struct interface *iface)
  394. {
  395. time_t now = monotonic_time();
  396. for (struct cache_record *r = avl_find_ge_element(&records, name, r, avl);
  397. r && !strcmp(r->record, name);
  398. r = !avl_is_last(&records, &r->avl) ? avl_next_element(r, avl) : NULL) {
  399. int32_t ttl = r->ttl - (now - r->time);
  400. if (ttl <= 0 || (iface && iface->ifindex != r->iface->ifindex) ||
  401. (type != TYPE_ANY && type != r->type))
  402. continue;
  403. const char *txt;
  404. char buf[INET6_ADDRSTRLEN];
  405. void *k = blobmsg_open_table(b, NULL), *l;
  406. const struct dns_srv_data *dsd = (const struct dns_srv_data*)r->rdata;
  407. blobmsg_add_string(b, "name", r->record);
  408. blobmsg_add_string(b, "type", dns_type_string(r->type));
  409. blobmsg_add_u32(b, "ttl", ttl);
  410. switch (r->type) {
  411. case TYPE_TXT:
  412. if ((txt = r->txt) && strlen(txt)) {
  413. l = blobmsg_open_array(b, "data");
  414. do {
  415. blobmsg_add_string(b, NULL, txt);
  416. txt = &txt[strlen(txt) + 1];
  417. } while (*txt);
  418. blobmsg_close_array(b, l);
  419. }
  420. break;
  421. case TYPE_SRV:
  422. if (r->rdlength > sizeof(*dsd)) {
  423. blobmsg_add_u32(b, "priority", be16_to_cpu(dsd->priority));
  424. blobmsg_add_u32(b, "weight", be16_to_cpu(dsd->weight));
  425. blobmsg_add_u32(b, "port", be16_to_cpu(dsd->port));
  426. blobmsg_add_string(b, "target", (const char*)&dsd[1]);
  427. }
  428. break;
  429. case TYPE_PTR:
  430. if (r->rdlength > 0)
  431. blobmsg_add_string(b, "target", (const char*)r->rdata);
  432. break;
  433. case TYPE_A:
  434. if ((r->rdlength == 4) && inet_ntop(AF_INET, r->rdata, buf, sizeof(buf)))
  435. blobmsg_add_string(b, "target", buf);
  436. break;
  437. case TYPE_AAAA:
  438. if ((r->rdlength == 16) && inet_ntop(AF_INET6, r->rdata, buf, sizeof(buf)))
  439. blobmsg_add_string(b, "target", buf);
  440. break;
  441. }
  442. blobmsg_close_table(b, k);
  443. if (r->type == TYPE_PTR) {
  444. cache_dump_recursive(b, (const char*)r->rdata, TYPE_SRV, iface);
  445. cache_dump_recursive(b, (const char*)r->rdata, TYPE_TXT, iface);
  446. }
  447. if (r->type == TYPE_SRV) {
  448. cache_dump_recursive(b, (const char*)&dsd[1], TYPE_A, iface);
  449. cache_dump_recursive(b, (const char*)&dsd[1], TYPE_AAAA, iface);
  450. }
  451. }
  452. }