systemd-resolve: allow whole packets to be dumped in binary form
This commit is contained in:
parent
2e74028a5c
commit
dab48ea63a
|
@ -232,6 +232,16 @@
|
|||
logic is disabled.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--raw</option><optional>=payload|packet</optional></term>
|
||||
|
||||
<listitem><para>Dump the answer as binary data. If there is no argument or if the argument is
|
||||
<literal>payload</literal>, the payload of the packet is exported. If the argument is
|
||||
<literal>packet</literal>, the whole packet is dumped in wire format, prefixed by
|
||||
length specified as a little-endian 64-bit number. This format allows multiple packets
|
||||
to be dumped and unambigously parsed.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--legend=</option><replaceable>BOOL</replaceable></term>
|
||||
|
||||
|
|
|
@ -43,7 +43,14 @@ static uint16_t arg_type = 0;
|
|||
static uint16_t arg_class = 0;
|
||||
static bool arg_legend = true;
|
||||
static uint64_t arg_flags = 0;
|
||||
static bool arg_raw = false;
|
||||
|
||||
typedef enum RawType {
|
||||
RAW_NONE,
|
||||
RAW_PAYLOAD,
|
||||
RAW_PACKET,
|
||||
} RawType;
|
||||
|
||||
static RawType arg_raw = RAW_NONE;
|
||||
|
||||
static enum {
|
||||
MODE_RESOLVE_HOST,
|
||||
|
@ -332,6 +339,50 @@ static int parse_address(const char *s, int *family, union in_addr_union *addres
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int output_rr_packet(const void *d, size_t l, int ifindex) {
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
||||
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
|
||||
int r;
|
||||
char ifname[IF_NAMESIZE] = "";
|
||||
|
||||
r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
p->refuse_compression = true;
|
||||
|
||||
r = dns_packet_append_blob(p, d, l, NULL);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = dns_packet_read_rr(p, &rr, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse RR: %m");
|
||||
|
||||
if (arg_raw == RAW_PAYLOAD) {
|
||||
void *data;
|
||||
ssize_t k;
|
||||
|
||||
k = dns_resource_record_payload(rr, &data);
|
||||
if (k < 0)
|
||||
return log_error_errno(k, "Cannot dump RR: %m");
|
||||
fwrite(data, 1, k, stdout);
|
||||
} else {
|
||||
const char *s;
|
||||
|
||||
s = dns_resource_record_to_string(rr);
|
||||
if (!s)
|
||||
return log_oom();
|
||||
|
||||
if (ifindex > 0 && !if_indextoname(ifindex, ifname))
|
||||
log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
|
||||
|
||||
printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
@ -378,8 +429,6 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
|
|||
return bus_log_parse_error(r);
|
||||
|
||||
while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
||||
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
|
||||
uint16_t c, t;
|
||||
int ifindex;
|
||||
const void *d;
|
||||
|
@ -399,44 +448,17 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
|
|||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (arg_raw == RAW_PACKET) {
|
||||
uint64_t u64 = htole64(l);
|
||||
|
||||
p->refuse_compression = true;
|
||||
|
||||
r = dns_packet_append_blob(p, d, l, NULL);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = dns_packet_read_rr(p, &rr, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse RR: %m");
|
||||
|
||||
if (arg_raw) {
|
||||
void *data;
|
||||
ssize_t k;
|
||||
|
||||
k = dns_resource_record_payload(rr, &data);
|
||||
if (k < 0)
|
||||
return log_error_errno(k, "Cannot dump RR: %m");
|
||||
fwrite(data, 1, k, stdout);
|
||||
fwrite(&u64, sizeof(u64), 1, stdout);
|
||||
fwrite(d, 1, l, stdout);
|
||||
} else {
|
||||
const char *s;
|
||||
|
||||
s = dns_resource_record_to_string(rr);
|
||||
if (!s)
|
||||
return log_oom();
|
||||
|
||||
ifname[0] = 0;
|
||||
if (ifindex > 0 && !if_indextoname(ifindex, ifname))
|
||||
log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
|
||||
|
||||
printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
|
||||
r = output_rr_packet(d, l, ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
|
||||
|
||||
if (dns_type_needs_authentication(t))
|
||||
needs_authentication = true;
|
||||
|
||||
|
@ -1012,6 +1034,7 @@ static void help(void) {
|
|||
" --cname=BOOL Follow CNAME redirects (default: yes)\n"
|
||||
" --search=BOOL Use search domains for single-label names\n"
|
||||
" (default: yes)\n"
|
||||
" --raw[=payload|packet] Dump the answer as binary data\n"
|
||||
" --legend=BOOL Print headers and additional info (default: yes)\n"
|
||||
" --statistics Show resolver statistics\n"
|
||||
" --reset-statistics Reset resolver statistics\n"
|
||||
|
@ -1046,7 +1069,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
{ "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
|
||||
{ "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
|
||||
{ "openpgp", no_argument, NULL, ARG_OPENPGP },
|
||||
{ "raw", no_argument, NULL, ARG_RAW },
|
||||
{ "raw", optional_argument, NULL, ARG_RAW },
|
||||
{ "search", required_argument, NULL, ARG_SEARCH },
|
||||
{ "statistics", no_argument, NULL, ARG_STATISTICS, },
|
||||
{ "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
|
||||
|
@ -1166,7 +1189,15 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
return -ENOTTY;
|
||||
}
|
||||
|
||||
arg_raw = true;
|
||||
if (optarg == NULL || streq(optarg, "payload"))
|
||||
arg_raw = RAW_PAYLOAD;
|
||||
else if (streq(optarg, "packet"))
|
||||
arg_raw = RAW_PACKET;
|
||||
else {
|
||||
log_error("Unknown --raw specifier \"%s\".", optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arg_legend = false;
|
||||
break;
|
||||
|
||||
|
|
Loading…
Reference in New Issue