diff options
Diffstat (limited to 'src/libs6dns/s6dns_analyze_packet.c')
-rw-r--r-- | src/libs6dns/s6dns_analyze_packet.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/libs6dns/s6dns_analyze_packet.c b/src/libs6dns/s6dns_analyze_packet.c new file mode 100644 index 0000000..57a5ce5 --- /dev/null +++ b/src/libs6dns/s6dns_analyze_packet.c @@ -0,0 +1,127 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/uint16.h> +#include <skalibs/bytestr.h> +#include <skalibs/genwrite.h> +#include <skalibs/fmtscan.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-analyze.h> + +#define add(s) if ((*gp->put)(gp->target, (s), str_len(s)) < 0) return 0 +#define addfmt(n) if ((*gp->put)(gp->target, fmt, uint_fmt(fmt, (n))) < 0) return 0 +#define addfmt16(n) if ((*gp->put)(gp->target, fmt, uint16_fmt(fmt, (n))) < 0) return 0 + +int s6dns_analyze_packet (genwrite_t *gp, char const *packet, unsigned int packetlen, int rec) +{ + s6dns_message_header_t h ; + s6dns_message_counts_t counts ; + unsigned int pos ; + unsigned int section ; + char fmt[UINT_FMT] ; + if (!s6dns_message_parse_init(&h, &counts, packet, packetlen, &pos)) + return 0 ; + + addfmt(packetlen) ; + add(" bytes, ") ; + addfmt16(counts.qd) ; + add("+") ; + addfmt16(counts.an) ; + add("+") ; + addfmt16(counts.ns) ; + add("+") ; + addfmt16(counts.nr) ; + add(" records") ; + if (h.qr) add(", response") ; + if (h.opcode) + { + add(", weird op (") ; + addfmt(h.opcode) ; + add(")") ; + } + if (h.aa) add(", authoritative") ; + if (h.tc) add(", truncated") ; + if (h.rd) + { + add(", ") ; + if (!rec) add("weird ") ; + add("rd") ; + } + if (h.ra) + { + add(", ") ; + if (!rec) add("weird ") ; + add("ra") ; + } + switch (h.rcode) + { + case 0 : add(", noerror") ; break ; + case 1 : add(", fmterror") ; break ; + case 2 : add(", servfail") ; break ; + case 3 : add(", nxdomain") ; break ; + case 4 : add(", notimpl") ; break ; + case 5 : add(", refused") ; break ; + default: + { + add(", weird rcode (") ; + addfmt(h.rcode) ; + add(")") ; + } + } + if (h.z) + { + add(", weird z (") ; + addfmt(h.z) ; + add(")") ; + } + add("\n") ; + + for (;;) + { + s6dns_domain_t d ; + char buf[257] ; + unsigned int len ; + uint16 qtype ; + uint16 qclass ; + section = s6dns_message_counts_next(&counts) ; + if (section != 1) break ; + add("query: ") ; + if (!s6dns_message_get_domain(&d, packet, packetlen, &pos)) return 0 ; + len = s6dns_domain_tostring(buf, 255, &d) ; + if (!len) return 0 ; + buf[len++] = '\n' ; buf[len++] = 0 ; + if (pos + 4 > packetlen) return (errno = EPROTO, 0) ; + uint16_unpack_big(packet + pos, &qtype) ; pos += 2 ; + uint16_unpack_big(packet + pos, &qclass) ; pos += 2 ; + if (qclass != S6DNS_C_IN) + { + add("weird class (") ; + addfmt16(qclass) ; + add(") - ") ; + } + addfmt16(qtype) ; + add(" ") ; + add(buf) ; + } + + while (section) + { + static char const *intro[3] = { "answer: ", "authority: ", "additional: " } ; + s6dns_message_rr_t rr ; + if (!s6dns_message_parse_getrr(&rr, packet, packetlen, &pos)) return 0 ; + add(intro[section-2]) ; + if (rr.rclass != S6DNS_C_IN) + { + add("weird class (") ; + addfmt16(rr.rclass) ; + add("), not attempting to analyze record\n") ; + } + else if (!s6dns_analyze_record(gp, &rr, packet, packetlen, pos)) return 0 ; + section = s6dns_message_parse_next(&counts, &rr, packet, packetlen, &pos) ; + } + + return 1 ; +} |