1/* $NetBSD$ */ 2 3/* 4 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2001 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20/* Id: wire_test.c,v 1.67 2007/06/19 23:46:59 tbox Exp */ 21 22#include <config.h> 23 24#include <stdlib.h> 25 26#include <isc/buffer.h> 27#include <isc/commandline.h> 28#include <isc/mem.h> 29#include <isc/string.h> 30#include <isc/util.h> 31 32#include <dns/result.h> 33 34#include "printmsg.h" 35 36int parseflags = 0; 37isc_mem_t *mctx; 38isc_boolean_t printmemstats = ISC_FALSE; 39isc_boolean_t dorender = ISC_FALSE; 40 41static void 42process_message(isc_buffer_t *source); 43 44static inline void 45CHECKRESULT(isc_result_t result, const char *msg) { 46 if (result != ISC_R_SUCCESS) { 47 printf("%s: %s\n", msg, dns_result_totext(result)); 48 49 exit(1); 50 } 51} 52 53static int 54fromhex(char c) { 55 if (c >= '0' && c <= '9') 56 return (c - '0'); 57 else if (c >= 'a' && c <= 'f') 58 return (c - 'a' + 10); 59 else if (c >= 'A' && c <= 'F') 60 return (c - 'A' + 10); 61 62 printf("bad input format: %02x\n", c); 63 exit(3); 64 /* NOTREACHED */ 65} 66 67static void 68usage(void) { 69 fprintf(stderr, "wire_test [-p] [-b] [-s] [-r]\n"); 70 fprintf(stderr, "\t-p\tPreserve order of the records in messages\n"); 71 fprintf(stderr, "\t-b\tBest-effort parsing (ignore some errors)\n"); 72 fprintf(stderr, "\t-s\tPrint memory statistics\n"); 73 fprintf(stderr, "\t-r\tAfter parsing, re-render the message\n"); 74 fprintf(stderr, "\t-t\tTCP mode - ignore the first 2 bytes\n"); 75} 76 77int 78main(int argc, char *argv[]) { 79 char *rp, *wp; 80 unsigned char *bp; 81 isc_buffer_t source; 82 size_t len, i; 83 int n; 84 FILE *f; 85 isc_boolean_t need_close = ISC_FALSE; 86 unsigned char b[64 * 1024]; 87 char s[4000]; 88 isc_boolean_t tcp = ISC_FALSE; 89 int ch; 90 91 mctx = NULL; 92 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); 93 94 while ((ch = isc_commandline_parse(argc, argv, "pbsrt")) != -1) { 95 switch (ch) { 96 case 'p': 97 parseflags |= DNS_MESSAGEPARSE_PRESERVEORDER; 98 break; 99 case 'b': 100 parseflags |= DNS_MESSAGEPARSE_BESTEFFORT; 101 break; 102 case 's': 103 printmemstats = ISC_TRUE; 104 break; 105 case 'r': 106 dorender = ISC_TRUE; 107 break; 108 case 't': 109 tcp = ISC_TRUE; 110 break; 111 default: 112 usage(); 113 exit(1); 114 } 115 } 116 117 argc -= isc_commandline_index; 118 argv += isc_commandline_index; 119 120 if (argc > 1) { 121 f = fopen(argv[1], "r"); 122 if (f == NULL) { 123 printf("fopen failed\n"); 124 exit(1); 125 } 126 need_close = ISC_TRUE; 127 } else 128 f = stdin; 129 130 bp = b; 131 while (fgets(s, sizeof(s), f) != NULL) { 132 rp = s; 133 wp = s; 134 len = 0; 135 while (*rp != '\0') { 136 if (*rp == '#') 137 break; 138 if (*rp != ' ' && *rp != '\t' && 139 *rp != '\r' && *rp != '\n') { 140 *wp++ = *rp; 141 len++; 142 } 143 rp++; 144 } 145 if (len == 0U) 146 break; 147 if (len % 2 != 0U) { 148 printf("bad input format: %lu\n", (unsigned long)len); 149 exit(1); 150 } 151 if (len > sizeof(b) * 2) { 152 printf("input too long\n"); 153 exit(2); 154 } 155 rp = s; 156 for (i = 0; i < len; i += 2) { 157 n = fromhex(*rp++); 158 n *= 16; 159 n += fromhex(*rp++); 160 *bp++ = n; 161 } 162 } 163 164 if (need_close) 165 fclose(f); 166 167 if (tcp) { 168 unsigned char *p = b; 169 while (p < bp) { 170 unsigned int len; 171 172 if (p + 2 > bp) { 173 printf("premature end of packet\n"); 174 exit(1); 175 } 176 len = p[0] << 8 | p[1]; 177 178 if (p + 2 + len > bp) { 179 printf("premature end of packet\n"); 180 exit(1); 181 } 182 isc_buffer_init(&source, p + 2, len); 183 isc_buffer_add(&source, len); 184 process_message(&source); 185 p += 2 + len; 186 } 187 } else { 188 isc_buffer_init(&source, b, sizeof(b)); 189 isc_buffer_add(&source, bp - b); 190 process_message(&source); 191 } 192 193 if (printmemstats) 194 isc_mem_stats(mctx, stdout); 195 isc_mem_destroy(&mctx); 196 197 return (0); 198} 199 200static void 201process_message(isc_buffer_t *source) { 202 dns_message_t *message; 203 isc_result_t result; 204 int i; 205 206 message = NULL; 207 result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &message); 208 CHECKRESULT(result, "dns_message_create failed"); 209 210 result = dns_message_parse(message, source, parseflags); 211 if (result == DNS_R_RECOVERABLE) 212 result = ISC_R_SUCCESS; 213 CHECKRESULT(result, "dns_message_parse failed"); 214 215 result = printmessage(message); 216 CHECKRESULT(result, "printmessage() failed"); 217 218 if (printmemstats) 219 isc_mem_stats(mctx, stdout); 220 221 if (dorender) { 222 unsigned char b2[64 * 1024]; 223 isc_buffer_t buffer; 224 dns_compress_t cctx; 225 226 isc_buffer_init(&buffer, b2, sizeof(b2)); 227 228 /* 229 * XXXMLG 230 * Changing this here is a hack, and should not be done in 231 * reasonable application code, ever. 232 */ 233 message->from_to_wire = DNS_MESSAGE_INTENTRENDER; 234 235 for (i = 0; i < DNS_SECTION_MAX; i++) 236 message->counts[i] = 0; /* Another hack XXX */ 237 238 result = dns_compress_init(&cctx, -1, mctx); 239 CHECKRESULT(result, "dns_compress_init() failed"); 240 241 result = dns_message_renderbegin(message, &cctx, &buffer); 242 CHECKRESULT(result, "dns_message_renderbegin() failed"); 243 244 result = dns_message_rendersection(message, 245 DNS_SECTION_QUESTION, 0); 246 CHECKRESULT(result, 247 "dns_message_rendersection(QUESTION) failed"); 248 249 result = dns_message_rendersection(message, 250 DNS_SECTION_ANSWER, 0); 251 CHECKRESULT(result, 252 "dns_message_rendersection(ANSWER) failed"); 253 254 result = dns_message_rendersection(message, 255 DNS_SECTION_AUTHORITY, 0); 256 CHECKRESULT(result, 257 "dns_message_rendersection(AUTHORITY) failed"); 258 259 result = dns_message_rendersection(message, 260 DNS_SECTION_ADDITIONAL, 0); 261 CHECKRESULT(result, 262 "dns_message_rendersection(ADDITIONAL) failed"); 263 264 dns_message_renderend(message); 265 266 dns_compress_invalidate(&cctx); 267 268 message->from_to_wire = DNS_MESSAGE_INTENTPARSE; 269 dns_message_destroy(&message); 270 271 printf("Message rendered.\n"); 272 if (printmemstats) 273 isc_mem_stats(mctx, stdout); 274 275 result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, 276 &message); 277 CHECKRESULT(result, "dns_message_create failed"); 278 279 result = dns_message_parse(message, &buffer, parseflags); 280 CHECKRESULT(result, "dns_message_parse failed"); 281 282 result = printmessage(message); 283 CHECKRESULT(result, "printmessage() failed"); 284 } 285 dns_message_destroy(&message); 286} 287