1*e2b1b9c0Schristos /* $NetBSD: wire_test.c,v 1.1.1.1 2018/08/12 12:07:27 christos Exp $ */ 2*e2b1b9c0Schristos 3*e2b1b9c0Schristos /* 4*e2b1b9c0Schristos * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5*e2b1b9c0Schristos * 6*e2b1b9c0Schristos * This Source Code Form is subject to the terms of the Mozilla Public 7*e2b1b9c0Schristos * License, v. 2.0. If a copy of the MPL was not distributed with this 8*e2b1b9c0Schristos * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9*e2b1b9c0Schristos * 10*e2b1b9c0Schristos * See the COPYRIGHT file distributed with this work for additional 11*e2b1b9c0Schristos * information regarding copyright ownership. 12*e2b1b9c0Schristos */ 13*e2b1b9c0Schristos 14*e2b1b9c0Schristos #include <config.h> 15*e2b1b9c0Schristos 16*e2b1b9c0Schristos #include <stdlib.h> 17*e2b1b9c0Schristos 18*e2b1b9c0Schristos #include <isc/buffer.h> 19*e2b1b9c0Schristos #include <isc/commandline.h> 20*e2b1b9c0Schristos #include <isc/file.h> 21*e2b1b9c0Schristos #include <isc/mem.h> 22*e2b1b9c0Schristos #include <isc/print.h> 23*e2b1b9c0Schristos #include <isc/string.h> 24*e2b1b9c0Schristos #include <isc/util.h> 25*e2b1b9c0Schristos 26*e2b1b9c0Schristos #include <dns/message.h> 27*e2b1b9c0Schristos #include <dns/result.h> 28*e2b1b9c0Schristos 29*e2b1b9c0Schristos int parseflags = 0; 30*e2b1b9c0Schristos isc_mem_t *mctx = NULL; 31*e2b1b9c0Schristos isc_boolean_t printmemstats = ISC_FALSE; 32*e2b1b9c0Schristos isc_boolean_t dorender = ISC_FALSE; 33*e2b1b9c0Schristos 34*e2b1b9c0Schristos static void 35*e2b1b9c0Schristos process_message(isc_buffer_t *source); 36*e2b1b9c0Schristos 37*e2b1b9c0Schristos static isc_result_t 38*e2b1b9c0Schristos printmessage(dns_message_t *msg); 39*e2b1b9c0Schristos 40*e2b1b9c0Schristos static inline void 41*e2b1b9c0Schristos CHECKRESULT(isc_result_t result, const char *msg) { 42*e2b1b9c0Schristos if (result != ISC_R_SUCCESS) { 43*e2b1b9c0Schristos printf("%s: %s\n", msg, dns_result_totext(result)); 44*e2b1b9c0Schristos 45*e2b1b9c0Schristos exit(1); 46*e2b1b9c0Schristos } 47*e2b1b9c0Schristos } 48*e2b1b9c0Schristos 49*e2b1b9c0Schristos static int 50*e2b1b9c0Schristos fromhex(char c) { 51*e2b1b9c0Schristos if (c >= '0' && c <= '9') 52*e2b1b9c0Schristos return (c - '0'); 53*e2b1b9c0Schristos else if (c >= 'a' && c <= 'f') 54*e2b1b9c0Schristos return (c - 'a' + 10); 55*e2b1b9c0Schristos else if (c >= 'A' && c <= 'F') 56*e2b1b9c0Schristos return (c - 'A' + 10); 57*e2b1b9c0Schristos 58*e2b1b9c0Schristos fprintf(stderr, "bad input format: %02x\n", c); 59*e2b1b9c0Schristos exit(3); 60*e2b1b9c0Schristos /* NOTREACHED */ 61*e2b1b9c0Schristos } 62*e2b1b9c0Schristos 63*e2b1b9c0Schristos static void 64*e2b1b9c0Schristos usage(void) { 65*e2b1b9c0Schristos fprintf(stderr, "wire_test [-b] [-d] [-p] [-r] [-s]\n"); 66*e2b1b9c0Schristos fprintf(stderr, " [-m {usage|trace|record|size|mctx}]\n"); 67*e2b1b9c0Schristos fprintf(stderr, " [filename]\n\n"); 68*e2b1b9c0Schristos fprintf(stderr, "\t-b\tBest-effort parsing (ignore some errors)\n"); 69*e2b1b9c0Schristos fprintf(stderr, "\t-d\tRead input as raw binary data\n"); 70*e2b1b9c0Schristos fprintf(stderr, "\t-p\tPreserve order of the records in messages\n"); 71*e2b1b9c0Schristos fprintf(stderr, "\t-r\tAfter parsing, re-render the message\n"); 72*e2b1b9c0Schristos fprintf(stderr, "\t-s\tPrint memory statistics\n"); 73*e2b1b9c0Schristos fprintf(stderr, "\t-t\tTCP mode - ignore the first 2 bytes\n"); 74*e2b1b9c0Schristos } 75*e2b1b9c0Schristos 76*e2b1b9c0Schristos static isc_result_t 77*e2b1b9c0Schristos printmessage(dns_message_t *msg) { 78*e2b1b9c0Schristos isc_buffer_t b; 79*e2b1b9c0Schristos char *buf = NULL; 80*e2b1b9c0Schristos int len = 1024; 81*e2b1b9c0Schristos isc_result_t result = ISC_R_SUCCESS; 82*e2b1b9c0Schristos 83*e2b1b9c0Schristos do { 84*e2b1b9c0Schristos buf = isc_mem_get(mctx, len); 85*e2b1b9c0Schristos if (buf == NULL) { 86*e2b1b9c0Schristos result = ISC_R_NOMEMORY; 87*e2b1b9c0Schristos break; 88*e2b1b9c0Schristos } 89*e2b1b9c0Schristos 90*e2b1b9c0Schristos isc_buffer_init(&b, buf, len); 91*e2b1b9c0Schristos result = dns_message_totext(msg, &dns_master_style_debug, 92*e2b1b9c0Schristos 0, &b); 93*e2b1b9c0Schristos if (result == ISC_R_NOSPACE) { 94*e2b1b9c0Schristos isc_mem_put(mctx, buf, len); 95*e2b1b9c0Schristos len *= 2; 96*e2b1b9c0Schristos } else if (result == ISC_R_SUCCESS) 97*e2b1b9c0Schristos printf("%.*s\n", (int) isc_buffer_usedlength(&b), buf); 98*e2b1b9c0Schristos } while (result == ISC_R_NOSPACE); 99*e2b1b9c0Schristos 100*e2b1b9c0Schristos if (buf != NULL) 101*e2b1b9c0Schristos isc_mem_put(mctx, buf, len); 102*e2b1b9c0Schristos 103*e2b1b9c0Schristos return (result); 104*e2b1b9c0Schristos } 105*e2b1b9c0Schristos 106*e2b1b9c0Schristos int 107*e2b1b9c0Schristos main(int argc, char *argv[]) { 108*e2b1b9c0Schristos isc_buffer_t *input = NULL; 109*e2b1b9c0Schristos isc_boolean_t need_close = ISC_FALSE; 110*e2b1b9c0Schristos isc_boolean_t tcp = ISC_FALSE; 111*e2b1b9c0Schristos isc_boolean_t rawdata = ISC_FALSE; 112*e2b1b9c0Schristos isc_result_t result; 113*e2b1b9c0Schristos isc_uint8_t c; 114*e2b1b9c0Schristos FILE *f; 115*e2b1b9c0Schristos int ch; 116*e2b1b9c0Schristos 117*e2b1b9c0Schristos #define CMDLINE_FLAGS "bdm:prst" 118*e2b1b9c0Schristos /* 119*e2b1b9c0Schristos * Process memory debugging argument first. 120*e2b1b9c0Schristos */ 121*e2b1b9c0Schristos while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { 122*e2b1b9c0Schristos switch (ch) { 123*e2b1b9c0Schristos case 'm': 124*e2b1b9c0Schristos if (strcasecmp(isc_commandline_argument, "record") == 0) 125*e2b1b9c0Schristos isc_mem_debugging |= ISC_MEM_DEBUGRECORD; 126*e2b1b9c0Schristos if (strcasecmp(isc_commandline_argument, "trace") == 0) 127*e2b1b9c0Schristos isc_mem_debugging |= ISC_MEM_DEBUGTRACE; 128*e2b1b9c0Schristos if (strcasecmp(isc_commandline_argument, "usage") == 0) 129*e2b1b9c0Schristos isc_mem_debugging |= ISC_MEM_DEBUGUSAGE; 130*e2b1b9c0Schristos if (strcasecmp(isc_commandline_argument, "size") == 0) 131*e2b1b9c0Schristos isc_mem_debugging |= ISC_MEM_DEBUGSIZE; 132*e2b1b9c0Schristos if (strcasecmp(isc_commandline_argument, "mctx") == 0) 133*e2b1b9c0Schristos isc_mem_debugging |= ISC_MEM_DEBUGCTX; 134*e2b1b9c0Schristos break; 135*e2b1b9c0Schristos default: 136*e2b1b9c0Schristos break; 137*e2b1b9c0Schristos } 138*e2b1b9c0Schristos } 139*e2b1b9c0Schristos isc_commandline_reset = ISC_TRUE; 140*e2b1b9c0Schristos 141*e2b1b9c0Schristos RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); 142*e2b1b9c0Schristos 143*e2b1b9c0Schristos while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { 144*e2b1b9c0Schristos switch (ch) { 145*e2b1b9c0Schristos case 'b': 146*e2b1b9c0Schristos parseflags |= DNS_MESSAGEPARSE_BESTEFFORT; 147*e2b1b9c0Schristos break; 148*e2b1b9c0Schristos case 'd': 149*e2b1b9c0Schristos rawdata = ISC_TRUE; 150*e2b1b9c0Schristos break; 151*e2b1b9c0Schristos case 'm': 152*e2b1b9c0Schristos break; 153*e2b1b9c0Schristos case 'p': 154*e2b1b9c0Schristos parseflags |= DNS_MESSAGEPARSE_PRESERVEORDER; 155*e2b1b9c0Schristos break; 156*e2b1b9c0Schristos case 'r': 157*e2b1b9c0Schristos dorender = ISC_TRUE; 158*e2b1b9c0Schristos break; 159*e2b1b9c0Schristos case 's': 160*e2b1b9c0Schristos printmemstats = ISC_TRUE; 161*e2b1b9c0Schristos break; 162*e2b1b9c0Schristos case 't': 163*e2b1b9c0Schristos tcp = ISC_TRUE; 164*e2b1b9c0Schristos break; 165*e2b1b9c0Schristos default: 166*e2b1b9c0Schristos usage(); 167*e2b1b9c0Schristos exit(1); 168*e2b1b9c0Schristos } 169*e2b1b9c0Schristos } 170*e2b1b9c0Schristos 171*e2b1b9c0Schristos argc -= isc_commandline_index; 172*e2b1b9c0Schristos argv += isc_commandline_index; 173*e2b1b9c0Schristos 174*e2b1b9c0Schristos if (argc >= 1) { 175*e2b1b9c0Schristos f = fopen(argv[0], "r"); 176*e2b1b9c0Schristos if (f == NULL) { 177*e2b1b9c0Schristos fprintf(stderr, "%s: fopen failed\n", argv[0]); 178*e2b1b9c0Schristos exit(1); 179*e2b1b9c0Schristos } 180*e2b1b9c0Schristos need_close = ISC_TRUE; 181*e2b1b9c0Schristos } else 182*e2b1b9c0Schristos f = stdin; 183*e2b1b9c0Schristos 184*e2b1b9c0Schristos result = isc_buffer_allocate(mctx, &input, 64 * 1024); 185*e2b1b9c0Schristos RUNTIME_CHECK(result == ISC_R_SUCCESS); 186*e2b1b9c0Schristos 187*e2b1b9c0Schristos if (rawdata) { 188*e2b1b9c0Schristos while (fread(&c, 1, 1, f) != 0) { 189*e2b1b9c0Schristos result = isc_buffer_reserve(&input, 1); 190*e2b1b9c0Schristos RUNTIME_CHECK(result == ISC_R_SUCCESS); 191*e2b1b9c0Schristos isc_buffer_putuint8(input, (isc_uint8_t) c); 192*e2b1b9c0Schristos } 193*e2b1b9c0Schristos } else { 194*e2b1b9c0Schristos char s[BUFSIZ]; 195*e2b1b9c0Schristos 196*e2b1b9c0Schristos while (fgets(s, sizeof(s), f) != NULL) { 197*e2b1b9c0Schristos char *rp = s, *wp = s; 198*e2b1b9c0Schristos size_t i, len = 0; 199*e2b1b9c0Schristos 200*e2b1b9c0Schristos while (*rp != '\0') { 201*e2b1b9c0Schristos if (*rp == '#') 202*e2b1b9c0Schristos break; 203*e2b1b9c0Schristos if (*rp != ' ' && *rp != '\t' && 204*e2b1b9c0Schristos *rp != '\r' && *rp != '\n') { 205*e2b1b9c0Schristos *wp++ = *rp; 206*e2b1b9c0Schristos len++; 207*e2b1b9c0Schristos } 208*e2b1b9c0Schristos rp++; 209*e2b1b9c0Schristos } 210*e2b1b9c0Schristos if (len == 0U) 211*e2b1b9c0Schristos continue; 212*e2b1b9c0Schristos if (len % 2 != 0U) { 213*e2b1b9c0Schristos fprintf(stderr, "bad input format: %lu\n", 214*e2b1b9c0Schristos (unsigned long)len); 215*e2b1b9c0Schristos exit(1); 216*e2b1b9c0Schristos } 217*e2b1b9c0Schristos 218*e2b1b9c0Schristos rp = s; 219*e2b1b9c0Schristos for (i = 0; i < len; i += 2) { 220*e2b1b9c0Schristos c = fromhex(*rp++); 221*e2b1b9c0Schristos c *= 16; 222*e2b1b9c0Schristos c += fromhex(*rp++); 223*e2b1b9c0Schristos result = isc_buffer_reserve(&input, 1); 224*e2b1b9c0Schristos RUNTIME_CHECK(result == ISC_R_SUCCESS); 225*e2b1b9c0Schristos isc_buffer_putuint8(input, (isc_uint8_t) c); 226*e2b1b9c0Schristos } 227*e2b1b9c0Schristos } 228*e2b1b9c0Schristos } 229*e2b1b9c0Schristos 230*e2b1b9c0Schristos if (need_close) 231*e2b1b9c0Schristos fclose(f); 232*e2b1b9c0Schristos 233*e2b1b9c0Schristos if (tcp) { 234*e2b1b9c0Schristos while (isc_buffer_remaininglength(input) != 0) { 235*e2b1b9c0Schristos unsigned int tcplen; 236*e2b1b9c0Schristos 237*e2b1b9c0Schristos if (isc_buffer_remaininglength(input) < 2) { 238*e2b1b9c0Schristos fprintf(stderr, "premature end of packet\n"); 239*e2b1b9c0Schristos exit(1); 240*e2b1b9c0Schristos } 241*e2b1b9c0Schristos tcplen = isc_buffer_getuint16(input); 242*e2b1b9c0Schristos 243*e2b1b9c0Schristos if (isc_buffer_remaininglength(input) < tcplen) { 244*e2b1b9c0Schristos fprintf(stderr, "premature end of packet\n"); 245*e2b1b9c0Schristos exit(1); 246*e2b1b9c0Schristos } 247*e2b1b9c0Schristos process_message(input); 248*e2b1b9c0Schristos } 249*e2b1b9c0Schristos } else 250*e2b1b9c0Schristos process_message(input); 251*e2b1b9c0Schristos 252*e2b1b9c0Schristos if (input != NULL) 253*e2b1b9c0Schristos isc_buffer_free(&input); 254*e2b1b9c0Schristos 255*e2b1b9c0Schristos if (printmemstats) 256*e2b1b9c0Schristos isc_mem_stats(mctx, stdout); 257*e2b1b9c0Schristos isc_mem_destroy(&mctx); 258*e2b1b9c0Schristos 259*e2b1b9c0Schristos return (0); 260*e2b1b9c0Schristos } 261*e2b1b9c0Schristos 262*e2b1b9c0Schristos static void 263*e2b1b9c0Schristos process_message(isc_buffer_t *source) { 264*e2b1b9c0Schristos dns_message_t *message; 265*e2b1b9c0Schristos isc_result_t result; 266*e2b1b9c0Schristos int i; 267*e2b1b9c0Schristos 268*e2b1b9c0Schristos message = NULL; 269*e2b1b9c0Schristos result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &message); 270*e2b1b9c0Schristos CHECKRESULT(result, "dns_message_create failed"); 271*e2b1b9c0Schristos 272*e2b1b9c0Schristos result = dns_message_parse(message, source, parseflags); 273*e2b1b9c0Schristos if (result == DNS_R_RECOVERABLE) 274*e2b1b9c0Schristos result = ISC_R_SUCCESS; 275*e2b1b9c0Schristos CHECKRESULT(result, "dns_message_parse failed"); 276*e2b1b9c0Schristos 277*e2b1b9c0Schristos result = printmessage(message); 278*e2b1b9c0Schristos CHECKRESULT(result, "printmessage() failed"); 279*e2b1b9c0Schristos 280*e2b1b9c0Schristos if (printmemstats) 281*e2b1b9c0Schristos isc_mem_stats(mctx, stdout); 282*e2b1b9c0Schristos 283*e2b1b9c0Schristos if (dorender) { 284*e2b1b9c0Schristos unsigned char b2[64 * 1024]; 285*e2b1b9c0Schristos isc_buffer_t buffer; 286*e2b1b9c0Schristos dns_compress_t cctx; 287*e2b1b9c0Schristos 288*e2b1b9c0Schristos isc_buffer_init(&buffer, b2, sizeof(b2)); 289*e2b1b9c0Schristos 290*e2b1b9c0Schristos /* 291*e2b1b9c0Schristos * XXXMLG 292*e2b1b9c0Schristos * Changing this here is a hack, and should not be done in 293*e2b1b9c0Schristos * reasonable application code, ever. 294*e2b1b9c0Schristos */ 295*e2b1b9c0Schristos message->from_to_wire = DNS_MESSAGE_INTENTRENDER; 296*e2b1b9c0Schristos 297*e2b1b9c0Schristos for (i = 0; i < DNS_SECTION_MAX; i++) 298*e2b1b9c0Schristos message->counts[i] = 0; /* Another hack XXX */ 299*e2b1b9c0Schristos 300*e2b1b9c0Schristos result = dns_compress_init(&cctx, -1, mctx); 301*e2b1b9c0Schristos CHECKRESULT(result, "dns_compress_init() failed"); 302*e2b1b9c0Schristos 303*e2b1b9c0Schristos result = dns_message_renderbegin(message, &cctx, &buffer); 304*e2b1b9c0Schristos CHECKRESULT(result, "dns_message_renderbegin() failed"); 305*e2b1b9c0Schristos 306*e2b1b9c0Schristos result = dns_message_rendersection(message, 307*e2b1b9c0Schristos DNS_SECTION_QUESTION, 0); 308*e2b1b9c0Schristos CHECKRESULT(result, 309*e2b1b9c0Schristos "dns_message_rendersection(QUESTION) failed"); 310*e2b1b9c0Schristos 311*e2b1b9c0Schristos result = dns_message_rendersection(message, 312*e2b1b9c0Schristos DNS_SECTION_ANSWER, 0); 313*e2b1b9c0Schristos CHECKRESULT(result, 314*e2b1b9c0Schristos "dns_message_rendersection(ANSWER) failed"); 315*e2b1b9c0Schristos 316*e2b1b9c0Schristos result = dns_message_rendersection(message, 317*e2b1b9c0Schristos DNS_SECTION_AUTHORITY, 0); 318*e2b1b9c0Schristos CHECKRESULT(result, 319*e2b1b9c0Schristos "dns_message_rendersection(AUTHORITY) failed"); 320*e2b1b9c0Schristos 321*e2b1b9c0Schristos result = dns_message_rendersection(message, 322*e2b1b9c0Schristos DNS_SECTION_ADDITIONAL, 0); 323*e2b1b9c0Schristos CHECKRESULT(result, 324*e2b1b9c0Schristos "dns_message_rendersection(ADDITIONAL) failed"); 325*e2b1b9c0Schristos 326*e2b1b9c0Schristos dns_message_renderend(message); 327*e2b1b9c0Schristos 328*e2b1b9c0Schristos dns_compress_invalidate(&cctx); 329*e2b1b9c0Schristos 330*e2b1b9c0Schristos message->from_to_wire = DNS_MESSAGE_INTENTPARSE; 331*e2b1b9c0Schristos dns_message_destroy(&message); 332*e2b1b9c0Schristos 333*e2b1b9c0Schristos printf("Message rendered.\n"); 334*e2b1b9c0Schristos if (printmemstats) 335*e2b1b9c0Schristos isc_mem_stats(mctx, stdout); 336*e2b1b9c0Schristos 337*e2b1b9c0Schristos result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, 338*e2b1b9c0Schristos &message); 339*e2b1b9c0Schristos CHECKRESULT(result, "dns_message_create failed"); 340*e2b1b9c0Schristos 341*e2b1b9c0Schristos result = dns_message_parse(message, &buffer, parseflags); 342*e2b1b9c0Schristos CHECKRESULT(result, "dns_message_parse failed"); 343*e2b1b9c0Schristos 344*e2b1b9c0Schristos result = printmessage(message); 345*e2b1b9c0Schristos CHECKRESULT(result, "printmessage() failed"); 346*e2b1b9c0Schristos } 347*e2b1b9c0Schristos dns_message_destroy(&message); 348*e2b1b9c0Schristos } 349