1 /*	$NetBSD: named-rrchecker.c,v 1.1.1.3 2014/12/10 03:34:31 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <config.h>
20 
21 #include <stdlib.h>
22 
23 #include <isc/buffer.h>
24 #include <isc/commandline.h>
25 #include <isc/lex.h>
26 #include <isc/mem.h>
27 #include <isc/string.h>
28 #include <isc/util.h>
29 
30 #include <dns/fixedname.h>
31 #include <dns/name.h>
32 #include <dns/rdata.h>
33 #include <dns/rdataclass.h>
34 #include <dns/rdatatype.h>
35 #include <dns/result.h>
36 
37 static isc_mem_t *mctx;
38 static isc_lex_t *lex;
39 
40 static isc_lexspecials_t specials;
41 
42 static void
usage(void)43 usage(void) {
44 	fprintf(stderr, "usage: named-rrchecker [-o origin] [-hpCPT]\n");
45 	fprintf(stderr, "\t-h: print this help message\n");
46 	fprintf(stderr, "\t-o origin: set origin to be used when interpeting the record\n");
47 	fprintf(stderr, "\t-p: print the record in cannonical format\n");
48 	fprintf(stderr, "\t-C: list the supported class names\n");
49 	fprintf(stderr, "\t-T: list the supported standard type names\n");
50 	fprintf(stderr, "\t-P: list the supported private type names\n");
51 }
52 
53 int
main(int argc,char * argv[])54 main(int argc, char *argv[]) {
55 	isc_token_t token;
56 	isc_result_t result;
57 	int c;
58 	unsigned int options = 0;
59 	dns_rdatatype_t rdtype;
60 	dns_rdataclass_t rdclass;
61 	char text[256*1024];
62 	char data[64*1024];
63 	isc_buffer_t tbuf;
64 	isc_buffer_t dbuf;
65 	dns_rdata_t rdata = DNS_RDATA_INIT;
66 	isc_boolean_t doexit = ISC_FALSE;
67 	isc_boolean_t once = ISC_FALSE;
68 	isc_boolean_t print = ISC_FALSE;
69 	isc_boolean_t unknown = ISC_FALSE;
70 	unsigned int t;
71 	char *origin = NULL;
72 	dns_fixedname_t fixed;
73 	dns_name_t *name = NULL;
74 
75 	while ((c = isc_commandline_parse(argc, argv, "ho:puCPT")) != -1) {
76 		switch (c) {
77 		case '?':
78 		case 'h':
79 			if (isc_commandline_option != '?' &&
80 			    isc_commandline_option != 'h')
81 				fprintf(stderr, "%s: invalid argument -%c\n",
82 					argv[0], isc_commandline_option);
83 			usage();
84 			exit(1);
85 
86 		case 'o':
87 			origin = isc_commandline_argument;
88 			break;
89 
90 		case 'p':
91 			print = ISC_TRUE;
92 			break;
93 
94 		case 'u':
95 			unknown = ISC_TRUE;
96 			break;
97 
98 		case 'C':
99 			for (t = 1; t <= 0xfeffu; t++) {
100 				if (dns_rdataclass_ismeta(t))
101 					continue;
102 				dns_rdataclass_format(t, text, sizeof(text));
103 				if (strncmp(text, "CLASS", 4) != 0)
104 					fprintf(stdout, "%s\n", text);
105 			}
106 			exit(0);
107 
108 		case 'P':
109 			for (t = 0xff00; t <= 0xfffeu; t++) {
110 				if (dns_rdatatype_ismeta(t))
111 					continue;
112 				dns_rdatatype_format(t, text, sizeof(text));
113 				if (strncmp(text, "TYPE", 4) != 0)
114 					fprintf(stdout, "%s\n", text);
115 			}
116 			doexit = ISC_TRUE;
117 			break;
118 
119 		case 'T':
120 			for (t = 1; t <= 0xfeffu; t++) {
121 				if (dns_rdatatype_ismeta(t))
122 					continue;
123 				dns_rdatatype_format(t, text, sizeof(text));
124 				if (strncmp(text, "TYPE", 4) != 0)
125 					fprintf(stdout, "%s\n", text);
126 			}
127 			doexit = ISC_TRUE;
128 			break;
129 		}
130 	}
131 	if (doexit)
132 		exit(0);
133 
134 	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
135 	RUNTIME_CHECK(isc_lex_create(mctx, 256, &lex) == ISC_R_SUCCESS);
136 
137 	/*
138 	 * Set up to lex DNS master file.
139 	 */
140 
141 	specials['('] = 1;
142 	specials[')'] = 1;
143 	specials['"'] = 1;
144 	isc_lex_setspecials(lex, specials);
145 	options = ISC_LEXOPT_EOL;
146 	isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
147 
148 	RUNTIME_CHECK(isc_lex_openstream(lex, stdin) == ISC_R_SUCCESS);
149 
150 	if (origin != NULL) {
151 		dns_fixedname_init(&fixed);
152 		name = dns_fixedname_name(&fixed);
153 		result = dns_name_fromstring(name, origin, 0, NULL);
154 		if (result != ISC_R_SUCCESS) {
155 			fprintf(stderr, "dns_name_fromstring: %s\n",
156 				dns_result_totext(result));
157 			fflush(stderr);
158 			exit(1);
159 		}
160 	}
161 
162 	while ((result = isc_lex_gettoken(lex, options | ISC_LEXOPT_NUMBER,
163 					  &token)) == ISC_R_SUCCESS) {
164 		if (token.type == isc_tokentype_eof)
165 			break;
166 		if (token.type == isc_tokentype_eol)
167 			continue;
168 		if (once) {
169 			fprintf(stderr, "extra data\n");
170 			exit(1);
171 		}
172 		/*
173 		 * Get class.
174 		 */
175 		if (token.type == isc_tokentype_number) {
176 			rdclass = (dns_rdataclass_t) token.value.as_ulong;
177 			if (token.value.as_ulong > 0xffffu) {
178 				fprintf(stderr, "class value too big %lu\n",
179 					token.value.as_ulong);
180 				fflush(stderr);
181 				exit(1);
182 			}
183 			if (dns_rdataclass_ismeta(rdclass)) {
184 				fprintf(stderr, "class %lu is a meta value\n",
185 					token.value.as_ulong);
186 				fflush(stderr);
187 				exit(1);
188 			}
189 		} else if (token.type == isc_tokentype_string) {
190 			result = dns_rdataclass_fromtext(&rdclass,
191 					&token.value.as_textregion);
192 			if (result != ISC_R_SUCCESS) {
193 				fprintf(stderr, "dns_rdataclass_fromtext: %s\n",
194 					dns_result_totext(result));
195 				fflush(stderr);
196 				exit(1);
197 			}
198 			if (dns_rdataclass_ismeta(rdclass)) {
199 				fprintf(stderr,
200 					"class %.*s(%d) is a meta value\n",
201 					(int)token.value.as_textregion.length,
202 					token.value.as_textregion.base, rdclass);
203 				fflush(stderr);
204 				exit(1);
205 			}
206 		} else {
207 			fprintf(stderr, "unexpected token %u\n", token.type);
208 			exit(1);
209 		}
210 
211 		result = isc_lex_gettoken(lex, options | ISC_LEXOPT_NUMBER,
212 					  &token);
213 		if (result != ISC_R_SUCCESS)
214 			break;
215 		if (token.type == isc_tokentype_eol)
216 			continue;
217 		if (token.type == isc_tokentype_eof)
218 			break;
219 
220 		/*
221 		 * Get type.
222 		 */
223 		if (token.type == isc_tokentype_number) {
224 			rdtype = (dns_rdatatype_t) token.value.as_ulong;
225 			if (token.value.as_ulong > 0xffffu) {
226 				fprintf(stderr, "type value too big %lu\n",
227 					token.value.as_ulong);
228 				exit(1);
229 			}
230 			if (dns_rdatatype_ismeta(rdtype)) {
231 				fprintf(stderr, "type %lu is a meta value\n",
232 					token.value.as_ulong);
233 				fflush(stderr);
234 				exit(1);
235 			}
236 		} else if (token.type == isc_tokentype_string) {
237 			result = dns_rdatatype_fromtext(&rdtype,
238 					&token.value.as_textregion);
239 			if (result != ISC_R_SUCCESS) {
240 				fprintf(stdout, "dns_rdatatype_fromtext: %s\n",
241 					dns_result_totext(result));
242 				fflush(stdout);
243 				exit(1);
244 			}
245 			if (dns_rdatatype_ismeta(rdtype)) {
246 				fprintf(stderr,
247 					"type %.*s(%d) is a meta value\n",
248 					(int)token.value.as_textregion.length,
249 					token.value.as_textregion.base, rdtype);
250 				fflush(stderr);
251 				exit(1);
252 			}
253 		} else {
254 			fprintf(stderr, "unexpected token %u\n", token.type);
255 			exit(1);
256 		}
257 
258 		isc_buffer_init(&dbuf, data, sizeof(data));
259 		result = dns_rdata_fromtext(&rdata, rdclass, rdtype, lex,
260 					    name, 0, mctx, &dbuf, NULL);
261 		if (result != ISC_R_SUCCESS) {
262 			fprintf(stderr, "dns_rdata_fromtext:  %s\n",
263 				dns_result_totext(result));
264 			fflush(stderr);
265 			exit(1);
266 		}
267 		once = ISC_TRUE;
268 	}
269 	if (result != ISC_R_EOF) {
270 		fprintf(stderr, "eof not found\n");
271 		exit(1);
272 	}
273 	if (!once) {
274 		fprintf(stderr, "no records found\n");
275 		exit(1);
276 	}
277 
278 	if (print) {
279 		isc_buffer_init(&tbuf, text, sizeof(text));
280 		result = dns_rdataclass_totext(rdclass, &tbuf);
281 		if (result != ISC_R_SUCCESS) {
282 			fprintf(stderr, "dns_rdataclass_totext: %s\n",
283 				dns_result_totext(result));
284 			fflush(stderr);
285 			exit(1);
286 		}
287 		isc_buffer_putstr(&tbuf, "\t");
288 		result = dns_rdatatype_totext(rdtype, &tbuf);
289 		if (result != ISC_R_SUCCESS) {
290 			fprintf(stderr, "dns_rdatatype_totext: %s\n",
291 				dns_result_totext(result));
292 			fflush(stderr);
293 			exit(1);
294 		}
295 		isc_buffer_putstr(&tbuf, "\t");
296 		result = dns_rdata_totext(&rdata, NULL, &tbuf);
297 		if (result != ISC_R_SUCCESS)
298 			fprintf(stderr, "dns_rdata_totext: %s\n",
299 				dns_result_totext(result));
300 		else
301 			fprintf(stdout, "%.*s\n", (int)tbuf.used,
302 				(char*)tbuf.base);
303 		fflush(stdout);
304 	}
305 
306 	if (unknown) {
307 		fprintf(stdout, "CLASS%u\tTYPE%u\t\\# %u", rdclass, rdtype,
308 			rdata.length);
309 		if (rdata.length != 0) {
310 			unsigned int i;
311 			fprintf(stdout, " ");
312 			for (i = 0; i < rdata.length; i++)
313 				fprintf(stdout, "%02x", rdata.data[i]);
314 		}
315 		fprintf(stdout, "\n");
316 	}
317 
318 	isc_lex_close(lex);
319 	isc_lex_destroy(&lex);
320 	isc_mem_destroy(&mctx);
321 	return (0);
322 }
323