1
0

0024-Cache-SRV-records.patch 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. From 5b99eae59d59a8e34a7e512059b98bbd803312f2 Mon Sep 17 00:00:00 2001
  2. From: Simon Kelley <simon@thekelleys.org.uk>
  3. Date: Sun, 6 Jan 2019 23:09:50 +0000
  4. Subject: [PATCH 24/32] Cache SRV records.
  5. Inpsired by a patch from Jeremy Allison, but completely re-rolled
  6. by srk. All bugs are mine.
  7. Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
  8. ---
  9. src/auth.c | 2 +-
  10. src/blockdata.c | 12 ++---
  11. src/cache.c | 64 ++++++++++++++--------
  12. src/dnsmasq.c | 2 -
  13. src/dnsmasq.h | 11 ++--
  14. src/rfc1035.c | 141 ++++++++++++++++++++++++++++++++++++++----------
  15. 6 files changed, 166 insertions(+), 66 deletions(-)
  16. --- a/src/auth.c
  17. +++ b/src/auth.c
  18. @@ -129,7 +129,7 @@ size_t answer_auth(struct dns_header *he
  19. for (q = ntohs(header->qdcount); q != 0; q--)
  20. {
  21. - unsigned short flag = 0;
  22. + unsigned int flag = 0;
  23. int found = 0;
  24. int cname_wildcard = 0;
  25. --- a/src/blockdata.c
  26. +++ b/src/blockdata.c
  27. @@ -16,8 +16,6 @@
  28. #include "dnsmasq.h"
  29. -#ifdef HAVE_DNSSEC
  30. -
  31. static struct blockdata *keyblock_free;
  32. static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
  33. @@ -54,11 +52,10 @@ void blockdata_init(void)
  34. void blockdata_report(void)
  35. {
  36. - if (option_bool(OPT_DNSSEC_VALID))
  37. - my_syslog(LOG_INFO, _("DNSSEC memory in use %u, max %u, allocated %u"),
  38. - blockdata_count * sizeof(struct blockdata),
  39. - blockdata_hwm * sizeof(struct blockdata),
  40. - blockdata_alloced * sizeof(struct blockdata));
  41. + my_syslog(LOG_INFO, _("pool memory in use %u, max %u, allocated %u"),
  42. + blockdata_count * sizeof(struct blockdata),
  43. + blockdata_hwm * sizeof(struct blockdata),
  44. + blockdata_alloced * sizeof(struct blockdata));
  45. }
  46. static struct blockdata *blockdata_alloc_real(int fd, char *data, size_t len)
  47. @@ -178,4 +175,3 @@ struct blockdata *blockdata_read(int fd,
  48. return blockdata_alloc_real(fd, NULL, len);
  49. }
  50. -#endif
  51. --- a/src/cache.c
  52. +++ b/src/cache.c
  53. @@ -27,7 +27,7 @@ static int bignames_left, hash_size;
  54. static void make_non_terminals(struct crec *source);
  55. static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
  56. - time_t now, unsigned long ttl, unsigned short flags);
  57. + time_t now, unsigned long ttl, unsigned int flags);
  58. /* type->string mapping: this is also used by the name-hash function as a mixing table. */
  59. static const struct {
  60. @@ -198,15 +198,17 @@ static void cache_hash(struct crec *crec
  61. *up = crecp;
  62. }
  63. -#ifdef HAVE_DNSSEC
  64. static void cache_blockdata_free(struct crec *crecp)
  65. {
  66. - if (crecp->flags & F_DNSKEY)
  67. + if (crecp->flags & F_SRV)
  68. + blockdata_free(crecp->addr.srv.target);
  69. +#ifdef HAVE_DNSSEC
  70. + else if (crecp->flags & F_DNSKEY)
  71. blockdata_free(crecp->addr.key.keydata);
  72. else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
  73. blockdata_free(crecp->addr.ds.keydata);
  74. -}
  75. #endif
  76. +}
  77. static void cache_free(struct crec *crecp)
  78. {
  79. @@ -230,9 +232,7 @@ static void cache_free(struct crec *crec
  80. crecp->flags &= ~F_BIGNAME;
  81. }
  82. -#ifdef HAVE_DNSSEC
  83. cache_blockdata_free(crecp);
  84. -#endif
  85. }
  86. /* insert a new cache entry at the head of the list (youngest entry) */
  87. @@ -331,7 +331,7 @@ static int is_expired(time_t now, struct
  88. }
  89. static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned short class, time_t now,
  90. - unsigned short flags, struct crec **target_crec, unsigned int *target_uid)
  91. + unsigned int flags, struct crec **target_crec, unsigned int *target_uid)
  92. {
  93. /* Scan and remove old entries.
  94. If (flags & F_FORWARD) then remove any forward entries for name and any expired
  95. @@ -360,7 +360,7 @@ static struct crec *cache_scan_free(char
  96. if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
  97. {
  98. /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
  99. - if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) ||
  100. + if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV)) ||
  101. (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
  102. {
  103. if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
  104. @@ -467,10 +467,10 @@ void cache_start_insert(void)
  105. }
  106. struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
  107. - time_t now, unsigned long ttl, unsigned short flags)
  108. + time_t now, unsigned long ttl, unsigned int flags)
  109. {
  110. /* Don't log DNSSEC records here, done elsewhere */
  111. - if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
  112. + if (flags & (F_IPV4 | F_IPV6 | F_CNAME | F_SRV))
  113. {
  114. log_query(flags | F_UPSTREAM, name, addr, NULL);
  115. /* Don't mess with TTL for DNSSEC records. */
  116. @@ -485,7 +485,7 @@ struct crec *cache_insert(char *name, un
  117. static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
  118. - time_t now, unsigned long ttl, unsigned short flags)
  119. + time_t now, unsigned long ttl, unsigned int flags)
  120. {
  121. struct crec *new, *target_crec = NULL;
  122. union bigname *big_name = NULL;
  123. @@ -649,7 +649,7 @@ void cache_end_insert(void)
  124. {
  125. char *name = cache_get_name(new_chain);
  126. ssize_t m = strlen(name);
  127. - unsigned short flags = new_chain->flags;
  128. + unsigned int flags = new_chain->flags;
  129. #ifdef HAVE_DNSSEC
  130. u16 class = new_chain->uid;
  131. #endif
  132. @@ -659,8 +659,10 @@ void cache_end_insert(void)
  133. read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
  134. read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
  135. - if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS))
  136. + if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
  137. read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
  138. + if (flags & F_SRV)
  139. + blockdata_write(new_chain->addr.srv.target, new_chain->addr.srv.targetlen, daemon->pipe_to_parent);
  140. #ifdef HAVE_DNSSEC
  141. if (flags & F_DNSKEY)
  142. {
  143. @@ -699,7 +701,7 @@ int cache_recv_insert(time_t now, int fd
  144. union all_addr addr;
  145. unsigned long ttl;
  146. time_t ttd;
  147. - unsigned short flags;
  148. + unsigned int flags;
  149. struct crec *crecp = NULL;
  150. cache_start_insert();
  151. @@ -725,13 +727,16 @@ int cache_recv_insert(time_t now, int fd
  152. ttl = difftime(ttd, now);
  153. - if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS))
  154. + if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
  155. {
  156. unsigned short class = C_IN;
  157. if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
  158. return 0;
  159. -
  160. +
  161. + if (flags & F_SRV && !(addr.srv.target = blockdata_read(fd, addr.srv.targetlen)))
  162. + return 0;
  163. +
  164. #ifdef HAVE_DNSSEC
  165. if (flags & F_DNSKEY)
  166. {
  167. @@ -802,7 +807,7 @@ struct crec *cache_find_by_name(struct c
  168. /* first search, look for relevant entries and push to top of list
  169. also free anything which has expired */
  170. struct crec *next, **up, **insert = NULL, **chainp = &ans;
  171. - unsigned short ins_flags = 0;
  172. + unsigned int ins_flags = 0;
  173. for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
  174. {
  175. @@ -1086,7 +1091,7 @@ int read_hostsfile(char *filename, unsig
  176. FILE *f = fopen(filename, "r");
  177. char *token = daemon->namebuff, *domain_suffix = NULL;
  178. int addr_count = 0, name_count = cache_size, lineno = 0;
  179. - unsigned short flags = 0;
  180. + unsigned int flags = 0;
  181. union all_addr addr;
  182. int atnl, addrlen = 0;
  183. @@ -1201,9 +1206,8 @@ void cache_reload(void)
  184. for (i=0; i<hash_size; i++)
  185. for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
  186. {
  187. -#ifdef HAVE_DNSSEC
  188. cache_blockdata_free(cache);
  189. -#endif
  190. +
  191. tmp = cache->hash_next;
  192. if (cache->flags & (F_HOSTS | F_CONFIG))
  193. {
  194. @@ -1381,7 +1385,7 @@ void cache_add_dhcp_entry(char *host_nam
  195. union all_addr *host_address, time_t ttd)
  196. {
  197. struct crec *crec = NULL, *fail_crec = NULL;
  198. - unsigned short flags = F_IPV4;
  199. + unsigned int flags = F_IPV4;
  200. int in_hosts = 0;
  201. size_t addrlen = sizeof(struct in_addr);
  202. @@ -1682,9 +1686,8 @@ void dump_cache(time_t now)
  203. #ifdef HAVE_AUTH
  204. my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
  205. #endif
  206. -#ifdef HAVE_DNSSEC
  207. +
  208. blockdata_report();
  209. -#endif
  210. /* sum counts from different records for same server */
  211. for (serv = daemon->servers; serv; serv = serv->next)
  212. @@ -1726,6 +1729,17 @@ void dump_cache(time_t now)
  213. p += sprintf(p, "%-30.30s ", sanitise(n));
  214. if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
  215. a = sanitise(cache_get_cname_target(cache));
  216. + else if ((cache->flags & F_SRV) && !(cache->flags & F_NEG))
  217. + {
  218. + int targetlen = cache->addr.srv.targetlen;
  219. + ssize_t len = sprintf(a, "%u %u %u ", cache->addr.srv.priority,
  220. + cache->addr.srv.weight, cache->addr.srv.srvport);
  221. +
  222. + if (targetlen > (40 - len))
  223. + targetlen = 40 - len;
  224. + blockdata_retrieve(cache->addr.srv.target, targetlen, a + len);
  225. + a[len + targetlen] = 0;
  226. + }
  227. #ifdef HAVE_DNSSEC
  228. else if (cache->flags & F_DS)
  229. {
  230. @@ -1752,6 +1766,8 @@ void dump_cache(time_t now)
  231. t = "6";
  232. else if (cache->flags & F_CNAME)
  233. t = "C";
  234. + else if (cache->flags & F_SRV)
  235. + t = "V";
  236. #ifdef HAVE_DNSSEC
  237. else if (cache->flags & F_DS)
  238. t = "S";
  239. @@ -1913,6 +1929,8 @@ void log_query(unsigned int flags, char
  240. }
  241. else if (flags & F_CNAME)
  242. dest = "<CNAME>";
  243. + else if (flags & F_SRV)
  244. + dest = "<SRV>";
  245. else if (flags & F_RRNAME)
  246. dest = arg;
  247. --- a/src/dnsmasq.c
  248. +++ b/src/dnsmasq.c
  249. @@ -366,9 +366,7 @@ int main (int argc, char **argv)
  250. {
  251. cache_init();
  252. -#ifdef HAVE_DNSSEC
  253. blockdata_init();
  254. -#endif
  255. }
  256. #ifdef HAVE_INOTIFY
  257. --- a/src/dnsmasq.h
  258. +++ b/src/dnsmasq.h
  259. @@ -299,6 +299,10 @@ union all_addr {
  260. unsigned char algo;
  261. unsigned char digest;
  262. } ds;
  263. + struct {
  264. + struct blockdata *target;
  265. + unsigned short targetlen, srvport, priority, weight;
  266. + } srv;
  267. /* for log_query */
  268. struct {
  269. unsigned short keytag, algo, digest, rcode;
  270. @@ -426,7 +430,7 @@ struct crec {
  271. time_t ttd; /* time to die */
  272. /* used as class if DNSKEY/DS, index to source for F_HOSTS */
  273. unsigned int uid;
  274. - unsigned short flags;
  275. + unsigned int flags;
  276. union {
  277. char sname[SMALLDNAME];
  278. union bigname *bname;
  279. @@ -470,6 +474,7 @@ struct crec {
  280. #define F_NOEXTRA (1u<<27)
  281. #define F_SERVFAIL (1u<<28)
  282. #define F_RCODE (1u<<29)
  283. +#define F_SRV (1u<<30)
  284. #define UID_NONE 0
  285. /* Values of uid in crecs with F_CONFIG bit set. */
  286. @@ -1142,7 +1147,7 @@ void cache_end_insert(void);
  287. void cache_start_insert(void);
  288. int cache_recv_insert(time_t now, int fd);
  289. struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
  290. - time_t now, unsigned long ttl, unsigned short flags);
  291. + time_t now, unsigned long ttl, unsigned int flags);
  292. void cache_reload(void);
  293. void cache_add_dhcp_entry(char *host_name, int prot, union all_addr *host_address, time_t ttd);
  294. struct in_addr a_record_from_hosts(char *name, time_t now);
  295. @@ -1158,7 +1163,6 @@ int read_hostsfile(char *filename, unsig
  296. struct crec **rhash, int hashsz);
  297. /* blockdata.c */
  298. -#ifdef HAVE_DNSSEC
  299. void blockdata_init(void);
  300. void blockdata_report(void);
  301. struct blockdata *blockdata_alloc(char *data, size_t len);
  302. @@ -1166,7 +1170,6 @@ void *blockdata_retrieve(struct blockdat
  303. struct blockdata *blockdata_read(int fd, size_t len);
  304. void blockdata_write(struct blockdata *block, size_t len, int fd);
  305. void blockdata_free(struct blockdata *blocks);
  306. -#endif
  307. /* domain.c */
  308. char *get_domain(struct in_addr addr);
  309. --- a/src/rfc1035.c
  310. +++ b/src/rfc1035.c
  311. @@ -726,7 +726,7 @@ int extract_addresses(struct dns_header
  312. {
  313. /* everything other than PTR */
  314. struct crec *newc;
  315. - int addrlen;
  316. + int addrlen = 0;
  317. if (qtype == T_A)
  318. {
  319. @@ -738,7 +738,9 @@ int extract_addresses(struct dns_header
  320. addrlen = IN6ADDRSZ;
  321. flags |= F_IPV6;
  322. }
  323. - else
  324. + else if (qtype == T_SRV)
  325. + flags |= F_SRV;
  326. + else
  327. continue;
  328. cname_loop1:
  329. @@ -799,39 +801,61 @@ int extract_addresses(struct dns_header
  330. {
  331. found = 1;
  332. - /* copy address into aligned storage */
  333. - if (!CHECK_LEN(header, p1, qlen, addrlen))
  334. - return 0; /* bad packet */
  335. - memcpy(&addr, p1, addrlen);
  336. -
  337. - /* check for returned address in private space */
  338. - if (check_rebind)
  339. + if (flags & F_SRV)
  340. {
  341. - if ((flags & F_IPV4) &&
  342. - private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
  343. - return 1;
  344. -
  345. - if ((flags & F_IPV6) &&
  346. - IN6_IS_ADDR_V4MAPPED(&addr.addr6))
  347. + unsigned char *tmp = namep;
  348. +
  349. + if (!CHECK_LEN(header, p1, qlen, 6))
  350. + return 0; /* bad packet */
  351. + GETSHORT(addr.srv.priority, p1);
  352. + GETSHORT(addr.srv.weight, p1);
  353. + GETSHORT(addr.srv.srvport, p1);
  354. + if (!extract_name(header, qlen, &p1, name, 1, 0))
  355. + return 0;
  356. + addr.srv.targetlen = strlen(name) + 1; /* include terminating zero */
  357. + if (!(addr.srv.target = blockdata_alloc(name, addr.srv.targetlen)))
  358. + return 0;
  359. +
  360. + /* we overwrote the original name, so get it back here. */
  361. + if (!extract_name(header, qlen, &tmp, name, 1, 0))
  362. + return 0;
  363. + }
  364. + else
  365. + {
  366. + /* copy address into aligned storage */
  367. + if (!CHECK_LEN(header, p1, qlen, addrlen))
  368. + return 0; /* bad packet */
  369. + memcpy(&addr, p1, addrlen);
  370. +
  371. + /* check for returned address in private space */
  372. + if (check_rebind)
  373. {
  374. - struct in_addr v4;
  375. - v4.s_addr = ((const uint32_t *) (&addr.addr6))[3];
  376. - if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
  377. + if ((flags & F_IPV4) &&
  378. + private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
  379. return 1;
  380. +
  381. + if ((flags & F_IPV6) &&
  382. + IN6_IS_ADDR_V4MAPPED(&addr.addr6))
  383. + {
  384. + struct in_addr v4;
  385. + v4.s_addr = ((const uint32_t *) (&addr.addr6))[3];
  386. + if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
  387. + return 1;
  388. + }
  389. }
  390. - }
  391. -
  392. +
  393. #ifdef HAVE_IPSET
  394. - if (ipsets && (flags & (F_IPV4 | F_IPV6)))
  395. - {
  396. - ipsets_cur = ipsets;
  397. - while (*ipsets_cur)
  398. + if (ipsets && (flags & (F_IPV4 | F_IPV6)))
  399. {
  400. - log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
  401. - add_to_ipset(*ipsets_cur++, &addr, flags, 0);
  402. + ipsets_cur = ipsets;
  403. + while (*ipsets_cur)
  404. + {
  405. + log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
  406. + add_to_ipset(*ipsets_cur++, &addr, flags, 0);
  407. + }
  408. }
  409. - }
  410. #endif
  411. + }
  412. newc = cache_insert(name, &addr, C_IN, now, attl, flags | F_FORWARD | secflag);
  413. if (newc && cpp)
  414. @@ -1844,7 +1868,68 @@ size_t answer_request(struct dns_header
  415. *up = move;
  416. move->next = NULL;
  417. }
  418. -
  419. +
  420. + if (!found)
  421. + {
  422. + cname_srv_restart:
  423. + if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | F_SRV | (dryrun ? F_NO_RR : 0))) &&
  424. + (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
  425. + {
  426. + if (!(crecp->flags & F_DNSSECOK))
  427. + sec_data = 0;
  428. +
  429. + auth = 0;
  430. + found = ans = 1;
  431. +
  432. + do {
  433. + if (crecp->flags & F_CNAME)
  434. + {
  435. + char *cname_target = cache_get_cname_target(crecp);
  436. +
  437. + if (!dryrun)
  438. + {
  439. + log_query(crecp->flags, name, NULL, record_source(crecp->uid));
  440. + if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
  441. + crec_ttl(crecp, now), &nameoffset,
  442. + T_CNAME, C_IN, "d", cname_target))
  443. + anscount++;
  444. + }
  445. +
  446. + strcpy(name, cname_target);
  447. + goto cname_srv_restart;
  448. + }
  449. + else if (crecp->flags & F_NEG)
  450. + {
  451. + if (crecp->flags & F_NXDOMAIN)
  452. + nxdomain = 1;
  453. + if (!dryrun)
  454. + log_query(crecp->flags, name, NULL, NULL);
  455. + }
  456. + else
  457. + {
  458. + unsigned char *p1 = ((unsigned char *)header) + nameoffset;
  459. +
  460. + if (!dryrun)
  461. + {
  462. + log_query(crecp->flags, name, NULL, 0);
  463. +
  464. + blockdata_retrieve(crecp->addr.srv.target, crecp->addr.srv.targetlen, name);
  465. + if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
  466. + crec_ttl(crecp, now), NULL, T_SRV, C_IN, "sssd",
  467. + crecp->addr.srv.priority, crecp->addr.srv.weight, crecp->addr.srv.srvport,
  468. + name))
  469. + anscount++;
  470. +
  471. +
  472. + /* restore name we overwrote */
  473. + if (!extract_name(header, qlen, &p1, name, 1, 0))
  474. + return 0; /* bad packet */
  475. + }
  476. + }
  477. + } while ((crecp = cache_find_by_name(crecp, name, now, F_SRV | F_CNAME)));
  478. + }
  479. + }
  480. +
  481. if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
  482. {
  483. ans = 1;