1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * SPDX-License-Identifier: MPL-2.0
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14 #include <stdlib.h>
15 #include <sys/param.h>
16 #include <sys/select.h>
17 #include <sys/time.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20
21 #include <isc/app.h>
22 #include <isc/commandline.h>
23 #include <isc/managers.h>
24 #include <isc/mem.h>
25 #include <isc/print.h>
26 #include <isc/socket.h>
27 #include <isc/string.h>
28 #include <isc/task.h>
29 #include <isc/timer.h>
30 #include <isc/util.h>
31
32 #include <dns/db.h>
33 #include <dns/fixedname.h>
34 #include <dns/rdataclass.h>
35 #include <dns/rdataset.h>
36 #include <dns/result.h>
37 #include <dns/zone.h>
38
39 static int debug = 0;
40 static int quiet = 0;
41 static int stats = 0;
42 static isc_mem_t *mctx = NULL;
43 dns_zone_t *zone = NULL;
44 isc_nm_t *netmgr = NULL;
45 isc_taskmgr_t *taskmgr = NULL;
46 isc_timermgr_t *timermgr = NULL;
47 isc_socketmgr_t *socketmgr = NULL;
48 dns_zonemgr_t *zonemgr = NULL;
49 dns_zonetype_t zonetype = dns_zone_primary;
50 isc_sockaddr_t addr;
51
52 #define ERRRET(result, function) \
53 do { \
54 if (result != ISC_R_SUCCESS) { \
55 fprintf(stderr, "%s() returned %s\n", function, \
56 dns_result_totext(result)); \
57 return; \
58 } \
59 } while (0)
60
61 #define ERRCONT(result, function) \
62 if (result != ISC_R_SUCCESS) { \
63 fprintf(stderr, "%s() returned %s\n", function, \
64 dns_result_totext(result)); \
65 continue; \
66 } else \
67 (void)NULL
68
69 static void
usage(void)70 usage(void) {
71 fprintf(stderr, "usage: zone_test [-dqsSM] [-c class] [-f file] "
72 "zone\n");
73 exit(1);
74 }
75
76 static void
setup(const char * zonename,const char * filename,const char * classname)77 setup(const char *zonename, const char *filename, const char *classname) {
78 isc_result_t result;
79 dns_rdataclass_t rdclass;
80 isc_consttextregion_t region;
81 isc_buffer_t buffer;
82 dns_fixedname_t fixorigin;
83 dns_name_t *origin;
84 const char *rbt = "rbt";
85
86 if (debug) {
87 fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
88 zonename, filename, classname);
89 }
90 result = dns_zone_create(&zone, mctx);
91 ERRRET(result, "dns_zone_new");
92
93 dns_zone_settype(zone, zonetype);
94
95 isc_buffer_constinit(&buffer, zonename, strlen(zonename));
96 isc_buffer_add(&buffer, strlen(zonename));
97 dns_fixedname_init(&fixorigin);
98 result = dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer,
99 dns_rootname, 0, NULL);
100 ERRRET(result, "dns_name_fromtext");
101 origin = dns_fixedname_name(&fixorigin);
102
103 result = dns_zone_setorigin(zone, origin);
104 ERRRET(result, "dns_zone_setorigin");
105
106 dns_zone_setdbtype(zone, 1, &rbt);
107
108 result = dns_zone_setfile(zone, filename, dns_masterformat_text,
109 &dns_master_style_default);
110 ERRRET(result, "dns_zone_setfile");
111
112 region.base = classname;
113 region.length = strlen(classname);
114 result = dns_rdataclass_fromtext(&rdclass,
115 (isc_textregion_t *)(void *)®ion);
116 ERRRET(result, "dns_rdataclass_fromtext");
117
118 dns_zone_setclass(zone, rdclass);
119
120 if (zonetype == dns_zone_secondary) {
121 dns_zone_setprimaries(zone, &addr, 1);
122 }
123
124 result = dns_zone_load(zone, false);
125 ERRRET(result, "dns_zone_load");
126
127 result = dns_zonemgr_managezone(zonemgr, zone);
128 ERRRET(result, "dns_zonemgr_managezone");
129 }
130
131 static void
print_rdataset(dns_name_t * name,dns_rdataset_t * rdataset)132 print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset) {
133 isc_buffer_t text;
134 char t[1000];
135 isc_result_t result;
136 isc_region_t r;
137
138 isc_buffer_init(&text, t, sizeof(t));
139 result = dns_rdataset_totext(rdataset, name, false, false, &text);
140 isc_buffer_usedregion(&text, &r);
141 if (result == ISC_R_SUCCESS) {
142 printf("%.*s", (int)r.length, (char *)r.base);
143 } else {
144 printf("%s\n", dns_result_totext(result));
145 }
146 }
147
148 static void
query(void)149 query(void) {
150 char buf[1024];
151 dns_fixedname_t name;
152 dns_fixedname_t found;
153 dns_db_t *db;
154 isc_buffer_t buffer;
155 isc_result_t result;
156 dns_rdataset_t rdataset;
157 dns_rdataset_t sigset;
158 fd_set rfdset = { { 0 } };
159
160 db = NULL;
161 result = dns_zone_getdb(zone, &db);
162 if (result != ISC_R_SUCCESS) {
163 fprintf(stderr, "%s() returned %s\n", "dns_zone_getdb",
164 dns_result_totext(result));
165 return;
166 }
167
168 dns_fixedname_init(&found);
169 dns_rdataset_init(&rdataset);
170 dns_rdataset_init(&sigset);
171
172 do {
173 char *s;
174 fprintf(stdout, "zone_test ");
175 fflush(stdout);
176 FD_ZERO(&rfdset);
177 FD_SET(0, &rfdset);
178 select(1, &rfdset, NULL, NULL, NULL);
179 if (fgets(buf, sizeof(buf), stdin) == NULL) {
180 fprintf(stdout, "\n");
181 break;
182 }
183 buf[sizeof(buf) - 1] = '\0';
184
185 s = strchr(buf, '\n');
186 if (s != NULL) {
187 *s = '\0';
188 }
189 s = strchr(buf, '\r');
190 if (s != NULL) {
191 *s = '\0';
192 }
193 if (strcmp(buf, "dump") == 0) {
194 dns_zone_dumptostream(zone, stdout,
195 dns_masterformat_text,
196 &dns_master_style_default, 0);
197 continue;
198 }
199 if (strlen(buf) == 0U) {
200 continue;
201 }
202 dns_fixedname_init(&name);
203 isc_buffer_init(&buffer, buf, strlen(buf));
204 isc_buffer_add(&buffer, strlen(buf));
205 result = dns_name_fromtext(dns_fixedname_name(&name), &buffer,
206 dns_rootname, 0, NULL);
207 ERRCONT(result, "dns_name_fromtext");
208
209 result = dns_db_find(db, dns_fixedname_name(&name),
210 NULL /*version*/, dns_rdatatype_a,
211 0 /*options*/, 0 /*time*/, NULL /*nodep*/,
212 dns_fixedname_name(&found), &rdataset,
213 &sigset);
214 fprintf(stderr, "%s() returned %s\n", "dns_db_find",
215 dns_result_totext(result));
216 switch (result) {
217 case DNS_R_DELEGATION:
218 print_rdataset(dns_fixedname_name(&found), &rdataset);
219 break;
220 case ISC_R_SUCCESS:
221 print_rdataset(dns_fixedname_name(&name), &rdataset);
222 break;
223 default:
224 break;
225 }
226
227 if (dns_rdataset_isassociated(&rdataset)) {
228 dns_rdataset_disassociate(&rdataset);
229 }
230 if (dns_rdataset_isassociated(&sigset)) {
231 dns_rdataset_disassociate(&sigset);
232 }
233 } while (1);
234 dns_rdataset_invalidate(&rdataset);
235 dns_db_detach(&db);
236 }
237
238 int
main(int argc,char ** argv)239 main(int argc, char **argv) {
240 int c;
241 char *filename = NULL;
242 const char *classname = "IN";
243
244 while ((c = isc_commandline_parse(argc, argv, "cdf:m:qsMS")) != EOF) {
245 switch (c) {
246 case 'c':
247 classname = isc_commandline_argument;
248 break;
249 case 'd':
250 debug++;
251 break;
252 case 'f':
253 if (filename != NULL) {
254 usage();
255 }
256 filename = isc_commandline_argument;
257 break;
258 case 'm':
259 memset(&addr, 0, sizeof(addr));
260 addr.type.sin.sin_family = AF_INET;
261 if (inet_pton(AF_INET, isc_commandline_argument,
262 &addr.type.sin.sin_addr) != 1) {
263 fprintf(stderr, "bad master address '%s'\n",
264 isc_commandline_argument);
265 exit(1);
266 }
267 addr.type.sin.sin_port = htons(53);
268 break;
269 case 'q':
270 quiet++;
271 break;
272 case 's':
273 stats++;
274 break;
275 case 'S':
276 zonetype = dns_zone_secondary;
277 break;
278 case 'M':
279 zonetype = dns_zone_primary;
280 break;
281 default:
282 usage();
283 }
284 }
285
286 if (argv[isc_commandline_index] == NULL) {
287 usage();
288 }
289
290 RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS);
291 isc_mem_create(&mctx);
292 RUNTIME_CHECK(isc_managers_create(mctx, 2, 0, NULL, &taskmgr) ==
293 ISC_R_SUCCESS);
294 RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS);
295 RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS);
296 RUNTIME_CHECK(dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr,
297 &zonemgr) == ISC_R_SUCCESS);
298 if (filename == NULL) {
299 filename = argv[isc_commandline_index];
300 }
301 setup(argv[isc_commandline_index], filename, classname);
302 query();
303 if (zone != NULL) {
304 dns_zone_detach(&zone);
305 }
306 dns_zonemgr_shutdown(zonemgr);
307 dns_zonemgr_detach(&zonemgr);
308 isc_socketmgr_destroy(&socketmgr);
309 isc_managers_destroy(&netmgr, &taskmgr);
310 isc_timermgr_destroy(&timermgr);
311 if (!quiet && stats) {
312 isc_mem_stats(mctx, stdout);
313 }
314 isc_mem_destroy(&mctx);
315
316 return (0);
317 }
318