summaryrefslogtreecommitdiff
path: root/REORG.TODO/support/support_format_dns_packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/support/support_format_dns_packet.c')
-rw-r--r--REORG.TODO/support/support_format_dns_packet.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/REORG.TODO/support/support_format_dns_packet.c b/REORG.TODO/support/support_format_dns_packet.c
new file mode 100644
index 0000000000..2992c57971
--- /dev/null
+++ b/REORG.TODO/support/support_format_dns_packet.c
@@ -0,0 +1,222 @@
+/* Convert a DNS packet to a human-readable representation.
+ Copyright (C) 2016-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/format_nss.h>
+
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+struct in_buffer
+{
+ const unsigned char *data;
+ size_t size;
+};
+
+static inline bool
+extract_8 (struct in_buffer *in, unsigned char *value)
+{
+ if (in->size == 0)
+ return false;
+ *value = in->data[0];
+ ++in->data;
+ --in->size;
+ return true;
+}
+
+static inline bool
+extract_16 (struct in_buffer *in, unsigned short *value)
+{
+ if (in->size < 2)
+ return false;
+ *value = (in->data[0] << 8) | in->data[1];
+ in->data += 2;
+ in->size -= 2;
+ return true;
+}
+
+static inline bool
+extract_32 (struct in_buffer *in, unsigned *value)
+{
+ if (in->size < 4)
+ return false;
+ unsigned a = in->data[0];
+ unsigned b = in->data[1];
+ unsigned c = in->data[2];
+ unsigned d = in->data[3];
+ *value = (a << 24) | (b << 16) | (c << 8) | d;
+ in->data += 4;
+ in->size -= 4;
+ return true;
+}
+
+static inline bool
+extract_bytes (struct in_buffer *in, size_t length, struct in_buffer *value)
+{
+ if (in->size < length)
+ return false;
+ *value = (struct in_buffer) {in->data, length};
+ in->data += length;
+ in->size -= length;
+ return true;
+}
+
+struct dname
+{
+ char name[MAXDNAME + 1];
+};
+
+static bool
+extract_name (struct in_buffer full, struct in_buffer *in, struct dname *value)
+{
+ const unsigned char *full_end = full.data + full.size;
+ /* Sanity checks; these indicate buffer misuse. */
+ TEST_VERIFY_EXIT
+ (!(in->data < full.data || in->data > full_end
+ || in->size > (size_t) (full_end - in->data)));
+ int ret = dn_expand (full.data, full_end, in->data,
+ value->name, sizeof (value->name));
+ if (ret < 0)
+ return false;
+ in->data += ret;
+ in->size -= ret;
+ return true;
+}
+
+char *
+support_format_dns_packet (const unsigned char *buffer, size_t length)
+{
+ struct in_buffer full = { buffer, length };
+ struct in_buffer in = full;
+ struct xmemstream mem;
+ xopen_memstream (&mem);
+
+ unsigned short txnid;
+ unsigned short flags;
+ unsigned short qdcount;
+ unsigned short ancount;
+ unsigned short nscount;
+ unsigned short adcount;
+ if (!(extract_16 (&in, &txnid)
+ && extract_16 (&in, &flags)
+ && extract_16 (&in, &qdcount)
+ && extract_16 (&in, &ancount)
+ && extract_16 (&in, &nscount)
+ && extract_16 (&in, &adcount)))
+ {
+ fprintf (mem.out, "error: could not parse DNS header\n");
+ goto out;
+ }
+ if (qdcount != 1)
+ {
+ fprintf (mem.out, "error: question count is %d, not 1\n", qdcount);
+ goto out;
+ }
+ struct dname qname;
+ if (!extract_name (full, &in, &qname))
+ {
+ fprintf (mem.out, "error: malformed QNAME\n");
+ goto out;
+ }
+ unsigned short qtype;
+ unsigned short qclass;
+ if (!(extract_16 (&in, &qtype)
+ && extract_16 (&in, &qclass)))
+ {
+ fprintf (mem.out, "error: malformed question\n");
+ goto out;
+ }
+ if (qtype != T_A && qtype != T_AAAA && qtype != T_PTR)
+ {
+ fprintf (mem.out, "error: unsupported QTYPE %d\n", qtype);
+ goto out;
+ }
+
+ fprintf (mem.out, "name: %s\n", qname.name);
+
+ for (int i = 0; i < ancount; ++i)
+ {
+ struct dname rname;
+ if (!extract_name (full, &in, &rname))
+ {
+ fprintf (mem.out, "error: malformed record name\n");
+ goto out;
+ }
+ unsigned short rtype;
+ unsigned short rclass;
+ unsigned ttl;
+ unsigned short rdlen;
+ struct in_buffer rdata;
+ if (!(extract_16 (&in, &rtype)
+ && extract_16 (&in, &rclass)
+ && extract_32 (&in, &ttl)
+ && extract_16 (&in, &rdlen)
+ && extract_bytes (&in, rdlen, &rdata)))
+ {
+ fprintf (mem.out, "error: malformed record header\n");
+ goto out;
+ }
+ /* Skip non-matching record types. */
+ if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass)
+ continue;
+ switch (rtype)
+ {
+ case T_A:
+ if (rdlen == 4)
+ fprintf (mem.out, "address: %d.%d.%d.%d\n",
+ rdata.data[0],
+ rdata.data[1],
+ rdata.data[2],
+ rdata.data[3]);
+ else
+ fprintf (mem.out, "error: A record of size %d: %s\n",
+ rdlen, rname.name);
+ break;
+ case T_AAAA:
+ {
+ if (rdlen == 16)
+ {
+ char buf[100];
+ if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL)
+ fprintf (mem.out, "error: AAAA record decoding failed: %m\n");
+ else
+ fprintf (mem.out, "address: %s\n", buf);
+ }
+ else
+ fprintf (mem.out, "error: AAAA record of size %d: %s\n",
+ rdlen, rname.name);
+ }
+ break;
+ case T_CNAME:
+ case T_PTR:
+ {
+ struct dname name;
+ if (extract_name (full, &rdata, &name))
+ fprintf (mem.out, "name: %s\n", name.name);
+ else
+ fprintf (mem.out, "error: malformed CNAME/PTR record\n");
+ }
+ }
+ }
+
+ out:
+ xfclose_memstream (&mem);
+ return mem.buffer;
+}