diff options
author | 2012-04-14 09:24:18 +0000 | |
---|---|---|
committer | 2012-04-14 09:24:18 +0000 | |
commit | b44da6278dfc5a9ac4bcab6662bc7def6c347a68 (patch) | |
tree | cbe5fcbe427706b86755f57914f80402178c4fa0 /lib/libc/asr/asr_debug.c | |
parent | Free tmp buffer in case the cluster allocation failed. Found by David Hill. (diff) | |
download | wireguard-openbsd-b44da6278dfc5a9ac4bcab6662bc7def6c347a68.tar.xz wireguard-openbsd-b44da6278dfc5a9ac4bcab6662bc7def6c347a68.zip |
Import asr, an experimental async resolver implementation.
The idea is to eventually replace the existing resolver with
something better. Time to start working on it in tree.
ok deraadt@
Diffstat (limited to 'lib/libc/asr/asr_debug.c')
-rw-r--r-- | lib/libc/asr/asr_debug.c | 569 |
1 files changed, 569 insertions, 0 deletions
diff --git a/lib/libc/asr/asr_debug.c b/lib/libc/asr/asr_debug.c new file mode 100644 index 00000000000..1305633c352 --- /dev/null +++ b/lib/libc/asr/asr_debug.c @@ -0,0 +1,569 @@ +/* $OpenBSD: asr_debug.c,v 1.1 2012/04/14 09:24:18 eric Exp $ */ +/* + * Copyright (c) 2010-2012 Eric Faurot <eric@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <inttypes.h> +#include <resolv.h> +#include <string.h> +#include <stdarg.h> + +#include "asr.h" +#include "asr_private.h" + +static void asr_vdebug(const char *, va_list); + +static char *print_dname(const char *, char *, size_t); +static char *print_host(const struct sockaddr *, char *, size_t); + +static const char *typetostr(uint16_t); +static const char *classtostr(uint16_t); +static const char *rcodetostr(uint16_t); + +static const char *inet6_ntoa(struct in6_addr); + + +#define OPCODE_SHIFT 11 +#define Z_SHIFT 4 + +struct keyval { + const char *key; + uint16_t value; +}; + +static struct keyval kv_class[] = { + { "IN", C_IN }, + { "CHAOS", C_CHAOS }, + { "HS", C_HS }, + { "ANY", C_ANY }, + { NULL, 0 }, +}; + +static struct keyval kv_type[] = { + { "A", T_A }, + { "NS", T_NS }, + { "MD", T_MD }, + { "MF", T_MF }, + { "CNAME", T_CNAME }, + { "SOA", T_SOA }, + { "MB", T_MB }, + { "MG", T_MG }, + { "MR", T_MR }, + { "NULL", T_NULL }, + { "WKS", T_WKS }, + { "PTR", T_PTR }, + { "HINFO", T_HINFO }, + { "MINFO", T_MINFO }, + { "MX", T_MX }, + { "TXT", T_TXT }, + + { "AAAA", T_AAAA }, + + { "AXFR", T_AXFR }, + { "MAILB", T_MAILB }, + { "MAILA", T_MAILA }, + { "ANY", T_ANY }, + { NULL, 0 }, +}; + +static struct keyval kv_rcode[] = { + { "NOERROR", NOERROR }, + { "FORMERR", FORMERR }, + { "SERVFAIL", SERVFAIL }, + { "NXDOMAIN", NXDOMAIN }, + { "NOTIMP", NOTIMP }, + { "REFUSED", REFUSED }, + { NULL, 0 }, +}; + +static const char * +typetostr(uint16_t v) +{ + static char buf[16]; + size_t i; + + for(i = 0; kv_type[i].key; i++) + if (kv_type[i].value == v) + return (kv_type[i].key); + + snprintf(buf, sizeof buf, "%"PRIu16"?", v); + + return (buf); +} + +static const char * +classtostr(uint16_t v) +{ + static char buf[16]; + size_t i; + + for(i = 0; kv_class[i].key; i++) + if (kv_class[i].value == v) + return (kv_class[i].key); + + snprintf(buf, sizeof buf, "%"PRIu16"?", v); + + return (buf); +} + +static const char * +rcodetostr(uint16_t v) +{ + static char buf[16]; + size_t i; + + for(i = 0; kv_rcode[i].key; i++) + if (kv_rcode[i].value == v) + return (kv_rcode[i].key); + + snprintf(buf, sizeof buf, "%"PRIu16"?", v); + + return (buf); +} + +static const char * +inet6_ntoa(struct in6_addr a) +{ + static char buf[256]; + struct sockaddr_in6 si; + + si.sin6_len = sizeof(si); + si.sin6_family = PF_INET6; + si.sin6_addr = a; + + return print_host((struct sockaddr*)&si, buf, sizeof buf); +} + +static char* +print_rr(struct rr *rr, char *buf, size_t max) +{ + char *res; + char tmp[256]; + char tmp2[256]; + int r; + + res = buf; + + r = snprintf(buf, max, "%s %u %s %s ", + print_dname(rr->rr_dname, tmp, sizeof tmp), + rr->rr_ttl, + classtostr(rr->rr_class), + typetostr(rr->rr_type)); + if (r == -1) { + buf[0] = '\0'; + return buf; + } + + if ((size_t)r >= max) + return buf; + + max -= r; + buf += r; + + switch(rr->rr_type) { + case T_CNAME: + print_dname(rr->rr.cname.cname, buf, max); + break; + case T_MX: + snprintf(buf, max, "%"PRIu32" %s", + rr->rr.mx.preference, + print_dname(rr->rr.mx.exchange, tmp, sizeof tmp)); + break; + case T_NS: + print_dname(rr->rr.ns.nsname, buf, max); + break; + case T_PTR: + print_dname(rr->rr.ptr.ptrname, buf, max); + break; + case T_SOA: + snprintf(buf, max, + "%s %s %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32, + print_dname(rr->rr.soa.rname, tmp, sizeof tmp), + print_dname(rr->rr.soa.mname, tmp2, sizeof tmp2), + rr->rr.soa.serial, + rr->rr.soa.refresh, + rr->rr.soa.retry, + rr->rr.soa.expire, + rr->rr.soa.minimum); + break; + case T_A: + if (rr->rr_class != C_IN) + goto other; + snprintf(buf, max, "%s", inet_ntoa(rr->rr.in_a.addr)); + break; + case T_AAAA: + if (rr->rr_class != C_IN) + goto other; + snprintf(buf, max, "%s", inet6_ntoa(rr->rr.in_aaaa.addr6)); + break; + default: + other: + snprintf(buf, max, "(rdlen=%"PRIu16 ")", rr->rr.other.rdlen); + break; + } + + return (res); +} + +static char* +print_query(struct query *q, char *buf, size_t max) +{ + char b[256]; + + snprintf(buf, max, "%s %s %s", + print_dname(q->q_dname, b, sizeof b), + classtostr(q->q_class), typetostr(q->q_type)); + + return (buf); +} + +static char* +print_dname(const char *_dname, char *buf, size_t max) +{ + return asr_strdname(_dname, buf, max); +} + +static char* +print_header(struct header *h, char *buf, size_t max, int noid) +{ + snprintf(buf, max, + "id:0x%04x %s op:%i %s %s %s %s z:%i r:%s qd:%i an:%i ns:%i ar:%i", + noid ? 0 : ((int)h->id), + (h->flags & QR_MASK) ? "QR":" ", + (int)(OPCODE(h->flags) >> OPCODE_SHIFT), + (h->flags & AA_MASK) ? "AA":" ", + (h->flags & TC_MASK) ? "TC":" ", + (h->flags & RD_MASK) ? "RD":" ", + (h->flags & RA_MASK) ? "RA":" ", + ((h->flags & Z_MASK) >> Z_SHIFT), + rcodetostr(RCODE(h->flags)), + h->qdcount, h->ancount, h->nscount, h->arcount); + + return buf; +} + +static char * +print_host(const struct sockaddr *sa, char *buf, size_t len) +{ + int e; + + if ((e = getnameinfo(sa, sa->sa_len, + buf, len, NULL, 0, NI_NUMERICHOST)) != 0) { + buf[0] = '\0'; + return (NULL); + } + return (buf); +} + +char * +print_addr(const struct sockaddr *sa, char *buf, size_t len) +{ + char h[256]; + + print_host(sa, h, sizeof h); + + switch (sa->sa_family) { + case AF_INET: + snprintf(buf, len, "%s:%i", h, + ntohs(((struct sockaddr_in*)(sa))->sin_port)); + break; + case AF_INET6: + snprintf(buf, len, "[%s]:%i", h, + ntohs(((struct sockaddr_in6*)(sa))->sin6_port)); + break; + default: + snprintf(buf, len, "?"); + break; + } + + return (buf); +} + +struct kv { int code; const char *name; }; + +static const char* kvlookup(struct kv *, int); + +int asr_debug = 0; + +void +asr_dump(struct asr *a) +{ + char buf[256]; + int i; + struct asr_ctx *ac; + unsigned int options; + + ac = a->a_ctx; + + asr_printf("--------- ASR CONFIG ---------------\n"); + if (a->a_path) + asr_printf("CONF FILE \"%s\"\n", a->a_path); + else + asr_printf("STATIC CONF\n"); + asr_printf("DOMAIN \"%s\"\n", ac->ac_domain); + asr_printf("SEARCH\n"); + for(i = 0; i < ac->ac_domcount; i++) + asr_printf(" \"%s\"\n", ac->ac_dom[i]); + asr_printf("OPTIONS\n"); + asr_printf(" options:"); + options = ac->ac_options; + if (options & RES_INIT) { + asr_printf(" INIT"); options &= ~RES_INIT; + } + if (options & RES_DEBUG) { + asr_printf(" DEBUG"); options &= ~RES_DEBUG; + } + if (options & RES_USEVC) { + asr_printf(" USEVC"); options &= ~RES_USEVC; + } + if (options & RES_IGNTC) { + asr_printf(" IGNTC"); options &= ~RES_IGNTC; + } + if (options & RES_RECURSE) { + asr_printf(" RECURSE"); options &= ~RES_RECURSE; + } + if (options & RES_DEFNAMES) { + asr_printf(" DEFNAMES"); options &= ~RES_DEFNAMES; + } + if (options & RES_STAYOPEN) { + asr_printf(" STAYOPEN"); options &= ~RES_STAYOPEN; + } + if (options & RES_DNSRCH) { + asr_printf(" DNSRCH"); options &= ~RES_DNSRCH; + } + if (options & RES_NOALIASES) { + asr_printf(" NOALIASES"); options &= ~RES_NOALIASES; + } + if (options & RES_USE_EDNS0) { + asr_printf(" USE_EDNS0"); options &= ~RES_USE_EDNS0; + } + if (options & RES_USE_DNSSEC) { + asr_printf(" USE_DNSSEC"); options &= ~RES_USE_DNSSEC; + } + if (options) + asr_printf("0x%08x\n", options); + asr_printf("\n", ac->ac_options); + + asr_printf(" ndots: %i\n", ac->ac_ndots); + asr_printf(" family:"); + for(i = 0; ac->ac_family[i] != -1; i++) + asr_printf(" %s", (ac->ac_family[i] == AF_INET) ? "inet" : "inet6"); + asr_printf("\n"); + asr_printf("NAMESERVERS timeout=%i retry=%i\n", + ac->ac_nstimeout, + ac->ac_nsretries); + for(i = 0; i < ac->ac_nscount; i++) + asr_printf(" %s\n", print_addr(ac->ac_ns[i], buf, sizeof buf)); + asr_printf("HOSTFILE %s\n", ac->ac_hostfile); + asr_printf("LOOKUP"); + for(i = 0; i < ac->ac_dbcount; i++) { + switch (ac->ac_db[i]) { + case ASR_DB_FILE: + asr_printf(" file"); + break; + case ASR_DB_DNS: + asr_printf(" dns"); + break; + case ASR_DB_YP: + asr_printf(" yp"); + break; + default: + asr_printf(" ?%i", ac->ac_db[i]); + } + } + asr_printf("\n------------------------------------\n"); +} + +static const char * +kvlookup(struct kv *kv, int code) +{ + while (kv->name) { + if (kv->code == code) + return (kv->name); + kv++; + } + return "???"; +} + +struct kv kv_query_type[] = { + { ASR_SEND, "ASR_SEND" }, + { ASR_SEARCH, "ASR_SEARCH" }, + { ASR_GETRRSETBYNAME, "ASR_GETRRSETBYNAME" }, + { ASR_GETHOSTBYNAME, "ASR_GETHOSTBYNAME" }, + { ASR_GETHOSTBYADDR, "ASR_GETHOSTBYADDR" }, + { ASR_GETNETBYNAME, "ASR_GETNETBYNAME" }, + { ASR_GETNETBYADDR, "ASR_GETNETBYADDR" }, + { ASR_GETADDRINFO, "ASR_GETADDRINFO" }, + { ASR_GETNAMEINFO, "ASR_GETNAMEINFO" }, + { ASR_HOSTADDR, "ASR_HOSTADDR" }, + { 0, NULL } +}; + +struct kv kv_db_type[] = { + { ASR_DB_FILE, "ASR_DB_FILE" }, + { ASR_DB_DNS, "ASR_DB_DNS" }, + { ASR_DB_YP, "ASR_DB_YP" }, + { 0, NULL } +}; + +struct kv kv_state[] = { + { ASR_STATE_INIT, "ASR_STATE_INIT" }, + { ASR_STATE_SEARCH_DOMAIN, "ASR_STATE_SEARCH_DOMAIN" }, + { ASR_STATE_LOOKUP_DOMAIN, "ASR_STATE_LOOKUP_DOMAIN" }, + { ASR_STATE_NEXT_DOMAIN, "ASR_STATE_NEXT_DOMAIN" }, + { ASR_STATE_NEXT_DB, "ASR_STATE_NEXT_DB" }, + { ASR_STATE_SAME_DB, "ASR_STATE_SAME_DB" }, + { ASR_STATE_NEXT_FAMILY, "ASR_STATE_NEXT_FAMILY" }, + { ASR_STATE_LOOKUP_FAMILY, "ASR_STATE_LOOKUP_FAMILY" }, + { ASR_STATE_NEXT_NS, "ASR_STATE_NEXT_NS" }, + { ASR_STATE_READ_RR, "ASR_STATE_READ_RR" }, + { ASR_STATE_READ_FILE, "ASR_STATE_READ_FILE" }, + { ASR_STATE_UDP_SEND, "ASR_STATE_UDP_SEND" }, + { ASR_STATE_UDP_RECV, "ASR_STATE_UDP_RECV" }, + { ASR_STATE_TCP_WRITE, "ASR_STATE_TCP_WRITE" }, + { ASR_STATE_TCP_READ, "ASR_STATE_TCP_READ" }, + { ASR_STATE_PACKET, "ASR_STATE_PACKET" }, + { ASR_STATE_SUBQUERY, "ASR_STATE_SUBQUERY" }, + { ASR_STATE_NOT_FOUND, "ASR_STATE_NOT_FOUND", }, + { ASR_STATE_HALT, "ASR_STATE_HALT" }, + { 0, NULL } +}; + +struct kv kv_transition[] = { + { ASYNC_COND, "ASYNC_COND" }, + { ASYNC_YIELD, "ASYNC_YIELD" }, + { ASYNC_DONE, "ASYNC_DONE" }, + { 0, NULL } +}; + +const char * +asr_querystr(int type) +{ + return kvlookup(kv_query_type, type); +} + +const char * +asr_transitionstr(int type) +{ + return kvlookup(kv_transition, type); +} + +void +asr_dump_async(struct async *as) +{ + asr_printf("%s fd=%i timeout=%i" + " dom_idx=%i db_idx=%i ns_idx=%i ns_cycles=%i\n", + kvlookup(kv_state, as->as_state), + as->as_fd, + as->as_timeout, + + as->as_dom_idx, + as->as_db_idx, + as->as_ns_idx, + as->as_ns_cycles); +} + +void +asr_dump_packet(FILE *f, const void *data, size_t len, int noid) +{ + char buf[1024]; + struct packed p; + struct header h; + struct query q; + struct rr rr; + int i, an, ns, ar, n; + + if (f == NULL) + return; + + packed_init(&p, (char *)data, len); + + if (unpack_header(&p, &h) == -1) { + fprintf(f, ";; BAD PACKET: %s\n", p.err); + return; + } + + fprintf(f, ";; HEADER %s\n", print_header(&h, buf, sizeof buf, noid)); + + if (h.qdcount) + fprintf(f, ";; QUERY SECTION:\n"); + for (i = 0; i < h.qdcount; i++) { + if (unpack_query(&p, &q) == -1) + goto error; + fprintf(f, "%s\n", print_query(&q, buf, sizeof buf)); + } + + an = 0; + ns = an + h.ancount; + ar = ns + h.nscount; + n = ar + h.arcount; + + for (i = 0; i < n; i++) { + if (i == an) + fprintf(f, "\n;; ANSWER SECTION:\n"); + if (i == ns) + fprintf(f, "\n;; AUTHORITY SECTION:\n"); + if (i == ar) + fprintf(f, "\n;; ADDITIONAL SECTION:\n"); + + if (unpack_rr(&p, &rr) == -1) + goto error; + fprintf(f, "%s\n", print_rr(&rr, buf, sizeof buf)); + } + + if (p.offset != len) + fprintf(f, ";; REMAINING GARBAGE %zu\n", len - p.offset); + + error: + if (p.err) + fprintf(f, ";; ERROR AT OFFSET %zu/%zu: %s\n", p.offset, p.len, + p.err); + + return; +} + +static void +asr_vdebug(const char *fmt, va_list ap) +{ + if (asr_debug) + vfprintf(stderr, fmt, ap); +} + +void +asr_printf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + asr_vdebug(fmt, ap); + va_end(ap); +} + +void +async_set_state(struct async *as, int state) +{ + asr_printf("asr: [%s@%p] %s -> %s\n", + kvlookup(kv_query_type, as->as_type), + as, + kvlookup(kv_state, as->as_state), + kvlookup(kv_state, state)); + as->as_state = state; +} |