/contrib/bind9/lib/dns/masterdump.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1803 lines · 1373 code · 233 blank · 197 comment · 325 complexity · 080ab4612fdc680c26df08a04a5583f0 MD5 · raw file

  1. /*
  2. * Copyright (C) 2004-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC")
  3. * Copyright (C) 1999-2003 Internet Software Consortium.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  10. * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  11. * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  12. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  13. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  14. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  15. * PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /* $Id$ */
  18. /*! \file */
  19. #include <config.h>
  20. #include <stdlib.h>
  21. #include <isc/event.h>
  22. #include <isc/file.h>
  23. #include <isc/magic.h>
  24. #include <isc/mem.h>
  25. #include <isc/print.h>
  26. #include <isc/stdio.h>
  27. #include <isc/string.h>
  28. #include <isc/task.h>
  29. #include <isc/time.h>
  30. #include <isc/util.h>
  31. #include <dns/db.h>
  32. #include <dns/dbiterator.h>
  33. #include <dns/events.h>
  34. #include <dns/fixedname.h>
  35. #include <dns/lib.h>
  36. #include <dns/log.h>
  37. #include <dns/master.h>
  38. #include <dns/masterdump.h>
  39. #include <dns/ncache.h>
  40. #include <dns/rdata.h>
  41. #include <dns/rdataclass.h>
  42. #include <dns/rdataset.h>
  43. #include <dns/rdatasetiter.h>
  44. #include <dns/rdatatype.h>
  45. #include <dns/result.h>
  46. #include <dns/time.h>
  47. #include <dns/ttl.h>
  48. #define DNS_DCTX_MAGIC ISC_MAGIC('D', 'c', 't', 'x')
  49. #define DNS_DCTX_VALID(d) ISC_MAGIC_VALID(d, DNS_DCTX_MAGIC)
  50. #define RETERR(x) do { \
  51. isc_result_t _r = (x); \
  52. if (_r != ISC_R_SUCCESS) \
  53. return (_r); \
  54. } while (0)
  55. #define CHECK(x) do { \
  56. if ((x) != ISC_R_SUCCESS) \
  57. goto cleanup; \
  58. } while (0)
  59. struct dns_master_style {
  60. unsigned int flags; /* DNS_STYLEFLAG_* */
  61. unsigned int ttl_column;
  62. unsigned int class_column;
  63. unsigned int type_column;
  64. unsigned int rdata_column;
  65. unsigned int line_length;
  66. unsigned int tab_width;
  67. };
  68. /*%
  69. * The maximum length of the newline+indentation that is output
  70. * when inserting a line break in an RR. This effectively puts an
  71. * upper limits on the value of "rdata_column", because if it is
  72. * very large, the tabs and spaces needed to reach it will not fit.
  73. */
  74. #define DNS_TOTEXT_LINEBREAK_MAXLEN 100
  75. /*%
  76. * Context structure for a masterfile dump in progress.
  77. */
  78. typedef struct dns_totext_ctx {
  79. dns_master_style_t style;
  80. isc_boolean_t class_printed;
  81. char * linebreak;
  82. char linebreak_buf[DNS_TOTEXT_LINEBREAK_MAXLEN];
  83. dns_name_t * origin;
  84. dns_name_t * neworigin;
  85. dns_fixedname_t origin_fixname;
  86. isc_uint32_t current_ttl;
  87. isc_boolean_t current_ttl_valid;
  88. } dns_totext_ctx_t;
  89. LIBDNS_EXTERNAL_DATA const dns_master_style_t
  90. dns_master_style_default = {
  91. DNS_STYLEFLAG_OMIT_OWNER |
  92. DNS_STYLEFLAG_OMIT_CLASS |
  93. DNS_STYLEFLAG_REL_OWNER |
  94. DNS_STYLEFLAG_REL_DATA |
  95. DNS_STYLEFLAG_OMIT_TTL |
  96. DNS_STYLEFLAG_TTL |
  97. DNS_STYLEFLAG_COMMENT |
  98. DNS_STYLEFLAG_MULTILINE,
  99. 24, 24, 24, 32, 80, 8
  100. };
  101. LIBDNS_EXTERNAL_DATA const dns_master_style_t
  102. dns_master_style_full = {
  103. DNS_STYLEFLAG_COMMENT |
  104. DNS_STYLEFLAG_RESIGN,
  105. 46, 46, 46, 64, 120, 8
  106. };
  107. LIBDNS_EXTERNAL_DATA const dns_master_style_t
  108. dns_master_style_explicitttl = {
  109. DNS_STYLEFLAG_OMIT_OWNER |
  110. DNS_STYLEFLAG_OMIT_CLASS |
  111. DNS_STYLEFLAG_REL_OWNER |
  112. DNS_STYLEFLAG_REL_DATA |
  113. DNS_STYLEFLAG_COMMENT |
  114. DNS_STYLEFLAG_MULTILINE,
  115. 24, 32, 32, 40, 80, 8
  116. };
  117. LIBDNS_EXTERNAL_DATA const dns_master_style_t
  118. dns_master_style_cache = {
  119. DNS_STYLEFLAG_OMIT_OWNER |
  120. DNS_STYLEFLAG_OMIT_CLASS |
  121. DNS_STYLEFLAG_MULTILINE |
  122. DNS_STYLEFLAG_TRUST |
  123. DNS_STYLEFLAG_NCACHE,
  124. 24, 32, 32, 40, 80, 8
  125. };
  126. LIBDNS_EXTERNAL_DATA const dns_master_style_t
  127. dns_master_style_simple = {
  128. 0,
  129. 24, 32, 32, 40, 80, 8
  130. };
  131. /*%
  132. * A style suitable for dns_rdataset_totext().
  133. */
  134. LIBDNS_EXTERNAL_DATA const dns_master_style_t
  135. dns_master_style_debug = {
  136. DNS_STYLEFLAG_REL_OWNER,
  137. 24, 32, 40, 48, 80, 8
  138. };
  139. #define N_SPACES 10
  140. static char spaces[N_SPACES+1] = " ";
  141. #define N_TABS 10
  142. static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t";
  143. #ifdef BIND9
  144. struct dns_dumpctx {
  145. unsigned int magic;
  146. isc_mem_t *mctx;
  147. isc_mutex_t lock;
  148. unsigned int references;
  149. isc_boolean_t canceled;
  150. isc_boolean_t first;
  151. isc_boolean_t do_date;
  152. isc_stdtime_t now;
  153. FILE *f;
  154. dns_db_t *db;
  155. dns_dbversion_t *version;
  156. dns_dbiterator_t *dbiter;
  157. dns_totext_ctx_t tctx;
  158. isc_task_t *task;
  159. dns_dumpdonefunc_t done;
  160. void *done_arg;
  161. unsigned int nodes;
  162. /* dns_master_dumpinc() */
  163. char *file;
  164. char *tmpfile;
  165. dns_masterformat_t format;
  166. isc_result_t (*dumpsets)(isc_mem_t *mctx, dns_name_t *name,
  167. dns_rdatasetiter_t *rdsiter,
  168. dns_totext_ctx_t *ctx,
  169. isc_buffer_t *buffer, FILE *f);
  170. };
  171. #endif /* BIND9 */
  172. #define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
  173. /*%
  174. * Output tabs and spaces to go from column '*current' to
  175. * column 'to', and update '*current' to reflect the new
  176. * current column.
  177. */
  178. static isc_result_t
  179. indent(unsigned int *current, unsigned int to, int tabwidth,
  180. isc_buffer_t *target)
  181. {
  182. isc_region_t r;
  183. unsigned char *p;
  184. unsigned int from;
  185. int ntabs, nspaces, t;
  186. from = *current;
  187. if (to < from + 1)
  188. to = from + 1;
  189. ntabs = to / tabwidth - from / tabwidth;
  190. if (ntabs < 0)
  191. ntabs = 0;
  192. if (ntabs > 0) {
  193. isc_buffer_availableregion(target, &r);
  194. if (r.length < (unsigned) ntabs)
  195. return (ISC_R_NOSPACE);
  196. p = r.base;
  197. t = ntabs;
  198. while (t) {
  199. int n = t;
  200. if (n > N_TABS)
  201. n = N_TABS;
  202. memcpy(p, tabs, n);
  203. p += n;
  204. t -= n;
  205. }
  206. isc_buffer_add(target, ntabs);
  207. from = (to / tabwidth) * tabwidth;
  208. }
  209. nspaces = to - from;
  210. INSIST(nspaces >= 0);
  211. isc_buffer_availableregion(target, &r);
  212. if (r.length < (unsigned) nspaces)
  213. return (ISC_R_NOSPACE);
  214. p = r.base;
  215. t = nspaces;
  216. while (t) {
  217. int n = t;
  218. if (n > N_SPACES)
  219. n = N_SPACES;
  220. memcpy(p, spaces, n);
  221. p += n;
  222. t -= n;
  223. }
  224. isc_buffer_add(target, nspaces);
  225. *current = to;
  226. return (ISC_R_SUCCESS);
  227. }
  228. static isc_result_t
  229. totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) {
  230. isc_result_t result;
  231. REQUIRE(style->tab_width != 0);
  232. ctx->style = *style;
  233. ctx->class_printed = ISC_FALSE;
  234. dns_fixedname_init(&ctx->origin_fixname);
  235. /*
  236. * Set up the line break string if needed.
  237. */
  238. if ((ctx->style.flags & DNS_STYLEFLAG_MULTILINE) != 0) {
  239. isc_buffer_t buf;
  240. isc_region_t r;
  241. unsigned int col = 0;
  242. isc_buffer_init(&buf, ctx->linebreak_buf,
  243. sizeof(ctx->linebreak_buf));
  244. isc_buffer_availableregion(&buf, &r);
  245. if (r.length < 1)
  246. return (DNS_R_TEXTTOOLONG);
  247. r.base[0] = '\n';
  248. isc_buffer_add(&buf, 1);
  249. result = indent(&col, ctx->style.rdata_column,
  250. ctx->style.tab_width, &buf);
  251. /*
  252. * Do not return ISC_R_NOSPACE if the line break string
  253. * buffer is too small, because that would just make
  254. * dump_rdataset() retry indefinitely with ever
  255. * bigger target buffers. That's a different buffer,
  256. * so it won't help. Use DNS_R_TEXTTOOLONG as a substitute.
  257. */
  258. if (result == ISC_R_NOSPACE)
  259. return (DNS_R_TEXTTOOLONG);
  260. if (result != ISC_R_SUCCESS)
  261. return (result);
  262. isc_buffer_availableregion(&buf, &r);
  263. if (r.length < 1)
  264. return (DNS_R_TEXTTOOLONG);
  265. r.base[0] = '\0';
  266. isc_buffer_add(&buf, 1);
  267. ctx->linebreak = ctx->linebreak_buf;
  268. } else {
  269. ctx->linebreak = NULL;
  270. }
  271. ctx->origin = NULL;
  272. ctx->neworigin = NULL;
  273. ctx->current_ttl = 0;
  274. ctx->current_ttl_valid = ISC_FALSE;
  275. return (ISC_R_SUCCESS);
  276. }
  277. #define INDENT_TO(col) \
  278. do { \
  279. if ((result = indent(&column, ctx->style.col, \
  280. ctx->style.tab_width, target)) \
  281. != ISC_R_SUCCESS) \
  282. return (result); \
  283. } while (0)
  284. static isc_result_t
  285. str_totext(const char *source, isc_buffer_t *target) {
  286. unsigned int l;
  287. isc_region_t region;
  288. isc_buffer_availableregion(target, &region);
  289. l = strlen(source);
  290. if (l > region.length)
  291. return (ISC_R_NOSPACE);
  292. memcpy(region.base, source, l);
  293. isc_buffer_add(target, l);
  294. return (ISC_R_SUCCESS);
  295. }
  296. static isc_result_t
  297. ncache_summary(dns_rdataset_t *rdataset, isc_boolean_t omit_final_dot,
  298. isc_buffer_t *target)
  299. {
  300. isc_result_t result = ISC_R_SUCCESS;
  301. dns_rdataset_t rds;
  302. dns_name_t name;
  303. dns_rdataset_init(&rds);
  304. dns_name_init(&name, NULL);
  305. do {
  306. dns_ncache_current(rdataset, &name, &rds);
  307. for (result = dns_rdataset_first(&rds);
  308. result == ISC_R_SUCCESS;
  309. result = dns_rdataset_next(&rds)) {
  310. CHECK(str_totext("; ", target));
  311. CHECK(dns_name_totext(&name, omit_final_dot, target));
  312. CHECK(str_totext(" ", target));
  313. CHECK(dns_rdatatype_totext(rds.type, target));
  314. if (rds.type == dns_rdatatype_rrsig) {
  315. CHECK(str_totext(" ", target));
  316. CHECK(dns_rdatatype_totext(rds.covers, target));
  317. CHECK(str_totext(" ...\n", target));
  318. } else {
  319. dns_rdata_t rdata = DNS_RDATA_INIT;
  320. dns_rdataset_current(&rds, &rdata);
  321. CHECK(str_totext(" ", target));
  322. CHECK(dns_rdata_tofmttext(&rdata, dns_rootname,
  323. 0, 0, " ", target));
  324. CHECK(str_totext("\n", target));
  325. }
  326. }
  327. dns_rdataset_disassociate(&rds);
  328. result = dns_rdataset_next(rdataset);
  329. } while (result == ISC_R_SUCCESS);
  330. if (result == ISC_R_NOMORE)
  331. result = ISC_R_SUCCESS;
  332. cleanup:
  333. if (dns_rdataset_isassociated(&rds))
  334. dns_rdataset_disassociate(&rds);
  335. return (result);
  336. }
  337. /*
  338. * Convert 'rdataset' to master file text format according to 'ctx',
  339. * storing the result in 'target'. If 'owner_name' is NULL, it
  340. * is omitted; otherwise 'owner_name' must be valid and have at least
  341. * one label.
  342. */
  343. static isc_result_t
  344. rdataset_totext(dns_rdataset_t *rdataset,
  345. dns_name_t *owner_name,
  346. dns_totext_ctx_t *ctx,
  347. isc_boolean_t omit_final_dot,
  348. isc_buffer_t *target)
  349. {
  350. isc_result_t result;
  351. unsigned int column;
  352. isc_boolean_t first = ISC_TRUE;
  353. isc_uint32_t current_ttl;
  354. isc_boolean_t current_ttl_valid;
  355. dns_rdatatype_t type;
  356. unsigned int type_start;
  357. REQUIRE(DNS_RDATASET_VALID(rdataset));
  358. rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
  359. result = dns_rdataset_first(rdataset);
  360. current_ttl = ctx->current_ttl;
  361. current_ttl_valid = ctx->current_ttl_valid;
  362. while (result == ISC_R_SUCCESS) {
  363. column = 0;
  364. /*
  365. * Owner name.
  366. */
  367. if (owner_name != NULL &&
  368. ! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0 &&
  369. !first))
  370. {
  371. unsigned int name_start = target->used;
  372. RETERR(dns_name_totext(owner_name,
  373. omit_final_dot,
  374. target));
  375. column += target->used - name_start;
  376. }
  377. /*
  378. * TTL.
  379. */
  380. if ((ctx->style.flags & DNS_STYLEFLAG_NO_TTL) == 0 &&
  381. !((ctx->style.flags & DNS_STYLEFLAG_OMIT_TTL) != 0 &&
  382. current_ttl_valid &&
  383. rdataset->ttl == current_ttl))
  384. {
  385. char ttlbuf[64];
  386. isc_region_t r;
  387. unsigned int length;
  388. INDENT_TO(ttl_column);
  389. length = snprintf(ttlbuf, sizeof(ttlbuf), "%u",
  390. rdataset->ttl);
  391. INSIST(length <= sizeof(ttlbuf));
  392. isc_buffer_availableregion(target, &r);
  393. if (r.length < length)
  394. return (ISC_R_NOSPACE);
  395. memcpy(r.base, ttlbuf, length);
  396. isc_buffer_add(target, length);
  397. column += length;
  398. /*
  399. * If the $TTL directive is not in use, the TTL we
  400. * just printed becomes the default for subsequent RRs.
  401. */
  402. if ((ctx->style.flags & DNS_STYLEFLAG_TTL) == 0) {
  403. current_ttl = rdataset->ttl;
  404. current_ttl_valid = ISC_TRUE;
  405. }
  406. }
  407. /*
  408. * Class.
  409. */
  410. if ((ctx->style.flags & DNS_STYLEFLAG_NO_CLASS) == 0 &&
  411. ((ctx->style.flags & DNS_STYLEFLAG_OMIT_CLASS) == 0 ||
  412. ctx->class_printed == ISC_FALSE))
  413. {
  414. unsigned int class_start;
  415. INDENT_TO(class_column);
  416. class_start = target->used;
  417. result = dns_rdataclass_totext(rdataset->rdclass,
  418. target);
  419. if (result != ISC_R_SUCCESS)
  420. return (result);
  421. column += (target->used - class_start);
  422. }
  423. /*
  424. * Type.
  425. */
  426. if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
  427. type = rdataset->covers;
  428. } else {
  429. type = rdataset->type;
  430. }
  431. INDENT_TO(type_column);
  432. type_start = target->used;
  433. if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
  434. RETERR(str_totext("\\-", target));
  435. result = dns_rdatatype_totext(type, target);
  436. if (result != ISC_R_SUCCESS)
  437. return (result);
  438. column += (target->used - type_start);
  439. /*
  440. * Rdata.
  441. */
  442. INDENT_TO(rdata_column);
  443. if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
  444. if (NXDOMAIN(rdataset))
  445. RETERR(str_totext(";-$NXDOMAIN\n", target));
  446. else
  447. RETERR(str_totext(";-$NXRRSET\n", target));
  448. /*
  449. * Print a summary of the cached records which make
  450. * up the negative response.
  451. */
  452. RETERR(ncache_summary(rdataset, omit_final_dot,
  453. target));
  454. break;
  455. } else {
  456. dns_rdata_t rdata = DNS_RDATA_INIT;
  457. isc_region_t r;
  458. dns_rdataset_current(rdataset, &rdata);
  459. RETERR(dns_rdata_tofmttext(&rdata,
  460. ctx->origin,
  461. ctx->style.flags,
  462. ctx->style.line_length -
  463. ctx->style.rdata_column,
  464. ctx->linebreak,
  465. target));
  466. isc_buffer_availableregion(target, &r);
  467. if (r.length < 1)
  468. return (ISC_R_NOSPACE);
  469. r.base[0] = '\n';
  470. isc_buffer_add(target, 1);
  471. }
  472. first = ISC_FALSE;
  473. result = dns_rdataset_next(rdataset);
  474. }
  475. if (result != ISC_R_NOMORE)
  476. return (result);
  477. /*
  478. * Update the ctx state to reflect what we just printed.
  479. * This is done last, only when we are sure we will return
  480. * success, because this function may be called multiple
  481. * times with increasing buffer sizes until it succeeds,
  482. * and failed attempts must not update the state prematurely.
  483. */
  484. ctx->class_printed = ISC_TRUE;
  485. ctx->current_ttl= current_ttl;
  486. ctx->current_ttl_valid = current_ttl_valid;
  487. return (ISC_R_SUCCESS);
  488. }
  489. /*
  490. * Print the name, type, and class of an empty rdataset,
  491. * such as those used to represent the question section
  492. * of a DNS message.
  493. */
  494. static isc_result_t
  495. question_totext(dns_rdataset_t *rdataset,
  496. dns_name_t *owner_name,
  497. dns_totext_ctx_t *ctx,
  498. isc_boolean_t omit_final_dot,
  499. isc_buffer_t *target)
  500. {
  501. unsigned int column;
  502. isc_result_t result;
  503. isc_region_t r;
  504. REQUIRE(DNS_RDATASET_VALID(rdataset));
  505. result = dns_rdataset_first(rdataset);
  506. REQUIRE(result == ISC_R_NOMORE);
  507. column = 0;
  508. /* Owner name */
  509. {
  510. unsigned int name_start = target->used;
  511. RETERR(dns_name_totext(owner_name,
  512. omit_final_dot,
  513. target));
  514. column += target->used - name_start;
  515. }
  516. /* Class */
  517. {
  518. unsigned int class_start;
  519. INDENT_TO(class_column);
  520. class_start = target->used;
  521. result = dns_rdataclass_totext(rdataset->rdclass, target);
  522. if (result != ISC_R_SUCCESS)
  523. return (result);
  524. column += (target->used - class_start);
  525. }
  526. /* Type */
  527. {
  528. unsigned int type_start;
  529. INDENT_TO(type_column);
  530. type_start = target->used;
  531. result = dns_rdatatype_totext(rdataset->type, target);
  532. if (result != ISC_R_SUCCESS)
  533. return (result);
  534. column += (target->used - type_start);
  535. }
  536. isc_buffer_availableregion(target, &r);
  537. if (r.length < 1)
  538. return (ISC_R_NOSPACE);
  539. r.base[0] = '\n';
  540. isc_buffer_add(target, 1);
  541. return (ISC_R_SUCCESS);
  542. }
  543. isc_result_t
  544. dns_rdataset_totext(dns_rdataset_t *rdataset,
  545. dns_name_t *owner_name,
  546. isc_boolean_t omit_final_dot,
  547. isc_boolean_t question,
  548. isc_buffer_t *target)
  549. {
  550. dns_totext_ctx_t ctx;
  551. isc_result_t result;
  552. result = totext_ctx_init(&dns_master_style_debug, &ctx);
  553. if (result != ISC_R_SUCCESS) {
  554. UNEXPECTED_ERROR(__FILE__, __LINE__,
  555. "could not set master file style");
  556. return (ISC_R_UNEXPECTED);
  557. }
  558. /*
  559. * The caller might want to give us an empty owner
  560. * name (e.g. if they are outputting into a master
  561. * file and this rdataset has the same name as the
  562. * previous one.)
  563. */
  564. if (dns_name_countlabels(owner_name) == 0)
  565. owner_name = NULL;
  566. if (question)
  567. return (question_totext(rdataset, owner_name, &ctx,
  568. omit_final_dot, target));
  569. else
  570. return (rdataset_totext(rdataset, owner_name, &ctx,
  571. omit_final_dot, target));
  572. }
  573. isc_result_t
  574. dns_master_rdatasettotext(dns_name_t *owner_name,
  575. dns_rdataset_t *rdataset,
  576. const dns_master_style_t *style,
  577. isc_buffer_t *target)
  578. {
  579. dns_totext_ctx_t ctx;
  580. isc_result_t result;
  581. result = totext_ctx_init(style, &ctx);
  582. if (result != ISC_R_SUCCESS) {
  583. UNEXPECTED_ERROR(__FILE__, __LINE__,
  584. "could not set master file style");
  585. return (ISC_R_UNEXPECTED);
  586. }
  587. return (rdataset_totext(rdataset, owner_name, &ctx,
  588. ISC_FALSE, target));
  589. }
  590. isc_result_t
  591. dns_master_questiontotext(dns_name_t *owner_name,
  592. dns_rdataset_t *rdataset,
  593. const dns_master_style_t *style,
  594. isc_buffer_t *target)
  595. {
  596. dns_totext_ctx_t ctx;
  597. isc_result_t result;
  598. result = totext_ctx_init(style, &ctx);
  599. if (result != ISC_R_SUCCESS) {
  600. UNEXPECTED_ERROR(__FILE__, __LINE__,
  601. "could not set master file style");
  602. return (ISC_R_UNEXPECTED);
  603. }
  604. return (question_totext(rdataset, owner_name, &ctx,
  605. ISC_FALSE, target));
  606. }
  607. #ifdef BIND9
  608. /*
  609. * Print an rdataset. 'buffer' is a scratch buffer, which must have been
  610. * dynamically allocated by the caller. It must be large enough to
  611. * hold the result from dns_ttl_totext(). If more than that is needed,
  612. * the buffer will be grown automatically.
  613. */
  614. static isc_result_t
  615. dump_rdataset(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset,
  616. dns_totext_ctx_t *ctx,
  617. isc_buffer_t *buffer, FILE *f)
  618. {
  619. isc_region_t r;
  620. isc_result_t result;
  621. REQUIRE(buffer->length > 0);
  622. /*
  623. * Output a $TTL directive if needed.
  624. */
  625. if ((ctx->style.flags & DNS_STYLEFLAG_TTL) != 0) {
  626. if (ctx->current_ttl_valid == ISC_FALSE ||
  627. ctx->current_ttl != rdataset->ttl)
  628. {
  629. if ((ctx->style.flags & DNS_STYLEFLAG_COMMENT) != 0)
  630. {
  631. isc_buffer_clear(buffer);
  632. result = dns_ttl_totext(rdataset->ttl,
  633. ISC_TRUE, buffer);
  634. INSIST(result == ISC_R_SUCCESS);
  635. isc_buffer_usedregion(buffer, &r);
  636. fprintf(f, "$TTL %u\t; %.*s\n", rdataset->ttl,
  637. (int) r.length, (char *) r.base);
  638. } else {
  639. fprintf(f, "$TTL %u\n", rdataset->ttl);
  640. }
  641. ctx->current_ttl = rdataset->ttl;
  642. ctx->current_ttl_valid = ISC_TRUE;
  643. }
  644. }
  645. isc_buffer_clear(buffer);
  646. /*
  647. * Generate the text representation of the rdataset into
  648. * the buffer. If the buffer is too small, grow it.
  649. */
  650. for (;;) {
  651. int newlength;
  652. void *newmem;
  653. result = rdataset_totext(rdataset, name, ctx,
  654. ISC_FALSE, buffer);
  655. if (result != ISC_R_NOSPACE)
  656. break;
  657. newlength = buffer->length * 2;
  658. newmem = isc_mem_get(mctx, newlength);
  659. if (newmem == NULL)
  660. return (ISC_R_NOMEMORY);
  661. isc_mem_put(mctx, buffer->base, buffer->length);
  662. isc_buffer_init(buffer, newmem, newlength);
  663. }
  664. if (result != ISC_R_SUCCESS)
  665. return (result);
  666. /*
  667. * Write the buffer contents to the master file.
  668. */
  669. isc_buffer_usedregion(buffer, &r);
  670. result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
  671. if (result != ISC_R_SUCCESS) {
  672. UNEXPECTED_ERROR(__FILE__, __LINE__,
  673. "master file write failed: %s",
  674. isc_result_totext(result));
  675. return (result);
  676. }
  677. return (ISC_R_SUCCESS);
  678. }
  679. /*
  680. * Define the order in which rdatasets should be printed in zone
  681. * files. We will print SOA and NS records before others, SIGs
  682. * immediately following the things they sign, and order everything
  683. * else by RR number. This is all just for aesthetics and
  684. * compatibility with buggy software that expects the SOA to be first;
  685. * the DNS specifications allow any order.
  686. */
  687. static int
  688. dump_order(const dns_rdataset_t *rds) {
  689. int t;
  690. int sig;
  691. if (rds->type == dns_rdatatype_rrsig) {
  692. t = rds->covers;
  693. sig = 1;
  694. } else {
  695. t = rds->type;
  696. sig = 0;
  697. }
  698. switch (t) {
  699. case dns_rdatatype_soa:
  700. t = 0;
  701. break;
  702. case dns_rdatatype_ns:
  703. t = 1;
  704. break;
  705. default:
  706. t += 2;
  707. break;
  708. }
  709. return (t << 1) + sig;
  710. }
  711. static int
  712. dump_order_compare(const void *a, const void *b) {
  713. return (dump_order(*((const dns_rdataset_t * const *) a)) -
  714. dump_order(*((const dns_rdataset_t * const *) b)));
  715. }
  716. /*
  717. * Dump all the rdatasets of a domain name to a master file. We make
  718. * a "best effort" attempt to sort the RRsets in a nice order, but if
  719. * there are more than MAXSORT RRsets, we punt and only sort them in
  720. * groups of MAXSORT. This is not expected to ever happen in practice
  721. * since much less than 64 RR types have been registered with the
  722. * IANA, so far, and the output will be correct (though not
  723. * aesthetically pleasing) even if it does happen.
  724. */
  725. #define MAXSORT 64
  726. static isc_result_t
  727. dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name,
  728. dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
  729. isc_buffer_t *buffer, FILE *f)
  730. {
  731. isc_result_t itresult, dumpresult;
  732. isc_region_t r;
  733. dns_rdataset_t rdatasets[MAXSORT];
  734. dns_rdataset_t *sorted[MAXSORT];
  735. int i, n;
  736. itresult = dns_rdatasetiter_first(rdsiter);
  737. dumpresult = ISC_R_SUCCESS;
  738. if (itresult == ISC_R_SUCCESS && ctx->neworigin != NULL) {
  739. isc_buffer_clear(buffer);
  740. itresult = dns_name_totext(ctx->neworigin, ISC_FALSE, buffer);
  741. RUNTIME_CHECK(itresult == ISC_R_SUCCESS);
  742. isc_buffer_usedregion(buffer, &r);
  743. fprintf(f, "$ORIGIN %.*s\n", (int) r.length, (char *) r.base);
  744. ctx->neworigin = NULL;
  745. }
  746. again:
  747. for (i = 0;
  748. itresult == ISC_R_SUCCESS && i < MAXSORT;
  749. itresult = dns_rdatasetiter_next(rdsiter), i++) {
  750. dns_rdataset_init(&rdatasets[i]);
  751. dns_rdatasetiter_current(rdsiter, &rdatasets[i]);
  752. sorted[i] = &rdatasets[i];
  753. }
  754. n = i;
  755. INSIST(n <= MAXSORT);
  756. qsort(sorted, n, sizeof(sorted[0]), dump_order_compare);
  757. for (i = 0; i < n; i++) {
  758. dns_rdataset_t *rds = sorted[i];
  759. if (ctx->style.flags & DNS_STYLEFLAG_TRUST)
  760. fprintf(f, "; %s\n", dns_trust_totext(rds->trust));
  761. if (((rds->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
  762. (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
  763. /* Omit negative cache entries */
  764. } else {
  765. isc_result_t result =
  766. dump_rdataset(mctx, name, rds, ctx,
  767. buffer, f);
  768. if (result != ISC_R_SUCCESS)
  769. dumpresult = result;
  770. if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0)
  771. name = NULL;
  772. }
  773. if (ctx->style.flags & DNS_STYLEFLAG_RESIGN &&
  774. rds->attributes & DNS_RDATASETATTR_RESIGN) {
  775. isc_buffer_t b;
  776. char buf[sizeof("YYYYMMDDHHMMSS")];
  777. memset(buf, 0, sizeof(buf));
  778. isc_buffer_init(&b, buf, sizeof(buf) - 1);
  779. dns_time64_totext((isc_uint64_t)rds->resign, &b);
  780. fprintf(f, "; resign=%s\n", buf);
  781. }
  782. dns_rdataset_disassociate(rds);
  783. }
  784. if (dumpresult != ISC_R_SUCCESS)
  785. return (dumpresult);
  786. /*
  787. * If we got more data than could be sorted at once,
  788. * go handle the rest.
  789. */
  790. if (itresult == ISC_R_SUCCESS)
  791. goto again;
  792. if (itresult == ISC_R_NOMORE)
  793. itresult = ISC_R_SUCCESS;
  794. return (itresult);
  795. }
  796. /*
  797. * Dump given RRsets in the "raw" format.
  798. */
  799. static isc_result_t
  800. dump_rdataset_raw(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset,
  801. isc_buffer_t *buffer, FILE *f)
  802. {
  803. isc_result_t result;
  804. isc_uint32_t totallen;
  805. isc_uint16_t dlen;
  806. isc_region_t r, r_hdr;
  807. REQUIRE(buffer->length > 0);
  808. REQUIRE(DNS_RDATASET_VALID(rdataset));
  809. rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
  810. restart:
  811. totallen = 0;
  812. result = dns_rdataset_first(rdataset);
  813. REQUIRE(result == ISC_R_SUCCESS);
  814. isc_buffer_clear(buffer);
  815. /*
  816. * Common header and owner name (length followed by name)
  817. * These fields should be in a moderate length, so we assume we
  818. * can store all of them in the initial buffer.
  819. */
  820. isc_buffer_availableregion(buffer, &r_hdr);
  821. INSIST(r_hdr.length >= sizeof(dns_masterrawrdataset_t));
  822. isc_buffer_putuint32(buffer, totallen); /* XXX: leave space */
  823. isc_buffer_putuint16(buffer, rdataset->rdclass); /* 16-bit class */
  824. isc_buffer_putuint16(buffer, rdataset->type); /* 16-bit type */
  825. isc_buffer_putuint16(buffer, rdataset->covers); /* same as type */
  826. isc_buffer_putuint32(buffer, rdataset->ttl); /* 32-bit TTL */
  827. isc_buffer_putuint32(buffer, dns_rdataset_count(rdataset));
  828. totallen = isc_buffer_usedlength(buffer);
  829. INSIST(totallen <= sizeof(dns_masterrawrdataset_t));
  830. dns_name_toregion(name, &r);
  831. INSIST(isc_buffer_availablelength(buffer) >=
  832. (sizeof(dlen) + r.length));
  833. dlen = (isc_uint16_t)r.length;
  834. isc_buffer_putuint16(buffer, dlen);
  835. isc_buffer_copyregion(buffer, &r);
  836. totallen += sizeof(dlen) + r.length;
  837. do {
  838. dns_rdata_t rdata = DNS_RDATA_INIT;
  839. isc_region_t r;
  840. dns_rdataset_current(rdataset, &rdata);
  841. dns_rdata_toregion(&rdata, &r);
  842. INSIST(r.length <= 0xffffU);
  843. dlen = (isc_uint16_t)r.length;
  844. /*
  845. * Copy the rdata into the buffer. If the buffer is too small,
  846. * grow it. This should be rare, so we'll simply restart the
  847. * entire procedure (or should we copy the old data and
  848. * continue?).
  849. */
  850. if (isc_buffer_availablelength(buffer) <
  851. sizeof(dlen) + r.length) {
  852. int newlength;
  853. void *newmem;
  854. newlength = buffer->length * 2;
  855. newmem = isc_mem_get(mctx, newlength);
  856. if (newmem == NULL)
  857. return (ISC_R_NOMEMORY);
  858. isc_mem_put(mctx, buffer->base, buffer->length);
  859. isc_buffer_init(buffer, newmem, newlength);
  860. goto restart;
  861. }
  862. isc_buffer_putuint16(buffer, dlen);
  863. isc_buffer_copyregion(buffer, &r);
  864. totallen += sizeof(dlen) + r.length;
  865. result = dns_rdataset_next(rdataset);
  866. } while (result == ISC_R_SUCCESS);
  867. if (result != ISC_R_NOMORE)
  868. return (result);
  869. /*
  870. * Fill in the total length field.
  871. * XXX: this is a bit tricky. Since we have already "used" the space
  872. * for the total length in the buffer, we first remember the entire
  873. * buffer length in the region, "rewind", and then write the value.
  874. */
  875. isc_buffer_usedregion(buffer, &r);
  876. isc_buffer_clear(buffer);
  877. isc_buffer_putuint32(buffer, totallen);
  878. INSIST(isc_buffer_usedlength(buffer) < totallen);
  879. /*
  880. * Write the buffer contents to the raw master file.
  881. */
  882. result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
  883. if (result != ISC_R_SUCCESS) {
  884. UNEXPECTED_ERROR(__FILE__, __LINE__,
  885. "raw master file write failed: %s",
  886. isc_result_totext(result));
  887. return (result);
  888. }
  889. return (result);
  890. }
  891. static isc_result_t
  892. dump_rdatasets_raw(isc_mem_t *mctx, dns_name_t *name,
  893. dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
  894. isc_buffer_t *buffer, FILE *f)
  895. {
  896. isc_result_t result;
  897. dns_rdataset_t rdataset;
  898. for (result = dns_rdatasetiter_first(rdsiter);
  899. result == ISC_R_SUCCESS;
  900. result = dns_rdatasetiter_next(rdsiter)) {
  901. dns_rdataset_init(&rdataset);
  902. dns_rdatasetiter_current(rdsiter, &rdataset);
  903. if (((rdataset.attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
  904. (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
  905. /* Omit negative cache entries */
  906. } else {
  907. result = dump_rdataset_raw(mctx, name, &rdataset,
  908. buffer, f);
  909. }
  910. dns_rdataset_disassociate(&rdataset);
  911. if (result != ISC_R_SUCCESS)
  912. return (result);
  913. }
  914. if (result == ISC_R_NOMORE)
  915. result = ISC_R_SUCCESS;
  916. return (result);
  917. }
  918. /*
  919. * Initial size of text conversion buffer. The buffer is used
  920. * for several purposes: converting origin names, rdatasets,
  921. * $DATE timestamps, and comment strings for $TTL directives.
  922. *
  923. * When converting rdatasets, it is dynamically resized, but
  924. * when converting origins, timestamps, etc it is not. Therefore,
  925. * the initial size must large enough to hold the longest possible
  926. * text representation of any domain name (for $ORIGIN).
  927. */
  928. static const int initial_buffer_length = 1200;
  929. static isc_result_t
  930. dumptostreaminc(dns_dumpctx_t *dctx);
  931. static void
  932. dumpctx_destroy(dns_dumpctx_t *dctx) {
  933. dctx->magic = 0;
  934. DESTROYLOCK(&dctx->lock);
  935. dns_dbiterator_destroy(&dctx->dbiter);
  936. if (dctx->version != NULL)
  937. dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
  938. dns_db_detach(&dctx->db);
  939. if (dctx->task != NULL)
  940. isc_task_detach(&dctx->task);
  941. if (dctx->file != NULL)
  942. isc_mem_free(dctx->mctx, dctx->file);
  943. if (dctx->tmpfile != NULL)
  944. isc_mem_free(dctx->mctx, dctx->tmpfile);
  945. isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx));
  946. }
  947. void
  948. dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target) {
  949. REQUIRE(DNS_DCTX_VALID(source));
  950. REQUIRE(target != NULL && *target == NULL);
  951. LOCK(&source->lock);
  952. INSIST(source->references > 0);
  953. source->references++;
  954. INSIST(source->references != 0); /* Overflow? */
  955. UNLOCK(&source->lock);
  956. *target = source;
  957. }
  958. void
  959. dns_dumpctx_detach(dns_dumpctx_t **dctxp) {
  960. dns_dumpctx_t *dctx;
  961. isc_boolean_t need_destroy = ISC_FALSE;
  962. REQUIRE(dctxp != NULL);
  963. dctx = *dctxp;
  964. REQUIRE(DNS_DCTX_VALID(dctx));
  965. *dctxp = NULL;
  966. LOCK(&dctx->lock);
  967. INSIST(dctx->references != 0);
  968. dctx->references--;
  969. if (dctx->references == 0)
  970. need_destroy = ISC_TRUE;
  971. UNLOCK(&dctx->lock);
  972. if (need_destroy)
  973. dumpctx_destroy(dctx);
  974. }
  975. dns_dbversion_t *
  976. dns_dumpctx_version(dns_dumpctx_t *dctx) {
  977. REQUIRE(DNS_DCTX_VALID(dctx));
  978. return (dctx->version);
  979. }
  980. dns_db_t *
  981. dns_dumpctx_db(dns_dumpctx_t *dctx) {
  982. REQUIRE(DNS_DCTX_VALID(dctx));
  983. return (dctx->db);
  984. }
  985. void
  986. dns_dumpctx_cancel(dns_dumpctx_t *dctx) {
  987. REQUIRE(DNS_DCTX_VALID(dctx));
  988. LOCK(&dctx->lock);
  989. dctx->canceled = ISC_TRUE;
  990. UNLOCK(&dctx->lock);
  991. }
  992. static isc_result_t
  993. closeandrename(FILE *f, isc_result_t result, const char *temp, const char *file)
  994. {
  995. isc_result_t tresult;
  996. isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS);
  997. if (result == ISC_R_SUCCESS)
  998. result = isc_stdio_sync(f);
  999. if (result != ISC_R_SUCCESS && logit) {
  1000. isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
  1001. DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
  1002. "dumping master file: %s: fsync: %s",
  1003. temp, isc_result_totext(result));
  1004. logit = ISC_FALSE;
  1005. }
  1006. tresult = isc_stdio_close(f);
  1007. if (result == ISC_R_SUCCESS)
  1008. result = tresult;
  1009. if (result != ISC_R_SUCCESS && logit) {
  1010. isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
  1011. DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
  1012. "dumping master file: %s: fclose: %s",
  1013. temp, isc_result_totext(result));
  1014. logit = ISC_FALSE;
  1015. }
  1016. if (result == ISC_R_SUCCESS)
  1017. result = isc_file_rename(temp, file);
  1018. else
  1019. (void)isc_file_remove(temp);
  1020. if (result != ISC_R_SUCCESS && logit) {
  1021. isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
  1022. DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
  1023. "dumping master file: rename: %s: %s",
  1024. file, isc_result_totext(result));
  1025. }
  1026. return (result);
  1027. }
  1028. static void
  1029. dump_quantum(isc_task_t *task, isc_event_t *event) {
  1030. isc_result_t result;
  1031. isc_result_t tresult;
  1032. dns_dumpctx_t *dctx;
  1033. REQUIRE(event != NULL);
  1034. dctx = event->ev_arg;
  1035. REQUIRE(DNS_DCTX_VALID(dctx));
  1036. if (dctx->canceled)
  1037. result = ISC_R_CANCELED;
  1038. else
  1039. result = dumptostreaminc(dctx);
  1040. if (result == DNS_R_CONTINUE) {
  1041. event->ev_arg = dctx;
  1042. isc_task_send(task, &event);
  1043. return;
  1044. }
  1045. if (dctx->file != NULL) {
  1046. tresult = closeandrename(dctx->f, result,
  1047. dctx->tmpfile, dctx->file);
  1048. if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
  1049. result = tresult;
  1050. }
  1051. (dctx->done)(dctx->done_arg, result);
  1052. isc_event_free(&event);
  1053. dns_dumpctx_detach(&dctx);
  1054. }
  1055. static isc_result_t
  1056. task_send(dns_dumpctx_t *dctx) {
  1057. isc_event_t *event;
  1058. event = isc_event_allocate(dctx->mctx, NULL, DNS_EVENT_DUMPQUANTUM,
  1059. dump_quantum, dctx, sizeof(*event));
  1060. if (event == NULL)
  1061. return (ISC_R_NOMEMORY);
  1062. isc_task_send(dctx->task, &event);
  1063. return (ISC_R_SUCCESS);
  1064. }
  1065. static isc_result_t
  1066. dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
  1067. const dns_master_style_t *style, FILE *f, dns_dumpctx_t **dctxp,
  1068. dns_masterformat_t format)
  1069. {
  1070. dns_dumpctx_t *dctx;
  1071. isc_result_t result;
  1072. unsigned int options;
  1073. dctx = isc_mem_get(mctx, sizeof(*dctx));
  1074. if (dctx == NULL)
  1075. return (ISC_R_NOMEMORY);
  1076. dctx->mctx = NULL;
  1077. dctx->f = f;
  1078. dctx->dbiter = NULL;
  1079. dctx->db = NULL;
  1080. dctx->version = NULL;
  1081. dctx->done = NULL;
  1082. dctx->done_arg = NULL;
  1083. dctx->task = NULL;
  1084. dctx->nodes = 0;
  1085. dctx->first = ISC_TRUE;
  1086. dctx->canceled = ISC_FALSE;
  1087. dctx->file = NULL;
  1088. dctx->tmpfile = NULL;
  1089. dctx->format = format;
  1090. switch (format) {
  1091. case dns_masterformat_text:
  1092. dctx->dumpsets = dump_rdatasets_text;
  1093. break;
  1094. case dns_masterformat_raw:
  1095. dctx->dumpsets = dump_rdatasets_raw;
  1096. break;
  1097. default:
  1098. INSIST(0);
  1099. break;
  1100. }
  1101. result = totext_ctx_init(style, &dctx->tctx);
  1102. if (result != ISC_R_SUCCESS) {
  1103. UNEXPECTED_ERROR(__FILE__, __LINE__,
  1104. "could not set master file style");
  1105. goto cleanup;
  1106. }
  1107. isc_stdtime_get(&dctx->now);
  1108. dns_db_attach(db, &dctx->db);
  1109. dctx->do_date = dns_db_iscache(dctx->db);
  1110. if (dctx->format == dns_masterformat_text &&
  1111. (dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) {
  1112. options = DNS_DB_RELATIVENAMES;
  1113. } else
  1114. options = 0;
  1115. result = dns_db_createiterator(dctx->db, options, &dctx->dbiter);
  1116. if (result != ISC_R_SUCCESS)
  1117. goto cleanup;
  1118. result = isc_mutex_init(&dctx->lock);
  1119. if (result != ISC_R_SUCCESS)
  1120. goto cleanup;
  1121. if (version != NULL)
  1122. dns_db_attachversion(dctx->db, version, &dctx->version);
  1123. else if (!dns_db_iscache(db))
  1124. dns_db_currentversion(dctx->db, &dctx->version);
  1125. isc_mem_attach(mctx, &dctx->mctx);
  1126. dctx->references = 1;
  1127. dctx->magic = DNS_DCTX_MAGIC;
  1128. *dctxp = dctx;
  1129. return (ISC_R_SUCCESS);
  1130. cleanup:
  1131. if (dctx->dbiter != NULL)
  1132. dns_dbiterator_destroy(&dctx->dbiter);
  1133. if (dctx->db != NULL)
  1134. dns_db_detach(&dctx->db);
  1135. if (dctx != NULL)
  1136. isc_mem_put(mctx, dctx, sizeof(*dctx));
  1137. return (result);
  1138. }
  1139. static isc_result_t
  1140. dumptostreaminc(dns_dumpctx_t *dctx) {
  1141. isc_result_t result;
  1142. isc_buffer_t buffer;
  1143. char *bufmem;
  1144. isc_region_t r;
  1145. dns_name_t *name;
  1146. dns_fixedname_t fixname;
  1147. unsigned int nodes;
  1148. dns_masterrawheader_t rawheader;
  1149. isc_uint32_t now32;
  1150. isc_time_t start;
  1151. bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
  1152. if (bufmem == NULL)
  1153. return (ISC_R_NOMEMORY);
  1154. isc_buffer_init(&buffer, bufmem, initial_buffer_length);
  1155. dns_fixedname_init(&fixname);
  1156. name = dns_fixedname_name(&fixname);
  1157. if (dctx->first) {
  1158. switch (dctx->format) {
  1159. case dns_masterformat_text:
  1160. /*
  1161. * If the database has cache semantics, output an
  1162. * RFC2540 $DATE directive so that the TTLs can be
  1163. * adjusted when it is reloaded. For zones it is not
  1164. * really needed, and it would make the file
  1165. * incompatible with pre-RFC2540 software, so we omit
  1166. * it in the zone case.
  1167. */
  1168. if (dctx->do_date) {
  1169. result = dns_time32_totext(dctx->now, &buffer);
  1170. RUNTIME_CHECK(result == ISC_R_SUCCESS);
  1171. isc_buffer_usedregion(&buffer, &r);
  1172. fprintf(dctx->f, "$DATE %.*s\n",
  1173. (int) r.length, (char *) r.base);
  1174. }
  1175. break;
  1176. case dns_masterformat_raw:
  1177. r.base = (unsigned char *)&rawheader;
  1178. r.length = sizeof(rawheader);
  1179. isc_buffer_region(&buffer, &r);
  1180. isc_buffer_putuint32(&buffer, dns_masterformat_raw);
  1181. isc_buffer_putuint32(&buffer, DNS_RAWFORMAT_VERSION);
  1182. #if !defined(STDTIME_ON_32BITS) || (STDTIME_ON_32BITS + 0) != 1
  1183. /*
  1184. * We assume isc_stdtime_t is a 32-bit integer,
  1185. * which should be the case on most cases.
  1186. * If it turns out to be uncommon, we'll need
  1187. * to bump the version number and revise the
  1188. * header format.
  1189. */
  1190. isc_log_write(dns_lctx,
  1191. ISC_LOGCATEGORY_GENERAL,
  1192. DNS_LOGMODULE_MASTERDUMP,
  1193. ISC_LOG_INFO,
  1194. "dumping master file in raw "
  1195. "format: stdtime is not 32bits");
  1196. now32 = 0;
  1197. #else
  1198. now32 = dctx->now;
  1199. #endif
  1200. isc_buffer_putuint32(&buffer, now32);
  1201. INSIST(isc_buffer_usedlength(&buffer) <=
  1202. sizeof(rawheader));
  1203. result = isc_stdio_write(buffer.base, 1,
  1204. isc_buffer_usedlength(&buffer),
  1205. dctx->f, NULL);
  1206. if (result != ISC_R_SUCCESS)
  1207. return (result);
  1208. isc_buffer_clear(&buffer);
  1209. break;
  1210. default:
  1211. INSIST(0);
  1212. }
  1213. result = dns_dbiterator_first(dctx->dbiter);
  1214. dctx->first = ISC_FALSE;
  1215. } else
  1216. result = ISC_R_SUCCESS;
  1217. nodes = dctx->nodes;
  1218. isc_time_now(&start);
  1219. while (result == ISC_R_SUCCESS && (dctx->nodes == 0 || nodes--)) {
  1220. dns_rdatasetiter_t *rdsiter = NULL;
  1221. dns_dbnode_t *node = NULL;
  1222. result = dns_dbiterator_current(dctx->dbiter, &node, name);
  1223. if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
  1224. break;
  1225. if (result == DNS_R_NEWORIGIN) {
  1226. dns_name_t *origin =
  1227. dns_fixedname_name(&dctx->tctx.origin_fixname);
  1228. result = dns_dbiterator_origin(dctx->dbiter, origin);
  1229. RUNTIME_CHECK(result == ISC_R_SUCCESS);
  1230. if ((dctx->tctx.style.flags & DNS_STYLEFLAG_REL_DATA) != 0)
  1231. dctx->tctx.origin = origin;
  1232. dctx->tctx.neworigin = origin;
  1233. }
  1234. result = dns_db_allrdatasets(dctx->db, node, dctx->version,
  1235. dctx->now, &rdsiter);
  1236. if (result != ISC_R_SUCCESS) {
  1237. dns_db_detachnode(dctx->db, &node);
  1238. goto fail;
  1239. }
  1240. result = (dctx->dumpsets)(dctx->mctx, name, rdsiter,
  1241. &dctx->tctx, &buffer, dctx->f);
  1242. dns_rdatasetiter_destroy(&rdsiter);
  1243. if (result != ISC_R_SUCCESS) {
  1244. dns_db_detachnode(dctx->db, &node);
  1245. goto fail;
  1246. }
  1247. dns_db_detachnode(dctx->db, &node);
  1248. result = dns_dbiterator_next(dctx->dbiter);
  1249. }
  1250. /*
  1251. * Work out how many nodes can be written in the time between
  1252. * two requests to the nameserver. Smooth the resulting number and
  1253. * use it as a estimate for the number of nodes to be written in the
  1254. * next iteration.
  1255. */
  1256. if (dctx->nodes != 0 && result == ISC_R_SUCCESS) {
  1257. unsigned int pps = dns_pps; /* packets per second */
  1258. unsigned int interval;
  1259. isc_uint64_t usecs;
  1260. isc_time_t end;
  1261. isc_time_now(&end);
  1262. if (pps < 100)
  1263. pps = 100;
  1264. interval = 1000000 / pps; /* interval in usecs */
  1265. if (interval == 0)
  1266. interval = 1;
  1267. usecs = isc_time_microdiff(&end, &start);
  1268. if (usecs == 0) {
  1269. dctx->nodes = dctx->nodes * 2;
  1270. if (dctx->nodes > 1000)
  1271. dctx->nodes = 1000;
  1272. } else {
  1273. nodes = dctx->nodes * interval;
  1274. nodes /= (unsigned int)usecs;
  1275. if (nodes == 0)
  1276. nodes = 1;
  1277. else if (nodes > 1000)
  1278. nodes = 1000;
  1279. /* Smooth and assign. */
  1280. dctx->nodes = (nodes + dctx->nodes * 7) / 8;
  1281. isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
  1282. DNS_LOGMODULE_MASTERDUMP,
  1283. ISC_LOG_DEBUG(1),
  1284. "dumptostreaminc(%p) new nodes -> %d\n",
  1285. dctx, dctx->nodes);
  1286. }
  1287. result = DNS_R_CONTINUE;
  1288. } else if (result == ISC_R_NOMORE)
  1289. result = ISC_R_SUCCESS;
  1290. fail:
  1291. RUNTIME_CHECK(dns_dbiterator_pause(dctx->dbiter) == ISC_R_SUCCESS);
  1292. isc_mem_put(dctx->mctx, buffer.base, buffer.length);
  1293. return (result);
  1294. }
  1295. isc_result_t
  1296. dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db,
  1297. dns_dbversion_t *version,
  1298. const dns_master_style_t *style,
  1299. FILE *f, isc_task_t *task,
  1300. dns_dumpdonefunc_t done, void *done_arg,
  1301. dns_dumpctx_t **dctxp)
  1302. {
  1303. dns_dumpctx_t *dctx = NULL;
  1304. isc_result_t result;
  1305. REQUIRE(task != NULL);
  1306. REQUIRE(f != NULL);
  1307. REQUIRE(done != NULL);
  1308. result = dumpctx_create(mctx, db, version, style, f, &dctx,
  1309. dns_masterformat_text);
  1310. if (result != ISC_R_SUCCESS)
  1311. return (result);
  1312. isc_task_attach(task, &dctx->task);
  1313. dctx->done = done;
  1314. dctx->done_arg = done_arg;
  1315. dctx->nodes = 100;
  1316. result = task_send(dctx);
  1317. if (result == ISC_R_SUCCESS) {
  1318. dns_dumpctx_attach(dctx, dctxp);
  1319. return (DNS_R_CONTINUE);
  1320. }
  1321. dns_dumpctx_detach(&dctx);
  1322. return (result);
  1323. }
  1324. /*
  1325. * Dump an entire database into a master file.
  1326. */
  1327. isc_result_t
  1328. dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db,
  1329. dns_dbversion_t *version,
  1330. const dns_master_style_t *style,
  1331. FILE *f)
  1332. {
  1333. return (dns_master_dumptostream2(mctx, db, version, style,
  1334. dns_masterformat_text, f));
  1335. }
  1336. isc_result_t
  1337. dns_master_dumptostream2(isc_mem_t *mctx, dns_db_t *db,
  1338. dns_dbversion_t *version,
  1339. const dns_master_style_t *style,
  1340. dns_masterformat_t format, FILE *f)
  1341. {
  1342. dns_dumpctx_t *dctx = NULL;
  1343. isc_result_t result;
  1344. result = dumpctx_create(mctx, db, version, style, f, &dctx, format);
  1345. if (result != ISC_R_SUCCESS)
  1346. return (result);
  1347. result = dumptostreaminc(dctx);
  1348. INSIST(result != DNS_R_CONTINUE);
  1349. dns_dumpctx_detach(&dctx);
  1350. return (result);
  1351. }
  1352. static isc_result_t
  1353. opentmp(isc_mem_t *mctx, const char *file, char **tempp, FILE **fp) {
  1354. FILE *f = NULL;
  1355. isc_result_t result;
  1356. char *tempname = NULL;
  1357. int tempnamelen;
  1358. tempnamelen = strlen(file) + 20;
  1359. tempname = isc_mem_allocate(mctx, tempnamelen);
  1360. if (tempname == NULL)
  1361. return (ISC_R_NOMEMORY);
  1362. result = isc_file_mktemplate(file, tempname, tempnamelen);
  1363. if (result != ISC_R_SUCCESS)
  1364. goto cleanup;
  1365. result = isc_file_openunique(tempname, &f);
  1366. if (result != ISC_R_SUCCESS) {
  1367. isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
  1368. DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
  1369. "dumping master file: %s: open: %s",
  1370. tempname, isc_result_totext(result));
  1371. goto cleanup;
  1372. }
  1373. *tempp = tempname;
  1374. *fp = f;
  1375. return (ISC_R_SUCCESS);
  1376. cleanup:
  1377. isc_mem_free(mctx, tempname);
  1378. return (result);
  1379. }
  1380. isc_result_t
  1381. dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
  1382. const dns_master_style_t *style, const char *filename,
  1383. isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
  1384. dns_dumpctx_t **dctxp)
  1385. {
  1386. return (dns_master_dumpinc2(mctx, db, version, style, filename, task,
  1387. done, done_arg, dctxp,
  1388. dns_masterformat_text));
  1389. }
  1390. isc_result_t
  1391. dns_master_dumpinc2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
  1392. const dns_master_style_t *style, const char *filename,
  1393. isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
  1394. dns_dumpctx_t **dctxp, dns_masterformat_t format)
  1395. {
  1396. FILE *f = NULL;
  1397. isc_result_t result;
  1398. char *tempname = NULL;
  1399. char *file = NULL;
  1400. dns_dumpctx_t *dctx = NULL;
  1401. file = isc_mem_strdup(mctx, filename);
  1402. if (file == NULL)
  1403. return (ISC_R_NOMEMORY);
  1404. result = opentmp(mctx, filename, &tempname, &f);
  1405. if (result != ISC_R_SUCCESS)
  1406. goto cleanup;
  1407. result = dumpctx_create(mctx, db, version, style, f, &dctx, format);
  1408. if (result != ISC_R_SUCCESS) {
  1409. (void)isc_stdio_close(f);
  1410. (void)isc_file_remove(tempname);
  1411. goto cleanup;
  1412. }
  1413. isc_task_attach(task, &dctx->task);
  1414. dctx->done = done;
  1415. dctx->done_arg = done_arg;
  1416. dctx->nodes = 100;
  1417. dctx->file = file;
  1418. file = NULL;
  1419. dctx->tmpfile = tempname;
  1420. tempname = NULL;
  1421. result = task_send(dctx);
  1422. if (result == ISC_R_SUCCESS) {
  1423. dns_dumpctx_attach(dctx, dctxp);
  1424. return (DNS_R_CONTINUE);
  1425. }
  1426. cleanup:
  1427. if (dctx != NULL)
  1428. dns_dumpctx_detach(&dctx);
  1429. if (file != NULL)
  1430. isc_mem_free(mctx, file);
  1431. if (tempname != NULL)
  1432. isc_mem_free(mctx, tempname);
  1433. return (result);
  1434. }
  1435. isc_result_t
  1436. dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
  1437. const dns_master_style_t *style, const char *filename)
  1438. {
  1439. return (dns_master_dump2(mctx, db, version, style, filename,
  1440. dns_masterformat_text));
  1441. }
  1442. isc_result_t
  1443. dns_master_dump2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
  1444. const dns_master_style_t *style, const char *filename,
  1445. dns_masterformat_t format)
  1446. {
  1447. FILE *f = NULL;
  1448. isc_result_t result;
  1449. char *tempname;
  1450. dns_dumpctx_t *dctx = NULL;
  1451. result = opentmp(mctx, filename, &tempname, &f);
  1452. if (result != ISC_R_SUCCESS)
  1453. return (result);
  1454. result = dumpctx_create(mctx, db, version, style, f, &dctx, format);
  1455. if (result != ISC_R_SUCCESS)
  1456. goto cleanup;
  1457. result = dumptostreaminc(dctx);
  1458. INSIST(result != DNS_R_CONTINUE);
  1459. dns_dumpctx_detach(&dctx);
  1460. result = closeandrename(f, result, tempname, filename);
  1461. cleanup:
  1462. isc_mem_free(mctx, tempname);
  1463. return (result);
  1464. }
  1465. /*
  1466. * Dump a database node into a master file.
  1467. * XXX: this function assumes the text format.
  1468. */
  1469. isc_result_t
  1470. dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db,
  1471. dns_dbversion_t *version,
  1472. dns_dbnode_t *node, dns_name_t *name,
  1473. const dns_master_style_t *style,
  1474. FILE *f)
  1475. {
  1476. isc_result_t result;
  1477. isc_buffer_t buffer;
  1478. char *bufmem;
  1479. isc_stdtime_t now;
  1480. dns_totext_ctx_t ctx;
  1481. dns_rdatasetiter_t *rdsiter = NULL;
  1482. result = totext_ctx_init(style, &ctx);
  1483. if (result != ISC_R_SUCCESS) {
  1484. UNEXPECTED_ERROR(__FILE__, __LINE__,
  1485. "could not set master file style");
  1486. return (ISC_R_UNEXPECTED);
  1487. }
  1488. isc_stdtime_get(&now);
  1489. bufmem = isc_mem_get(mctx, initial_buffer_length);
  1490. if (bufmem == NULL)
  1491. return (ISC_R_NOMEMORY);
  1492. isc_buffer_init(&buffer, bufmem, initial_buffer_length);
  1493. result = dns_db_allrdatasets(db, node, version, now, &rdsiter);
  1494. if (result != ISC_R_SUCCESS)
  1495. goto failure;
  1496. result = dump_rdatasets_text(mctx, name, rdsiter, &ctx, &buffer, f);
  1497. if (result != ISC_R_SUCCESS)
  1498. goto failure;
  1499. dns_rdatasetiter_destroy(&rdsiter);
  1500. result = ISC_R_SUCCESS;
  1501. failure:
  1502. isc_mem_put(mctx, buffer.base, buffer.length);
  1503. return (result);
  1504. }
  1505. isc_result_t
  1506. dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
  1507. dns_dbnode_t *node, dns_name_t *name,
  1508. const dns_master_style_t *style, const char *filename)
  1509. {
  1510. FILE *f = NULL;
  1511. isc_result_t result;
  1512. result = isc_stdio_open(filename, "w", &f);
  1513. if (result != ISC_R_SUCCESS) {
  1514. isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
  1515. DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
  1516. "dumping node to file: %s: open: %s", filename,
  1517. isc_result_totext(result));
  1518. return (ISC_R_UNEXPECTED);
  1519. }
  1520. result = dns_master_dumpnodetostream(mctx, db, version, node, name,
  1521. style, f);
  1522. if (result != ISC_R_SUCCESS) {
  1523. isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
  1524. DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
  1525. "dumping master file: %s: dump: %s", filename,
  1526. isc_result_totext(result));
  1527. (void)isc_stdio_close(f);
  1528. return (ISC_R_UNEXPECTED);
  1529. }
  1530. result = isc_stdio_close(f);
  1531. if (result != ISC_R_SUCCESS) {
  1532. isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
  1533. DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
  1534. "dumping master file: %s: close: %s", filename,
  1535. isc_result_totext(result));
  1536. return (ISC_R_UNEXPECTED);
  1537. }
  1538. return (result);
  1539. }
  1540. #endif /* BIND9 */
  1541. isc_result_t
  1542. dns_master_stylecreate(dns_master_style_t **stylep, unsigned int flags,
  1543. unsigned int ttl_column, unsigned int class_column,
  1544. unsigned int type_column, unsigned int rdata_column,
  1545. unsigned int line_length, unsigned int tab_width,
  1546. isc_mem_t *mctx)
  1547. {
  1548. dns_master_style_t *style;
  1549. REQUIRE(stylep != NULL && *stylep == NULL);
  1550. style = isc_mem_get(mctx, sizeof(*style));
  1551. if (style == NULL)
  1552. return (ISC_R_NOMEMORY);
  1553. style->flags = flags;
  1554. style->ttl_column = ttl_column;
  1555. style->class_column = class_column;
  1556. style->type_column = type_column;
  1557. style->rdata_column = rdata_column;
  1558. style->line_length = line_length;
  1559. style->tab_width = tab_width;
  1560. *stylep = style;
  1561. return (ISC_R_SUCCESS);
  1562. }
  1563. void
  1564. dns_master_styledestroy(dns_master_style_t **stylep, isc_mem_t *mctx) {
  1565. dns_master_style_t *style;
  1566. REQUIRE(stylep != NULL && *stylep != NULL);
  1567. style = *stylep;
  1568. *stylep = NULL;
  1569. isc_mem_put(mctx, style, sizeof(*style));
  1570. }