]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemd-resolve: allow whole packets to be dumped in binary form
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sun, 31 Jan 2016 05:06:49 +0000 (00:06 -0500)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 17 Feb 2016 00:55:50 +0000 (19:55 -0500)
man/systemd-resolve.xml
src/resolve/resolve-tool.c

index bec6213de2c4409f90864fbdb14379c19c2f5f35..c288fd974ec100cde9a46a9fd7f20c2b0f46045b 100644 (file)
         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>
 
index a24bb546d4fef11ae7bf15a0eac45db02a10866a..a51907427810c635bb058fee2b4c78d80a98653d 100644 (file)
@@ -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();
-
-                p->refuse_compression = true;
-
-                r = dns_packet_append_blob(p, d, l, NULL);
-                if (r < 0)
-                        return log_oom();
+                if (arg_raw == RAW_PACKET) {
+                        uint64_t u64 = htole64(l);
 
-                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;