1 /* $NetBSD: named-rrchecker.c,v 1.6 2022/09/23 12:15:26 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #include <stdbool.h> 17 #include <stdlib.h> 18 19 #include <isc/buffer.h> 20 #include <isc/commandline.h> 21 #include <isc/lex.h> 22 #include <isc/mem.h> 23 #include <isc/print.h> 24 #include <isc/string.h> 25 #include <isc/util.h> 26 27 #include <dns/fixedname.h> 28 #include <dns/name.h> 29 #include <dns/rdata.h> 30 #include <dns/rdataclass.h> 31 #include <dns/rdatatype.h> 32 #include <dns/result.h> 33 34 static isc_mem_t *mctx; 35 static isc_lex_t *lex; 36 37 static isc_lexspecials_t specials; 38 39 ISC_PLATFORM_NORETURN_PRE static void 40 usage(void) ISC_PLATFORM_NORETURN_POST; 41 42 static void 43 usage(void) { 44 fprintf(stderr, "usage: named-rrchecker [-o origin] [-hpCPTu]\n"); 45 fprintf(stderr, "\t-h: print this help message\n"); 46 fprintf(stderr, "\t-o origin: set origin to be used when " 47 "interpreting the record\n"); 48 fprintf(stderr, "\t-p: print the record in canonical format\n"); 49 fprintf(stderr, "\t-C: list the supported class names\n"); 50 fprintf(stderr, "\t-P: list the supported private type names\n"); 51 fprintf(stderr, "\t-T: list the supported standard type names\n"); 52 fprintf(stderr, "\t-u: print the record in unknown record format\n"); 53 exit(0); 54 } 55 56 ISC_PLATFORM_NORETURN_PRE static void 57 fatal(const char *format, ...) ISC_PLATFORM_NORETURN_POST; 58 59 static void 60 fatal(const char *format, ...) { 61 va_list args; 62 63 fprintf(stderr, "named-rrchecker: "); 64 va_start(args, format); 65 vfprintf(stderr, format, args); 66 va_end(args); 67 fputc('\n', stderr); 68 exit(1); 69 } 70 71 int 72 main(int argc, char *argv[]) { 73 isc_token_t token; 74 isc_result_t result; 75 int c; 76 unsigned int options = 0; 77 dns_rdatatype_t rdtype; 78 dns_rdataclass_t rdclass; 79 char text[256 * 1024]; 80 char data[64 * 1024]; 81 isc_buffer_t tbuf; 82 isc_buffer_t dbuf; 83 dns_rdata_t rdata = DNS_RDATA_INIT; 84 bool doexit = false; 85 bool once = false; 86 bool print = false; 87 bool unknown = false; 88 unsigned int t; 89 char *origin = NULL; 90 dns_fixedname_t fixed; 91 dns_name_t *name = NULL; 92 93 while ((c = isc_commandline_parse(argc, argv, "ho:puCPT")) != -1) { 94 switch (c) { 95 case 'o': 96 origin = isc_commandline_argument; 97 break; 98 99 case 'p': 100 print = true; 101 break; 102 103 case 'u': 104 unknown = true; 105 break; 106 107 case 'C': 108 for (t = 1; t <= 0xfeffu; t++) { 109 if (dns_rdataclass_ismeta(t)) { 110 continue; 111 } 112 dns_rdataclass_format(t, text, sizeof(text)); 113 if (strncmp(text, "CLASS", 4) != 0) { 114 fprintf(stdout, "%s\n", text); 115 } 116 } 117 exit(0); 118 119 case 'P': 120 for (t = 0xff00; t <= 0xfffeu; t++) { 121 if (dns_rdatatype_ismeta(t)) { 122 continue; 123 } 124 dns_rdatatype_format(t, text, sizeof(text)); 125 if (strncmp(text, "TYPE", 4) != 0) { 126 fprintf(stdout, "%s\n", text); 127 } 128 } 129 doexit = true; 130 break; 131 132 case 'T': 133 for (t = 1; t <= 0xfeffu; t++) { 134 if (dns_rdatatype_ismeta(t)) { 135 continue; 136 } 137 dns_rdatatype_format(t, text, sizeof(text)); 138 if (strncmp(text, "TYPE", 4) != 0) { 139 fprintf(stdout, "%s\n", text); 140 } 141 } 142 doexit = true; 143 break; 144 145 case '?': 146 case 'h': 147 /* Does not return. */ 148 usage(); 149 150 default: 151 fprintf(stderr, "%s: unhandled option -%c\n", argv[0], 152 isc_commandline_option); 153 exit(1); 154 } 155 } 156 if (doexit) { 157 exit(0); 158 } 159 160 isc_mem_create(&mctx); 161 RUNTIME_CHECK(isc_lex_create(mctx, 256, &lex) == ISC_R_SUCCESS); 162 163 /* 164 * Set up to lex DNS master file. 165 */ 166 167 specials['('] = 1; 168 specials[')'] = 1; 169 specials['"'] = 1; 170 isc_lex_setspecials(lex, specials); 171 options = ISC_LEXOPT_EOL; 172 isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE); 173 174 RUNTIME_CHECK(isc_lex_openstream(lex, stdin) == ISC_R_SUCCESS); 175 176 if (origin != NULL) { 177 name = dns_fixedname_initname(&fixed); 178 result = dns_name_fromstring(name, origin, 0, NULL); 179 if (result != ISC_R_SUCCESS) { 180 fatal("dns_name_fromstring: %s", 181 dns_result_totext(result)); 182 } 183 } 184 185 while ((result = isc_lex_gettoken(lex, options | ISC_LEXOPT_NUMBER, 186 &token)) == ISC_R_SUCCESS) 187 { 188 if (token.type == isc_tokentype_eof) { 189 break; 190 } 191 if (token.type == isc_tokentype_eol) { 192 continue; 193 } 194 if (once) { 195 fatal("extra data"); 196 } 197 /* 198 * Get class. 199 */ 200 if (token.type == isc_tokentype_number) { 201 rdclass = (dns_rdataclass_t)token.value.as_ulong; 202 if (token.value.as_ulong > 0xffffu) { 203 fatal("class value too big %lu", 204 token.value.as_ulong); 205 } 206 if (dns_rdataclass_ismeta(rdclass)) { 207 fatal("class %lu is a meta value", 208 token.value.as_ulong); 209 } 210 } else if (token.type == isc_tokentype_string) { 211 result = dns_rdataclass_fromtext( 212 &rdclass, &token.value.as_textregion); 213 if (result != ISC_R_SUCCESS) { 214 fatal("dns_rdataclass_fromtext: %s", 215 dns_result_totext(result)); 216 } 217 if (dns_rdataclass_ismeta(rdclass)) { 218 fatal("class %.*s(%d) is a meta value", 219 (int)token.value.as_textregion.length, 220 token.value.as_textregion.base, rdclass); 221 } 222 } else { 223 fatal("unexpected token %u", token.type); 224 } 225 226 result = isc_lex_gettoken(lex, options | ISC_LEXOPT_NUMBER, 227 &token); 228 if (result != ISC_R_SUCCESS) { 229 break; 230 } 231 if (token.type == isc_tokentype_eol) { 232 continue; 233 } 234 if (token.type == isc_tokentype_eof) { 235 break; 236 } 237 238 /* 239 * Get type. 240 */ 241 if (token.type == isc_tokentype_number) { 242 rdtype = (dns_rdatatype_t)token.value.as_ulong; 243 if (token.value.as_ulong > 0xffffu) { 244 fatal("type value too big %lu", 245 token.value.as_ulong); 246 } 247 if (dns_rdatatype_ismeta(rdtype)) { 248 fatal("type %lu is a meta value", 249 token.value.as_ulong); 250 } 251 } else if (token.type == isc_tokentype_string) { 252 result = dns_rdatatype_fromtext( 253 &rdtype, &token.value.as_textregion); 254 if (result != ISC_R_SUCCESS) { 255 fatal("dns_rdatatype_fromtext: %s", 256 dns_result_totext(result)); 257 } 258 if (dns_rdatatype_ismeta(rdtype)) { 259 fatal("type %.*s(%d) is a meta value", 260 (int)token.value.as_textregion.length, 261 token.value.as_textregion.base, rdtype); 262 } 263 } else { 264 fatal("unexpected token %u", token.type); 265 } 266 267 isc_buffer_init(&dbuf, data, sizeof(data)); 268 result = dns_rdata_fromtext(&rdata, rdclass, rdtype, lex, name, 269 0, mctx, &dbuf, NULL); 270 if (result != ISC_R_SUCCESS) { 271 fatal("dns_rdata_fromtext: %s", 272 dns_result_totext(result)); 273 } 274 once = true; 275 } 276 if (result != ISC_R_EOF) { 277 fatal("eof not found"); 278 } 279 if (!once) { 280 fatal("no records found"); 281 } 282 283 if (print) { 284 isc_buffer_init(&tbuf, text, sizeof(text)); 285 result = dns_rdataclass_totext(rdclass, &tbuf); 286 if (result != ISC_R_SUCCESS) { 287 fatal("dns_rdataclass_totext: %s", 288 dns_result_totext(result)); 289 } 290 isc_buffer_putstr(&tbuf, "\t"); 291 result = dns_rdatatype_totext(rdtype, &tbuf); 292 if (result != ISC_R_SUCCESS) { 293 fatal("dns_rdatatype_totext: %s", 294 dns_result_totext(result)); 295 } 296 isc_buffer_putstr(&tbuf, "\t"); 297 result = dns_rdata_totext(&rdata, NULL, &tbuf); 298 if (result != ISC_R_SUCCESS) { 299 fatal("dns_rdata_totext: %s", 300 dns_result_totext(result)); 301 } 302 303 printf("%.*s\n", (int)tbuf.used, (char *)tbuf.base); 304 fflush(stdout); 305 } 306 307 if (unknown) { 308 isc_buffer_init(&tbuf, text, sizeof(text)); 309 result = dns_rdataclass_tounknowntext(rdclass, &tbuf); 310 if (result != ISC_R_SUCCESS) { 311 fatal("dns_rdataclass_tounknowntext: %s", 312 dns_result_totext(result)); 313 } 314 isc_buffer_putstr(&tbuf, "\t"); 315 result = dns_rdatatype_tounknowntext(rdtype, &tbuf); 316 if (result != ISC_R_SUCCESS) { 317 fatal("dns_rdatatype_tounknowntext: %s", 318 dns_result_totext(result)); 319 } 320 isc_buffer_putstr(&tbuf, "\t"); 321 result = dns_rdata_tofmttext(&rdata, NULL, 322 DNS_STYLEFLAG_UNKNOWNFORMAT, 0, 0, 323 "", &tbuf); 324 if (result != ISC_R_SUCCESS) { 325 fatal("dns_rdata_tofmttext: %sn", 326 dns_result_totext(result)); 327 } 328 329 printf("%.*s\n", (int)tbuf.used, (char *)tbuf.base); 330 fflush(stdout); 331 } 332 333 isc_lex_close(lex); 334 isc_lex_destroy(&lex); 335 isc_mem_destroy(&mctx); 336 return (0); 337 } 338