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