2015-10-02 12:32:42 -07:00
|
|
|
/*
|
2018-02-23 09:53:12 +01:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2015-10-02 12:32:42 -07:00
|
|
|
*
|
2016-06-27 14:56:38 +10:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
2015-10-02 12:32:42 -07:00
|
|
|
*/
|
2015-10-03 23:45:23 +00:00
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
/*
|
|
|
|
* Portions of this code were adapted from dnstap-ldns:
|
|
|
|
*
|
|
|
|
* Copyright (c) 2014 by Farsight Security, Inc.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <isc/buffer.h>
|
|
|
|
#include <isc/commandline.h>
|
2017-04-20 20:22:19 -07:00
|
|
|
#include <isc/hex.h>
|
2015-10-02 12:32:42 -07:00
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/print.h>
|
|
|
|
#include <isc/string.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#include <dns/dnstap.h>
|
|
|
|
#include <dns/fixedname.h>
|
|
|
|
#include <dns/masterdump.h>
|
|
|
|
#include <dns/message.h>
|
|
|
|
#include <dns/name.h>
|
|
|
|
#include <dns/result.h>
|
|
|
|
|
|
|
|
isc_mem_t *mctx = NULL;
|
|
|
|
isc_boolean_t memrecord = ISC_FALSE;
|
|
|
|
isc_boolean_t printmessage = ISC_FALSE;
|
2017-04-20 20:22:19 -07:00
|
|
|
isc_boolean_t hexmessage = ISC_FALSE;
|
2015-10-02 12:32:42 -07:00
|
|
|
isc_boolean_t yaml = ISC_FALSE;
|
|
|
|
|
|
|
|
const char *program = "dnstap-read";
|
|
|
|
|
|
|
|
#define CHECKM(op, msg) \
|
|
|
|
do { result = (op); \
|
|
|
|
if (result != ISC_R_SUCCESS) { \
|
|
|
|
fprintf(stderr, \
|
2015-10-03 23:45:23 +00:00
|
|
|
"%s: %s: %s\n", program, msg, \
|
2015-10-02 12:32:42 -07:00
|
|
|
isc_result_totext(result)); \
|
|
|
|
goto cleanup; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
ISC_PLATFORM_NORETURN_PRE static void
|
|
|
|
fatal(const char *format, ...) ISC_PLATFORM_NORETURN_POST;
|
|
|
|
|
|
|
|
static void
|
|
|
|
fatal(const char *format, ...) {
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
fprintf(stderr, "%s: fatal: ", program);
|
|
|
|
va_start(args, format);
|
|
|
|
vfprintf(stderr, format, args);
|
|
|
|
va_end(args);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
usage(void) {
|
2017-04-20 20:22:19 -07:00
|
|
|
fprintf(stderr, "dnstap-read [-mpxy] [filename]\n");
|
2015-10-02 12:32:42 -07:00
|
|
|
fprintf(stderr, "\t-m\ttrace memory allocations\n");
|
|
|
|
fprintf(stderr, "\t-p\tprint the full DNS message\n");
|
2017-04-20 20:22:19 -07:00
|
|
|
fprintf(stderr, "\t-x\tuse hex format to print DNS message\n");
|
2015-10-02 12:32:42 -07:00
|
|
|
fprintf(stderr, "\t-y\tprint YAML format (implies -p)\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-12-28 10:06:40 +01:00
|
|
|
print_dtdata(dns_dtdata_t *dt) {
|
|
|
|
isc_result_t result;
|
|
|
|
isc_buffer_t *b = NULL;
|
|
|
|
|
|
|
|
isc_buffer_allocate(mctx, &b, 2048);
|
|
|
|
if (b == NULL)
|
|
|
|
fatal("out of memory");
|
|
|
|
|
|
|
|
CHECKM(dns_dt_datatotext(dt, &b), "dns_dt_datatotext");
|
|
|
|
printf("%.*s\n", (int) isc_buffer_usedlength(b),
|
|
|
|
(char *) isc_buffer_base(b));
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (b != NULL)
|
|
|
|
isc_buffer_free(&b);
|
|
|
|
}
|
|
|
|
|
2017-04-20 20:22:19 -07:00
|
|
|
static void
|
|
|
|
print_hex(dns_dtdata_t *dt) {
|
|
|
|
isc_buffer_t *b = NULL;
|
|
|
|
isc_result_t result;
|
|
|
|
size_t textlen;
|
|
|
|
|
|
|
|
if (dt->msg == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
textlen = (dt->msgdata.length * 2) + 1;
|
|
|
|
isc_buffer_allocate(mctx, &b, textlen);
|
|
|
|
if (b == NULL) {
|
|
|
|
fatal("out of memory");
|
|
|
|
}
|
|
|
|
|
|
|
|
result = isc_hex_totext(&dt->msgdata, 0, "", b);
|
|
|
|
CHECKM(result, "isc_hex_totext");
|
|
|
|
|
|
|
|
printf("%.*s\n", (int) isc_buffer_usedlength(b),
|
|
|
|
(char *) isc_buffer_base(b));
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (b != NULL)
|
|
|
|
isc_buffer_free(&b);
|
|
|
|
}
|
|
|
|
|
2016-12-28 10:06:40 +01:00
|
|
|
static void
|
|
|
|
print_packet(dns_dtdata_t *dt, const dns_master_style_t *style) {
|
|
|
|
isc_buffer_t *b = NULL;
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
if (dt->msg != NULL) {
|
|
|
|
size_t textlen = 2048;
|
|
|
|
|
|
|
|
isc_buffer_allocate(mctx, &b, textlen);
|
|
|
|
if (b == NULL)
|
|
|
|
fatal("out of memory");
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
isc_buffer_reserve(&b, textlen);
|
|
|
|
if (b == NULL)
|
|
|
|
fatal("out of memory");
|
|
|
|
|
|
|
|
result = dns_message_totext(dt->msg, style, 0, b);
|
|
|
|
if (result == ISC_R_NOSPACE) {
|
|
|
|
textlen *= 2;
|
|
|
|
continue;
|
|
|
|
} else if (result == ISC_R_SUCCESS) {
|
|
|
|
printf("%.*s",
|
|
|
|
(int) isc_buffer_usedlength(b),
|
|
|
|
(char *) isc_buffer_base(b));
|
|
|
|
isc_buffer_free(&b);
|
|
|
|
} else {
|
|
|
|
isc_buffer_free(&b);
|
|
|
|
CHECKM(result, "dns_message_totext");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (b != NULL)
|
|
|
|
isc_buffer_free(&b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_yaml(dns_dtdata_t *dt) {
|
|
|
|
Dnstap__Dnstap *frame = dt->frame;
|
2015-10-02 12:32:42 -07:00
|
|
|
Dnstap__Message *m = frame->message;
|
|
|
|
const ProtobufCEnumValue *ftype, *mtype;
|
2016-12-28 10:06:40 +01:00
|
|
|
static isc_boolean_t first = ISC_TRUE;
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
ftype = protobuf_c_enum_descriptor_get_value(
|
|
|
|
&dnstap__dnstap__type__descriptor,
|
|
|
|
frame->type);
|
|
|
|
if (ftype == NULL)
|
|
|
|
return;
|
|
|
|
|
2016-12-28 10:06:40 +01:00
|
|
|
if (!first)
|
|
|
|
printf("---\n");
|
|
|
|
else
|
|
|
|
first = ISC_FALSE;
|
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
printf("type: %s\n", ftype->name);
|
|
|
|
|
|
|
|
if (frame->has_identity)
|
|
|
|
printf("identity: %.*s\n", (int) frame->identity.len,
|
|
|
|
frame->identity.data);
|
|
|
|
|
|
|
|
if (frame->has_version)
|
|
|
|
printf("version: %.*s\n", (int) frame->version.len,
|
|
|
|
frame->version.data);
|
|
|
|
|
|
|
|
if (frame->type != DNSTAP__DNSTAP__TYPE__MESSAGE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
printf("message:\n");
|
|
|
|
|
|
|
|
mtype = protobuf_c_enum_descriptor_get_value(
|
|
|
|
&dnstap__message__type__descriptor,
|
|
|
|
m->type);
|
|
|
|
if (mtype == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
printf(" type: %s\n", mtype->name);
|
|
|
|
|
2016-12-28 10:06:40 +01:00
|
|
|
if (!isc_time_isepoch(&dt->qtime)) {
|
2015-10-02 12:32:42 -07:00
|
|
|
char buf[100];
|
2016-12-28 10:06:40 +01:00
|
|
|
isc_time_formatISO8601(&dt->qtime, buf, sizeof(buf));
|
2015-10-02 12:32:42 -07:00
|
|
|
printf(" query_time: !!timestamp %s\n", buf);
|
|
|
|
}
|
|
|
|
|
2016-12-28 10:06:40 +01:00
|
|
|
if (!isc_time_isepoch(&dt->rtime)) {
|
2015-10-02 12:32:42 -07:00
|
|
|
char buf[100];
|
2016-12-28 10:06:40 +01:00
|
|
|
isc_time_formatISO8601(&dt->rtime, buf, sizeof(buf));
|
2015-10-02 12:32:42 -07:00
|
|
|
printf(" response_time: !!timestamp %s\n", buf);
|
|
|
|
}
|
|
|
|
|
2016-12-28 23:48:39 +00:00
|
|
|
if (dt->msgdata.base != NULL) {
|
2018-02-15 11:52:33 +11:00
|
|
|
printf(" message_size: %zub\n", (size_t) dt->msgdata.length);
|
2016-12-28 23:48:39 +00:00
|
|
|
} else
|
|
|
|
printf(" message_size: 0b\n");
|
2016-12-28 10:06:40 +01:00
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
if (m->has_socket_family) {
|
|
|
|
const ProtobufCEnumValue *type =
|
|
|
|
protobuf_c_enum_descriptor_get_value(
|
|
|
|
&dnstap__socket_family__descriptor,
|
|
|
|
m->socket_family);
|
|
|
|
if (type != NULL)
|
|
|
|
printf(" socket_family: %s\n", type->name);
|
|
|
|
}
|
|
|
|
|
2016-12-28 10:06:40 +01:00
|
|
|
printf(" socket_protocol: %s\n", dt->tcp ? "TCP" : "UDP");
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
if (m->has_query_address) {
|
|
|
|
ProtobufCBinaryData *ip = &m->query_address;
|
|
|
|
char buf[100];
|
|
|
|
|
|
|
|
(void)inet_ntop(ip->len == 4 ? AF_INET : AF_INET6,
|
|
|
|
ip->data, buf, sizeof(buf));
|
|
|
|
printf(" query_address: %s\n", buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m->has_response_address) {
|
|
|
|
ProtobufCBinaryData *ip = &m->response_address;
|
|
|
|
char buf[100];
|
|
|
|
|
|
|
|
(void)inet_ntop(ip->len == 4 ? AF_INET : AF_INET6,
|
|
|
|
ip->data, buf, sizeof(buf));
|
|
|
|
printf(" response_address: %s\n", buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m->has_query_port)
|
|
|
|
printf(" query_port: %u\n", m->query_port);
|
|
|
|
|
|
|
|
if (m->has_response_port)
|
|
|
|
printf(" response_port: %u\n", m->response_port);
|
|
|
|
|
|
|
|
if (m->has_query_zone) {
|
|
|
|
isc_result_t result;
|
|
|
|
dns_fixedname_t fn;
|
|
|
|
dns_name_t *name;
|
|
|
|
isc_buffer_t b;
|
|
|
|
dns_decompress_t dctx;
|
|
|
|
|
2018-03-28 14:38:09 +02:00
|
|
|
name = dns_fixedname_initname(&fn);
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
isc_buffer_init(&b, m->query_zone.data, m->query_zone.len);
|
|
|
|
isc_buffer_add(&b, m->query_zone.len);
|
|
|
|
|
|
|
|
dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
|
|
|
|
result = dns_name_fromwire(name, &b, &dctx, 0, NULL);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
printf(" query_zone: ");
|
|
|
|
dns_name_print(name, stdout);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-28 10:06:40 +01:00
|
|
|
if (dt->msg != NULL) {
|
|
|
|
printf(" %s:\n", ((dt->type & DNS_DTTYPE_QUERY) != 0)
|
|
|
|
? "query_message_data"
|
|
|
|
: "response_message_data");
|
|
|
|
|
|
|
|
print_packet(dt, &dns_master_style_yaml);
|
|
|
|
|
|
|
|
printf(" %s: |\n", ((dt->type & DNS_DTTYPE_QUERY) != 0)
|
|
|
|
? "query_message"
|
|
|
|
: "response_message");
|
|
|
|
print_packet(dt, &dns_master_style_indent);
|
|
|
|
}
|
2015-10-02 12:32:42 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[]) {
|
|
|
|
isc_result_t result;
|
|
|
|
dns_message_t *message = NULL;
|
|
|
|
isc_buffer_t *b = NULL;
|
|
|
|
dns_dtdata_t *dt = NULL;
|
2016-08-25 10:03:22 +10:00
|
|
|
dns_dthandle_t *handle = NULL;
|
2015-10-02 12:32:42 -07:00
|
|
|
int rv = 0, ch;
|
|
|
|
|
2017-04-20 20:22:19 -07:00
|
|
|
while ((ch = isc_commandline_parse(argc, argv, "mpxy")) != -1) {
|
2015-10-02 12:32:42 -07:00
|
|
|
switch (ch) {
|
|
|
|
case 'm':
|
|
|
|
isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
|
|
|
|
memrecord = ISC_TRUE;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
printmessage = ISC_TRUE;
|
|
|
|
break;
|
2017-04-20 20:22:19 -07:00
|
|
|
case 'x':
|
|
|
|
hexmessage = ISC_TRUE;
|
|
|
|
break;
|
2015-10-02 12:32:42 -07:00
|
|
|
case 'y':
|
|
|
|
yaml = ISC_TRUE;
|
2016-12-28 10:06:40 +01:00
|
|
|
dns_master_indentstr = " ";
|
|
|
|
dns_master_indent = 2;
|
2015-10-02 12:32:42 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
argc -= isc_commandline_index;
|
|
|
|
argv += isc_commandline_index;
|
|
|
|
|
|
|
|
if (argc < 1)
|
|
|
|
fatal("no file specified");
|
|
|
|
|
|
|
|
RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
|
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
dns_result_register();
|
|
|
|
|
|
|
|
CHECKM(dns_dt_open(argv[0], dns_dtmode_file, mctx, &handle),
|
2015-10-02 12:32:42 -07:00
|
|
|
"dns_dt_openfile");
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
isc_region_t input;
|
|
|
|
isc_uint8_t *data;
|
|
|
|
size_t datalen;
|
|
|
|
|
2016-08-25 10:03:22 +10:00
|
|
|
result = dns_dt_getframe(handle, &data, &datalen);
|
2015-10-02 12:32:42 -07:00
|
|
|
if (result == ISC_R_NOMORE)
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
CHECKM(result, "dns_dt_getframe");
|
|
|
|
|
|
|
|
input.base = data;
|
|
|
|
input.length = datalen;
|
|
|
|
|
|
|
|
if (b != NULL)
|
|
|
|
isc_buffer_free(&b);
|
|
|
|
isc_buffer_allocate(mctx, &b, 2048);
|
|
|
|
if (b == NULL)
|
|
|
|
fatal("out of memory");
|
|
|
|
|
|
|
|
result = dns_dt_parse(mctx, &input, &dt);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
isc_buffer_free(&b);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-12-28 10:06:40 +01:00
|
|
|
if (yaml) {
|
2015-10-02 12:32:42 -07:00
|
|
|
print_yaml(dt);
|
2017-04-20 20:22:19 -07:00
|
|
|
} else if (hexmessage) {
|
|
|
|
print_dtdata(dt);
|
|
|
|
print_hex(dt);
|
2016-12-28 10:06:40 +01:00
|
|
|
} else if (printmessage) {
|
|
|
|
print_dtdata(dt);
|
|
|
|
print_packet(dt, &dns_master_style_debug);
|
|
|
|
} else {
|
|
|
|
print_dtdata(dt);
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
dns_dtdata_free(&dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (dt != NULL)
|
|
|
|
dns_dtdata_free(&dt);
|
2016-08-25 10:03:22 +10:00
|
|
|
if (handle != NULL)
|
|
|
|
dns_dt_close(&handle);
|
2015-10-02 12:32:42 -07:00
|
|
|
if (message != NULL)
|
|
|
|
dns_message_destroy(&message);
|
|
|
|
if (b != NULL)
|
|
|
|
isc_buffer_free(&b);
|
|
|
|
isc_mem_destroy(&mctx);
|
|
|
|
|
|
|
|
exit(rv);
|
|
|
|
}
|