#define DNS_C /* * Copyright (C) 2004, 2005 James Antill * * This 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 of the License, or (at your option) any later version. * * This 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * email: james@and.org */ /* dns resolving, meant for async calls ... TCP only atm. */ #define VSTR_COMPILE_INCLUDE 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* #define NDEBUG 1 -- done via. ./configure */ #include #include #include #include #include "dns.h" #include "vlg.h" #define TRUE 1 #define FALSE 0 #include "app.h" #define MAP_MAKE_ENTRY(x) [ DNS_CLASS_ ## x ] = #x static const char *dns_map_class2name[DNS_CLASS_ALL + 1] = { MAP_MAKE_ENTRY(IN), MAP_MAKE_ENTRY(CH), MAP_MAKE_ENTRY(HS), [DNS_CLASS_ALL] = "*" }; #undef MAP_MAKE_ENTRY #define MAP_MAKE_ENTRY(x) [ DNS_TYPE_IN_ ## x ] = #x static const char *dns_map_type_in2name[DNS_TYPE_ALL + 1] = { MAP_MAKE_ENTRY(A), MAP_MAKE_ENTRY(NS), MAP_MAKE_ENTRY(CNAME), MAP_MAKE_ENTRY(SOA), MAP_MAKE_ENTRY(PTR), MAP_MAKE_ENTRY(MX), MAP_MAKE_ENTRY(TXT), MAP_MAKE_ENTRY(AAAA), MAP_MAKE_ENTRY(SRV), MAP_MAKE_ENTRY(AXFR), MAP_MAKE_ENTRY(IXFR), [DNS_TYPE_ALL] = "*" }; #undef MAP_MAKE_ENTRY #define MAP_MAKE_ENTRY(x) [ DNS_TYPE_CH_ ## x ] = #x static const char *dns_map_type_ch2name[DNS_TYPE_ALL + 1] = { MAP_MAKE_ENTRY(A), MAP_MAKE_ENTRY(TXT), [DNS_TYPE_ALL] = "*" }; #undef MAP_MAKE_ENTRY #define MAP_MAKE_ENTRY(x) [ DNS_HDR_R_ ## x ] = #x static const char *dns_map_hdr_r2name[DNS_HDR_RSZ] = { MAP_MAKE_ENTRY(NONE), MAP_MAKE_ENTRY(BFMT), MAP_MAKE_ENTRY(SERV), MAP_MAKE_ENTRY(NAME), MAP_MAKE_ENTRY(NSUP), MAP_MAKE_ENTRY(REFU), }; #undef MAP_MAKE_ENTRY unsigned int dns_get_msg_len(Vstr_base *s1, size_t pos) { if (s1->len < pos + 1) return (0); return (2 + get_b_uint16(s1, pos)); } const char *dns_name_type_ch(unsigned int num) { if (num > DNS_TYPE_ALL) return (""); if (!dns_map_type_ch2name[num]) return (""); return (dns_map_type_ch2name[num]); } const char *dns_name_type_in(unsigned int num) { if (num > DNS_TYPE_ALL) return (""); if (!dns_map_type_in2name[num]) return (""); return (dns_map_type_in2name[num]); } const char *dns_name_class(unsigned int num) { if (num > DNS_CLASS_ALL) return (""); if (!dns_map_class2name[num]) return (""); return (dns_map_class2name[num]); } const char *dns_name_hdr_r(unsigned int num) { if (num > DNS_HDR_RSZ) return (""); if (!dns_map_hdr_r2name[num]) return (""); return (dns_map_hdr_r2name[num]); } static size_t dns_app_class_type(Vstr_base *out, Vstr_base *pkt, size_t pos, size_t msg_len, unsigned int *dns_class, unsigned int *dns_type) { unsigned int cnum = 0; unsigned int tnum = 0; if (4 > vstr_sc_posdiff(pos, msg_len)) return (msg_len); tnum = get_b_uint16(pkt, pos); pos += 2; cnum = get_b_uint16(pkt, pos); pos += 2; if (dns_class) *dns_class = cnum; if (dns_type) *dns_type = tnum; if (out) { if (dns_name_class(cnum)) app_cstr_buf(out, dns_name_class(cnum)); else app_fmt(out, "%u", cnum); app_cstr_buf(out, "."); } if (out) switch (cnum) { case DNS_CLASS_IN: app_cstr_buf(out, dns_name_type_in(tnum)); break; case DNS_CLASS_CH: app_cstr_buf(out, dns_name_type_ch(tnum)); break; case DNS_CLASS_ALL: if (tnum == DNS_TYPE_ALL) { app_cstr_buf(out, "*"); break; } /* FALL THROUGH */ default: app_fmt(out, "%u", tnum); break; } return (pos); } static size_t dns_app_txt(Vstr_base *out, Vstr_base *pkt, size_t pos, size_t msg_len) { unsigned char tmp = 0; while ((pos < msg_len) && (tmp = vstr_export_chr(pkt, pos))) { ++pos; if (tmp > vstr_sc_posdiff(pos, msg_len)) tmp = vstr_sc_posdiff(pos, msg_len); if (out) app_fmt(out, "${vstr:%p%zu%zu%u}", pkt, pos, tmp, VSTR_TYPE_ADD_ALL_BUF); pos += tmp; } if (pos <= msg_len) ++pos; return (pos); } #define OUT_EQ_VLOG() (out == base->io_dbg->out_vstr) static size_t dns_app_label(Dns_base *base, Vstr_base *out, Vstr_base *pkt, size_t pos, size_t msg_len) { unsigned char tmp = 0; while ((pos < msg_len) && (tmp = vstr_export_chr(pkt, pos))) { if (DNS_LABEL_IS_PTR(tmp)) { /* ptr */ if (OUT_EQ_VLOG()) app_cstr_buf(out, " "); return (msg_len); } /* label */ ++pos; if (tmp > vstr_sc_posdiff(pos, msg_len)) tmp = vstr_sc_posdiff(pos, msg_len); if (out) app_fmt(out, "${vstr:%p%zu%zu%u}.", pkt, pos, tmp, VSTR_TYPE_ADD_ALL_BUF); pos += tmp; } if (pos <= msg_len) ++pos; return (pos); } static size_t dns_app_name(Dns_base *base, Vstr_base *out, Vstr_base *pkt, size_t pos, size_t msg_len) { size_t orig_pos = pos; unsigned char tmp = 0; while ((pos < msg_len) && (tmp = vstr_export_chr(pkt, pos))) { if (DNS_LABEL_IS_PTR(tmp)) { unsigned int off = get_b_uint16(pkt, pos); off &= ~0xC000; /* remove top bits that specifiy it's a ptr */ ++off; /* offset is 0 indexed, position is 1 indexed */ if ((off != orig_pos) && (off < pos)) dns_app_name(base, out, pkt, off, msg_len); else if (OUT_EQ_VLOG()) app_cstr_buf(out, " "); return (pos + 2); } ++pos; if (tmp > vstr_sc_posdiff(pos, msg_len)) tmp = vstr_sc_posdiff(pos, msg_len); if (out) app_fmt(out, "${vstr:%p%zu%zu%u}.", pkt, pos, tmp, VSTR_TYPE_ADD_ALL_BUF); pos += tmp; } if (pos <= msg_len) ++pos; return (pos); } static size_t dns_app_ttl(Vstr_base *out, Vstr_base *pkt, size_t pos, size_t msg_len) { unsigned int num = 0; if (4 > vstr_sc_posdiff(pos, msg_len)) return (msg_len); num = get_b_uint32(pkt, pos); if (out) app_fmt(out, " for %ud %02u:%02u:%02u", (num / (1 * 60 * 60 * 24)), (num / (1 * 60 * 60)) % 24, (num / (1 * 60)) % 60, (num / (1)) % 60); return (pos + 4); } static size_t dns_app_rr_unknown_data(Dns_base *base, Vstr_base *pkt, size_t pos, size_t msg_len, unsigned int len) { (void)pkt; vlg_dbg2(base->io_dbg, " RD: %u %zu\n", len, vstr_sc_posdiff(pos, msg_len)); if (len <= vstr_sc_posdiff(pos, msg_len)) return (pos + len); return (msg_len); } static size_t dns_app_rr_data(Dns_base *base, Vstr_base *out, Vstr_base *pkt, size_t pos, size_t msg_len, unsigned int dns_class, unsigned int dns_type) { unsigned int len = 0; if (2 > vstr_sc_posdiff(pos, msg_len)) return (msg_len); len = get_b_uint16(pkt, pos); pos += 2; if (!len) return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len)); if (len > (vstr_sc_posdiff(pos, msg_len))) return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len)); if ((dns_class != DNS_CLASS_IN) && (dns_class != DNS_CLASS_CH)) return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len)); msg_len = vstr_sc_poslast(pos, len); if (dns_class == DNS_CLASS_CH) { if (0) { } else if (dns_type == DNS_TYPE_CH_A) { unsigned int num = 0; if (OUT_EQ_VLOG()) app_cstr_buf(out, " NAME: "); pos = dns_app_name(base, out, pkt, pos, msg_len); if (2 > vstr_sc_posdiff(pos, msg_len)) return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len)); num = get_b_uint16(pkt, pos); pos += 2; if (OUT_EQ_VLOG()) app_cstr_buf(out, " A: "); if (out) app_fmt(out, " %u", num); } else if (dns_type == DNS_TYPE_CH_TXT) { if (OUT_EQ_VLOG()) app_cstr_buf(out, " TXT: "); pos = dns_app_txt(out, pkt, pos, msg_len); } else return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len)); } if (dns_class == DNS_CLASS_IN) { if (0) { } else if (dns_type == DNS_TYPE_IN_A) { unsigned char buf[4]; if (len != 4) return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len)); vstr_export_buf(pkt, pos, 4, buf, sizeof(buf)); pos += 4; if (OUT_EQ_VLOG()) app_cstr_buf(out, " A: "); if (out) app_fmt(out, "%u.%u.%u.%u", buf[0], buf[1], buf[2], buf[3]); } else if (dns_type == DNS_TYPE_IN_NS) { if (OUT_EQ_VLOG()) app_cstr_buf(out, " NS: "); pos = dns_app_name(base, out, pkt, pos, msg_len); } else if (dns_type == DNS_TYPE_IN_CNAME) { if (OUT_EQ_VLOG()) app_cstr_buf(out, " CNAME: "); pos = dns_app_name(base, out, pkt, pos, msg_len); } else if (dns_type == DNS_TYPE_IN_SOA) { unsigned int num_serial = 0; unsigned int num_refresh = 0; unsigned int num_retry = 0; unsigned int num_expire = 0; unsigned int num_min = 0; if (OUT_EQ_VLOG()) app_cstr_buf(out, " SOA:\n"); if (OUT_EQ_VLOG()) app_cstr_buf(out, " NS: "); pos = dns_app_name(base, out, pkt, pos, msg_len); if (OUT_EQ_VLOG()) app_cstr_buf(out, "\n"); else if (out) app_cstr_buf(out, " "); if (OUT_EQ_VLOG()) app_cstr_buf(out, " ROOT: "); pos = dns_app_name(base, out, pkt, pos, msg_len); if (OUT_EQ_VLOG()) app_cstr_buf(out, "\n"); else if (out) app_cstr_buf(out, " "); if (16 > vstr_sc_posdiff(pos, msg_len)) return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len)); num_serial = get_b_uint32(pkt, pos); pos += 4; num_refresh = get_b_uint32(pkt, pos); pos += 4; num_retry = get_b_uint32(pkt, pos); pos += 4; num_expire = get_b_uint32(pkt, pos); pos += 4; num_min = get_b_uint32(pkt, pos); pos += 4; if (OUT_EQ_VLOG()) app_fmt(out, " SERIAL: %u REFRESH: %u" " RETRY: %u EXPIRE: %u MIN: %u", num_serial, num_refresh, num_retry, num_expire, num_min); else if (out) app_fmt(out, " %u %u %u %u %u", num_serial, num_refresh, num_retry, num_expire, num_min); } else if (dns_type == DNS_TYPE_IN_PTR) { if (OUT_EQ_VLOG()) app_cstr_buf(out, " PTR: "); pos = dns_app_name(base, out, pkt, pos, msg_len); } else if (dns_type == DNS_TYPE_IN_HINFO) { if (OUT_EQ_VLOG()) app_cstr_buf(out, " CPU: "); pos = dns_app_txt(out, pkt, pos, msg_len); if (out) app_cstr_buf(out, " "); if (OUT_EQ_VLOG()) app_cstr_buf(out, "OS: "); pos = dns_app_txt(out, pkt, pos, msg_len); } else if (dns_type == DNS_TYPE_IN_MX) { unsigned int num = 0; if (len < 4) return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len)); num = get_b_uint16(pkt, pos); pos += 2; if (OUT_EQ_VLOG()) app_cstr_buf(out, " PREF: "); if (out) app_fmt(out, "%u ", num); if (OUT_EQ_VLOG()) app_cstr_buf(out, "NAME: "); pos = dns_app_name(base, out, pkt, pos, msg_len); } else if (dns_type == DNS_TYPE_IN_TXT) { if (OUT_EQ_VLOG()) app_cstr_buf(out, " TXT: "); pos = dns_app_txt(out, pkt, pos, msg_len); } else if (dns_type == DNS_TYPE_IN_SRV) { unsigned int num_pri = 0; unsigned int num_weight = 0; unsigned int num_port = 0; if (len < 8) return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len)); num_pri = get_b_uint16(pkt, pos); pos += 2; num_weight = get_b_uint16(pkt, pos); pos += 2; num_port = get_b_uint16(pkt, pos); pos += 2; if (OUT_EQ_VLOG()) app_fmt(out, " PRI: %u WEIGHT: %u PORT: %u NAME: ", num_pri, num_weight, num_port); else if (out) app_fmt(out, " %u %u %u ", num_pri, num_weight, num_port); pos = dns_app_name(base, out, pkt, pos, msg_len); } else return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len)); } return (pos); } void dns_dbg_prnt_pkt(Dns_base *base, Vstr_base *pkt) { size_t pos = 1; unsigned int id = 0; unsigned int flags = 0; unsigned int qdc = 0; unsigned int anc = 0; unsigned int nsc = 0; unsigned int arc = 0; unsigned int scan= 0; const size_t msg_len = pkt->len; int prefix = FALSE; if (!base->io_dbg->out_dbg) return; prefix = vlg_prefix_set(base->io_dbg, FALSE); if (12 <= msg_len) { id = get_b_uint16(pkt, pos); pos += 2; flags = get_b_uint16(pkt, pos); pos += 2; qdc = get_b_uint16(pkt, pos); pos += 2; anc = get_b_uint16(pkt, pos); pos += 2; nsc = get_b_uint16(pkt, pos); pos += 2; arc = get_b_uint16(pkt, pos); pos += 2; vlg_dbg1(base->io_dbg, " id=%u\n", id); vlg_dbg1(base->io_dbg, " %*s: op=%u |%s|%s|%s|%s| z=%d ret=%d ->" " qd=%u an=%u ns=%u ar=%u\n", (int)strlen("Response"), ((flags & DNS_HDR_QR) ? "Response" : "Query"), ((flags & DNS_HDR_OPCMASK) >> DNS_HDR_OPCOFF), ((flags & DNS_HDR_AA) ? "AA" : " "), ((flags & DNS_HDR_TC) ? "TC" : " "), ((flags & DNS_HDR_RD) ? "RD" : " "), ((flags & DNS_HDR_RA) ? "RA" : " "), ((flags & DNS_HDR_ZMASK) >> DNS_HDR_ZOFF), ((flags & DNS_HDR_RMASK) >> DNS_HDR_ROFF), qdc, anc, nsc, arc); } else vlg_dbg1(base->io_dbg, "\n"); scan = 0; while ((scan++ < qdc) && (6 <= vstr_sc_posdiff(pos, msg_len))) { vlg_dbg1(base->io_dbg, " QUERY(%u/%u): ", scan, qdc); pos = dns_app_label(base, base->io_dbg->out_vstr, pkt, pos, msg_len); vlg_dbg1(base->io_dbg, " "); pos = dns_app_class_type(base->io_dbg->out_vstr, pkt, pos, msg_len, NULL, NULL); vlg_dbg1(base->io_dbg, "\n"); } scan = 0; while ((scan++ < (anc + nsc + arc)) && (12 <= vstr_sc_posdiff(pos, msg_len))) { unsigned int dns_class = 0; unsigned int dns_type = 0; if (0) { } else if (anc && (scan <= (anc))) vlg_dbg1(base->io_dbg, " AN-RR(%u/%u): ", scan, anc); else if (nsc && (scan <= (anc + nsc))) vlg_dbg1(base->io_dbg, " NS-RR(%u/%u): ", scan - anc, nsc); else vlg_dbg1(base->io_dbg, " AR-RR(%u/%u): ", scan - (anc + nsc), arc); pos = dns_app_name(base, base->io_dbg->out_vstr, pkt, pos, msg_len); vlg_dbg1(base->io_dbg, " "); pos = dns_app_class_type(base->io_dbg->out_vstr, pkt, pos, msg_len, &dns_class, &dns_type); pos = dns_app_ttl(base->io_dbg->out_vstr, pkt, pos, msg_len); vlg_dbg1(base->io_dbg, "\n"); pos = dns_app_rr_data(base, base->io_dbg->out_vstr, pkt, pos, msg_len, dns_class, dns_type); vlg_dbg1(base->io_dbg, "\n"); } vlg_prefix_set(base->io_dbg, prefix); } void dns_app_recq_pkt(Dns_base *base, unsigned int qcount, ...) { Vstr_base *io_w = base->io_w_serv; va_list ap; size_t pos1 = 0; size_t len1 = 0; unsigned int id = 0; Vstr_base *s1 = vstr_make_base(io_w->conf); size_t srch_pos = 0; size_t srch_len = 0; if (!s1) errno = ENOMEM, err(EXIT_FAILURE, __func__); pos1 = io_w->len + 1; app_b_uint16(io_w, 0); /* TCP length */ id = rand(); id &= 0xFFFF; app_b_uint16(io_w, id); app_b_uint16(io_w, DNS_HDR_OPC_QUERY | (base->opt_recur ? DNS_HDR_RD : 0)); app_b_uint16(io_w, qcount); app_b_uint16(io_w, 0); app_b_uint16(io_w, 0); app_b_uint16(io_w, 0); va_start(ap, qcount); while (qcount--) { const char *name = va_arg(ap, const char *); unsigned int dns_class = va_arg(ap, unsigned int); unsigned int dns_type = va_arg(ap, unsigned int); assert(name); vstr_sub_cstr_ptr(s1, 1, s1->len, name); if ((dns_class == DNS_CLASS_IN) && (dns_type == DNS_TYPE_IN_PTR)) { /* magic remapping for ptr */ unsigned char ipv4[4]; unsigned int ipv6[8]; unsigned int ern = 0; if (0) { } else if (vstr_parse_ipv4(s1, 1, s1->len, ipv4, NULL, VSTR_FLAG_PARSE_IPV4_FULL | VSTR_FLAG_PARSE_IPV4_ONLY, NULL, &ern) && !ern) { vstr_del(s1, 1, s1->len); vstr_add_fmt(s1, s1->len, "%u.%u.%u.%u.in-addr.arpa", ipv4[3], ipv4[2], ipv4[1], ipv4[0]); } else if (vstr_parse_ipv6(s1, 1, s1->len, ipv6, NULL, VSTR_FLAG_PARSE_IPV6_ONLY, NULL, &ern) && !ern) { vstr_del(s1, 1, s1->len); # define IP6_INT2BYTES(x) \ (ipv6[(x)] >> 0) & 0xF, \ (ipv6[(x)] >> 4) & 0xF, \ (ipv6[(x)] >> 8) & 0xF, \ (ipv6[(x)] >> 12) & 0xF vstr_add_fmt(s1, s1->len, "%x.%x.%x.%x." "%x.%x.%x.%x." "%x.%x.%x.%x." "%x.%x.%x.%x." "%x.%x.%x.%x." "%x.%x.%x.%x." "%x.%x.%x.%x." "%x.%x.%x.%x." "ip6.int", IP6_INT2BYTES(7), IP6_INT2BYTES(6), IP6_INT2BYTES(5), IP6_INT2BYTES(4), IP6_INT2BYTES(3), IP6_INT2BYTES(2), IP6_INT2BYTES(1), IP6_INT2BYTES(0)); # undef IP6_INT2BYTES } } /* question */ srch_pos = vstr_csrch_cstr_chrs_fwd(s1, 1, s1->len, "."); srch_len = vstr_sc_posdiff(srch_pos, s1->len); while (srch_len) { size_t difflen = vstr_cspn_cstr_chrs_fwd(s1, srch_pos, srch_len, "."); if (!difflen) /* ignore spurious '.' */ difflen = vstr_spn_cstr_chrs_fwd(s1, srch_pos, srch_len, "."); else { app_b_uint8(io_w, difflen); app_vstr(io_w, s1, srch_pos, difflen, VSTR_TYPE_ADD_ALL_BUF); if (difflen != srch_len) ++difflen; } assert(difflen <= srch_len); srch_len -= difflen; srch_pos += difflen; } app_b_uint8(io_w, 0); /* 0 length label is terminator */ app_b_uint16(io_w, dns_type); app_b_uint16(io_w, dns_class); } va_end(ap); if (io_w->conf->malloc_bad) errno = ENOMEM, err(EXIT_FAILURE, __func__); /* make the lengths correct */ len1 = io_w->len - (pos1 - 1); sub_b_uint16(io_w, pos1, len1 - 2); vlg_dbg1(base->io_dbg, "\n${rep_chr:%c%zu} send ${BKMG.u:%u} ${rep_chr:%c%zu}\n", '=', 33, len1 - 2, '=', 33); if (base->io_dbg->out_dbg >= 1) vstr_sub_vstr(s1, 1, s1->len, io_w, pos1 + 2, len1 - 2, VSTR_TYPE_ADD_BUF_PTR); dns_dbg_prnt_pkt(base, s1); vlg_dbg1(base->io_dbg, "\n${rep_chr:%c%zu}\n", '-', 79); vstr_free_base(s1); io_w->conf->malloc_bad = FALSE; } void dns_sc_ui_out(Dns_base *base, Vstr_base *pkt) { Vstr_base *io_w = base->io_w_user; size_t pos = 1; unsigned int id = 0; unsigned int flags = 0; unsigned int qdc = 0; unsigned int anc = 0; unsigned int nsc = 0; unsigned int arc = 0; unsigned int scan = 0; const size_t msg_len = pkt->len; if (12 <= msg_len) { id = get_b_uint16(pkt, pos); pos += 2; flags = get_b_uint16(pkt, pos); pos += 2; qdc = get_b_uint16(pkt, pos); pos += 2; anc = get_b_uint16(pkt, pos); pos += 2; nsc = get_b_uint16(pkt, pos); pos += 2; arc = get_b_uint16(pkt, pos); pos += 2; } /* can't check id atm. */ if (!(flags & DNS_HDR_QR)) return; if (!anc) { scan = 0; while ((scan++ < qdc) && (6 <= vstr_sc_posdiff(pos, msg_len))) { unsigned int hdr_r_code = ((flags & DNS_HDR_RMASK) >> DNS_HDR_ROFF); pos = dns_app_label(base, io_w, pkt, pos, msg_len); app_cstr_buf(io_w, " "); pos = dns_app_class_type(io_w, pkt, pos, msg_len, NULL, NULL); app_fmt(io_w, ":ret=%d#%s\n", hdr_r_code, dns_name_hdr_r(hdr_r_code)); } return; } scan = 0; while ((scan++ < qdc) && (6 <= vstr_sc_posdiff(pos, msg_len))) { pos = dns_app_label(base, NULL, pkt, pos, msg_len); pos = dns_app_class_type(NULL, pkt, pos, msg_len, NULL, NULL); } scan = 0; while ((scan++ < anc) && (12 <= vstr_sc_posdiff(pos, msg_len))) { unsigned int dns_class = 0; unsigned int dns_type = 0; pos = dns_app_name(base, io_w, pkt, pos, msg_len); app_cstr_buf(io_w, " "); pos = dns_app_class_type(io_w, pkt, pos, msg_len, &dns_class, &dns_type); app_cstr_buf(io_w, " "); pos = dns_app_ttl(NULL, pkt, pos, msg_len); pos = dns_app_rr_data(base, io_w, pkt, pos, msg_len, dns_class, dns_type); app_cstr_buf(io_w, "\n"); } }