1 /* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
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 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17 #include <inttypes.h>
18
19 #include "knot/dnssec/zone-nsec.h"
20 #include "knot/zone/zone-dump.h"
21 #include "libknot/libknot.h"
22
23 /*! \brief Size of auxiliary buffer. */
24 #define DUMP_BUF_LEN (70 * 1024)
25
26 /*! \brief Dump parameters. */
27 typedef struct {
28 FILE *file;
29 char *buf;
30 size_t buflen;
31 uint64_t rr_count;
32 bool dump_rrsig;
33 bool dump_nsec;
34 const knot_dname_t *origin;
35 const knot_dump_style_t *style;
36 const char *first_comment;
37 } dump_params_t;
38
apex_node_dump_text(zone_node_t * node,dump_params_t * params)39 static int apex_node_dump_text(zone_node_t *node, dump_params_t *params)
40 {
41 knot_rrset_t soa = node_rrset(node, KNOT_RRTYPE_SOA);
42 knot_dump_style_t soa_style = *params->style;
43
44 // Dump SOA record as a first.
45 if (!params->dump_nsec) {
46 int ret = knot_rrset_txt_dump(&soa, ¶ms->buf, ¶ms->buflen,
47 &soa_style);
48 if (ret < 0) {
49 return ret;
50 }
51 params->rr_count += soa.rrs.count;
52 fprintf(params->file, "%s", params->buf);
53 params->buf[0] = '\0';
54 }
55
56 // Dump other records.
57 for (uint16_t i = 0; i < node->rrset_count; i++) {
58 knot_rrset_t rrset = node_rrset_at(node, i);
59 switch (rrset.type) {
60 case KNOT_RRTYPE_NSEC:
61 continue;
62 case KNOT_RRTYPE_RRSIG:
63 continue;
64 case KNOT_RRTYPE_SOA:
65 continue;
66 default:
67 break;
68 }
69
70 int ret = knot_rrset_txt_dump(&rrset, ¶ms->buf, ¶ms->buflen,
71 params->style);
72 if (ret < 0) {
73 return ret;
74 }
75 params->rr_count += rrset.rrs.count;
76 fprintf(params->file, "%s", params->buf);
77 params->buf[0] = '\0';
78 }
79
80 return KNOT_EOK;
81 }
82
node_dump_text(zone_node_t * node,void * data)83 static int node_dump_text(zone_node_t *node, void *data)
84 {
85 dump_params_t *params = (dump_params_t *)data;
86
87 // Zone apex rrsets.
88 if (node->owner == params->origin && !params->dump_rrsig &&
89 !params->dump_nsec) {
90 apex_node_dump_text(node, params);
91 return KNOT_EOK;
92 }
93
94 // Dump non-apex rrsets.
95 for (uint16_t i = 0; i < node->rrset_count; i++) {
96 knot_rrset_t rrset = node_rrset_at(node, i);
97 switch (rrset.type) {
98 case KNOT_RRTYPE_RRSIG:
99 if (params->dump_rrsig) {
100 break;
101 }
102 continue;
103 case KNOT_RRTYPE_NSEC:
104 if (params->dump_nsec) {
105 break;
106 }
107 continue;
108 case KNOT_RRTYPE_NSEC3:
109 if (params->dump_nsec) {
110 break;
111 }
112 continue;
113 default:
114 if (params->dump_nsec || params->dump_rrsig) {
115 continue;
116 }
117 break;
118 }
119
120 // Dump block comment if available.
121 if (params->first_comment != NULL) {
122 fprintf(params->file, "%s", params->first_comment);
123 params->first_comment = NULL;
124 }
125
126 int ret = knot_rrset_txt_dump(&rrset, ¶ms->buf, ¶ms->buflen,
127 params->style);
128 if (ret < 0) {
129 return ret;
130 }
131 params->rr_count += rrset.rrs.count;
132 fprintf(params->file, "%s", params->buf);
133 params->buf[0] = '\0';
134 }
135
136 return KNOT_EOK;
137 }
138
zone_dump_text(zone_contents_t * zone,FILE * file,bool comments)139 int zone_dump_text(zone_contents_t *zone, FILE *file, bool comments)
140 {
141 if (file == NULL) {
142 return KNOT_EINVAL;
143 }
144
145 if (zone == NULL) {
146 return KNOT_EEMPTYZONE;
147 }
148
149 // Allocate auxiliary buffer for dumping operations.
150 char *buf = malloc(DUMP_BUF_LEN);
151 if (buf == NULL) {
152 return KNOT_ENOMEM;
153 }
154
155 if (comments) {
156 fprintf(file, ";; Zone dump (Knot DNS %s)\n", PACKAGE_VERSION);
157 }
158
159 // Set structure with parameters.
160 zone_node_t *apex = zone->apex;
161 dump_params_t params = {
162 .file = file,
163 .buf = buf,
164 .buflen = DUMP_BUF_LEN,
165 .rr_count = 0,
166 .origin = apex->owner,
167 .style = &KNOT_DUMP_STYLE_DEFAULT,
168 .dump_rrsig = false,
169 .dump_nsec = false
170 };
171
172 // Dump standard zone records without RRSIGS.
173 int ret = zone_contents_apply(zone, node_dump_text, ¶ms);
174 if (ret != KNOT_EOK) {
175 free(params.buf);
176 return ret;
177 }
178
179 // Dump RRSIG records if available.
180 params.dump_rrsig = true;
181 params.dump_nsec = false;
182 params.first_comment = comments ? ";; DNSSEC signatures\n" : NULL;
183 ret = zone_contents_apply(zone, node_dump_text, ¶ms);
184 if (ret != KNOT_EOK) {
185 free(params.buf);
186 return ret;
187 }
188
189 // Dump NSEC chain if available.
190 params.dump_rrsig = false;
191 params.dump_nsec = true;
192 params.first_comment = comments ? ";; DNSSEC NSEC chain\n" : NULL;
193 ret = zone_contents_apply(zone, node_dump_text, ¶ms);
194 if (ret != KNOT_EOK) {
195 free(params.buf);
196 return ret;
197 }
198
199 // Dump NSEC3 chain if available.
200 params.dump_rrsig = false;
201 params.dump_nsec = true;
202 params.first_comment = comments ? ";; DNSSEC NSEC3 chain\n" : NULL;
203 ret = zone_contents_nsec3_apply(zone, node_dump_text, ¶ms);
204 if (ret != KNOT_EOK) {
205 free(params.buf);
206 return ret;
207 }
208
209 params.dump_rrsig = true;
210 params.dump_nsec = false;
211 params.first_comment = comments ? ";; DNSSEC NSEC3 signatures\n" : NULL;
212 ret = zone_contents_nsec3_apply(zone, node_dump_text, ¶ms);
213 if (ret != KNOT_EOK) {
214 free(params.buf);
215 return ret;
216 }
217
218 if (comments) {
219 // Create formatted date-time string.
220 time_t now = time(NULL);
221 struct tm tm;
222 localtime_r(&now, &tm);
223 char date[64];
224 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S %Z", &tm);
225
226 // Dump trailing statistics.
227 fprintf(file, ";; Written %"PRIu64" records\n"
228 ";; Time %s\n",
229 params.rr_count, date);
230 }
231
232 free(params.buf); // params.buf may be != buf because of knot_rrset_txt_dump_dynamic()
233
234 return KNOT_EOK;
235 }
236