xref: /openbsd/regress/lib/libc/asr/bin/common.c (revision a9e85050)
1*a9e85050Seric /*	$OpenBSD: common.c,v 1.4 2018/12/15 15:16:12 eric Exp $	*/
24c1e55dcSeric /*
34c1e55dcSeric  * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
44c1e55dcSeric  *
54c1e55dcSeric  * Permission to use, copy, modify, and distribute this software for any
64c1e55dcSeric  * purpose with or without fee is hereby granted, provided that the above
74c1e55dcSeric  * copyright notice and this permission notice appear in all copies.
84c1e55dcSeric  *
94c1e55dcSeric  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
104c1e55dcSeric  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
114c1e55dcSeric  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
124c1e55dcSeric  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
134c1e55dcSeric  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
144c1e55dcSeric  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
154c1e55dcSeric  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
164c1e55dcSeric  */
174c1e55dcSeric #include <sys/types.h>
184c1e55dcSeric #include <sys/socket.h>
194c1e55dcSeric #include <netinet/in.h>
204c1e55dcSeric #include <arpa/inet.h>
214c1e55dcSeric #include <arpa/nameser.h>
224c1e55dcSeric 
234c1e55dcSeric #include <err.h>
244c1e55dcSeric #include <errno.h>
254c1e55dcSeric #include <inttypes.h>
264c1e55dcSeric #include <netdb.h>
274c1e55dcSeric #include <resolv.h>
284c1e55dcSeric #include <stdio.h>
294c1e55dcSeric #include <string.h>
304c1e55dcSeric 
314c1e55dcSeric #include "common.h"
324c1e55dcSeric 
334c1e55dcSeric int long_err;
344c1e55dcSeric int gai_errno;
354c1e55dcSeric int rrset_errno;
364c1e55dcSeric 
374c1e55dcSeric 
384c1e55dcSeric char *
gethostarg(char * n)394c1e55dcSeric gethostarg(char *n)
404c1e55dcSeric {
414c1e55dcSeric 	if (n == NULL)
424c1e55dcSeric 		return (n);
434c1e55dcSeric 	if (!strcmp(n, "NULL"))
444c1e55dcSeric 		return (NULL);
454c1e55dcSeric 	if (!strcmp(n, "EMPTY"))
464c1e55dcSeric 		return ("");
474c1e55dcSeric 	return (n);
484c1e55dcSeric }
494c1e55dcSeric 
504c1e55dcSeric const char *rrsetstrerror(int);
514c1e55dcSeric char * print_addr(const struct sockaddr *, char *, size_t);
524c1e55dcSeric 
534c1e55dcSeric struct kv { int code; const char *name; };
544c1e55dcSeric 
554c1e55dcSeric struct kv kv_family[] = {
564c1e55dcSeric 	{ AF_UNIX,	"unix" },
574c1e55dcSeric 	{ AF_INET,	"inet" },
584c1e55dcSeric 	{ AF_INET6,	"inet6" },
594c1e55dcSeric 	{ 0,	NULL, }
604c1e55dcSeric };
614c1e55dcSeric struct kv kv_socktype[] = {
624c1e55dcSeric 	{ SOCK_STREAM,		"stream" },
634c1e55dcSeric 	{ SOCK_DGRAM,		"dgram" },
644c1e55dcSeric 	{ SOCK_RAW,		"raw" },
65c2ec5216Sguenther 	{ SOCK_SEQPACKET,	"seqpacket" },
664c1e55dcSeric 	{ 0,	NULL, }
674c1e55dcSeric };
684c1e55dcSeric struct kv kv_protocol[] = {
694c1e55dcSeric 	{ IPPROTO_UDP, "udp" },
704c1e55dcSeric 	{ IPPROTO_TCP, "tcp" },
71f2033d2fSeric 	{ IPPROTO_ICMP, "icmp" },
72f2033d2fSeric 	{ IPPROTO_ICMPV6, "icmpv6" },
734c1e55dcSeric 	{ 0,	NULL, }
744c1e55dcSeric };
754c1e55dcSeric 
764c1e55dcSeric static const char *
kv_lookup_name(struct kv * kv,int code,char * buf,size_t sz)77f2033d2fSeric kv_lookup_name(struct kv *kv, int code, char *buf, size_t sz)
784c1e55dcSeric {
794c1e55dcSeric 	while (kv->name) {
804c1e55dcSeric 		if (kv->code == code)
814c1e55dcSeric 			return (kv->name);
824c1e55dcSeric 		kv++;
834c1e55dcSeric 	}
84f2033d2fSeric 	snprintf(buf, sz, "%i", code);
85f2033d2fSeric 	return (buf);
864c1e55dcSeric }
874c1e55dcSeric 
884c1e55dcSeric struct keyval {
894c1e55dcSeric         const char *key;
90*a9e85050Seric         int	    value;
914c1e55dcSeric };
924c1e55dcSeric 
934c1e55dcSeric static struct keyval kv_class[] = {
944c1e55dcSeric 	{ "IN",	C_IN },
954c1e55dcSeric 	{ "CHAOS", C_CHAOS },
964c1e55dcSeric 	{ "HS", C_HS },
974c1e55dcSeric 	{ "ANY", C_ANY },
984c1e55dcSeric 	{ NULL, 	0 },
994c1e55dcSeric };
1004c1e55dcSeric 
1014c1e55dcSeric static struct keyval kv_type[] = {
1024c1e55dcSeric 	{ "A",		T_A	},
1034c1e55dcSeric 	{ "NS",		T_NS	},
1044c1e55dcSeric 	{ "MD",		T_MD	},
1054c1e55dcSeric 	{ "MF",		T_MF	},
1064c1e55dcSeric 	{ "CNAME",	T_CNAME	},
1074c1e55dcSeric 	{ "SOA",	T_SOA	},
1084c1e55dcSeric 	{ "MB",		T_MB	},
1094c1e55dcSeric 	{ "MG",		T_MG	},
1104c1e55dcSeric 	{ "MR",		T_MR	},
1114c1e55dcSeric 	{ "NULL",	T_NULL	},
1124c1e55dcSeric 	{ "WKS",	T_WKS	},
1134c1e55dcSeric 	{ "PTR",	T_PTR	},
1144c1e55dcSeric 	{ "HINFO",	T_HINFO	},
1154c1e55dcSeric 	{ "MINFO",	T_MINFO	},
1164c1e55dcSeric 	{ "MX",		T_MX	},
1174c1e55dcSeric 	{ "TXT",	T_TXT	},
1184c1e55dcSeric 
1194c1e55dcSeric 	{ "AAAA",	T_AAAA	},
1204c1e55dcSeric 
1214c1e55dcSeric 	{ "AXFR",	T_AXFR	},
1224c1e55dcSeric 	{ "MAILB",	T_MAILB	},
1234c1e55dcSeric 	{ "MAILA",	T_MAILA	},
1244c1e55dcSeric 	{ "ANY",	T_ANY	},
1254c1e55dcSeric 	{ NULL, 	0 },
1264c1e55dcSeric };
1274c1e55dcSeric 
1284c1e55dcSeric static struct keyval kv_rcode[] = {
1294c1e55dcSeric 	{ "NOERROR",	NOERROR	},
1304c1e55dcSeric 	{ "FORMERR",	FORMERR },
1314c1e55dcSeric 	{ "SERVFAIL",	SERVFAIL },
1324c1e55dcSeric 	{ "NXDOMAIN",	NXDOMAIN },
1334c1e55dcSeric 	{ "NOTIMP",	NOTIMP },
1344c1e55dcSeric 	{ "REFUSED",	REFUSED },
1354c1e55dcSeric 	{ NULL, 	0 },
1364c1e55dcSeric };
1374c1e55dcSeric 
138*a9e85050Seric static struct keyval kv_resopt[] = {
139*a9e85050Seric 	{ "DEBUG",	RES_DEBUG },
140*a9e85050Seric 	{ "AAONLY",	RES_AAONLY },
141*a9e85050Seric 	{ "USEVC",	RES_USEVC },
142*a9e85050Seric 	{ "PRIMARY",	RES_PRIMARY },
143*a9e85050Seric 	{ "IGNTC",	RES_IGNTC },
144*a9e85050Seric 	{ "RECURSE",	RES_RECURSE },
145*a9e85050Seric 	{ "DEFNAMES",	RES_DEFNAMES },
146*a9e85050Seric 	{ "STAYOPEN",	RES_STAYOPEN },
147*a9e85050Seric 	{ "DNSRCH",	RES_DNSRCH },
148*a9e85050Seric 	{ "INSECURE1",	RES_INSECURE1 },
149*a9e85050Seric 	{ "INSECURE2",	RES_INSECURE2 },
150*a9e85050Seric 	{ "NOALIASES",	RES_NOALIASES },
151*a9e85050Seric 	{ "USE_INET6",	RES_USE_INET6 },
152*a9e85050Seric 	{ "USE_EDNS0",	RES_USE_EDNS0 },
153*a9e85050Seric 	{ "USE_DNSSEC",	RES_USE_DNSSEC },
154*a9e85050Seric 	{ NULL, 	0 },
155*a9e85050Seric };
1564c1e55dcSeric 
1574c1e55dcSeric const char *
rcodetostr(uint16_t v)1584c1e55dcSeric rcodetostr(uint16_t v)
1594c1e55dcSeric {
1604c1e55dcSeric 	static char	buf[16];
1614c1e55dcSeric 	size_t		i;
1624c1e55dcSeric 
1634c1e55dcSeric 	for(i = 0; kv_rcode[i].key; i++)
1644c1e55dcSeric 		if (kv_rcode[i].value == v)
1654c1e55dcSeric 			return (kv_rcode[i].key);
1664c1e55dcSeric 
1674c1e55dcSeric 	snprintf(buf, sizeof buf, "%"PRIu16"?", v);
1684c1e55dcSeric 
1694c1e55dcSeric 	return (buf);
1704c1e55dcSeric }
1714c1e55dcSeric 
1724c1e55dcSeric const char *
typetostr(uint16_t v)1734c1e55dcSeric typetostr(uint16_t v)
1744c1e55dcSeric {
1754c1e55dcSeric 	static char	 buf[16];
1764c1e55dcSeric 	size_t		 i;
1774c1e55dcSeric 
1784c1e55dcSeric 	for(i = 0; kv_type[i].key; i++)
1794c1e55dcSeric 		if (kv_type[i].value == v)
1804c1e55dcSeric 			return (kv_type[i].key);
1814c1e55dcSeric 
1824c1e55dcSeric 	snprintf(buf, sizeof buf, "%"PRIu16"?", v);
1834c1e55dcSeric 
1844c1e55dcSeric 	return (buf);
1854c1e55dcSeric }
1864c1e55dcSeric 
1874c1e55dcSeric const char *
classtostr(uint16_t v)1884c1e55dcSeric classtostr(uint16_t v)
1894c1e55dcSeric {
1904c1e55dcSeric 	static char	 buf[16];
1914c1e55dcSeric 	size_t		 i;
1924c1e55dcSeric 
1934c1e55dcSeric 	for(i = 0; kv_class[i].key; i++)
1944c1e55dcSeric 		if (kv_class[i].value == v)
1954c1e55dcSeric 			return (kv_class[i].key);
1964c1e55dcSeric 
1974c1e55dcSeric 	snprintf(buf, sizeof buf, "%"PRIu16"?", v);
1984c1e55dcSeric 
1994c1e55dcSeric 	return (buf);
2004c1e55dcSeric }
2014c1e55dcSeric 
2024c1e55dcSeric uint16_t
strtotype(const char * name)2034c1e55dcSeric strtotype(const char *name)
2044c1e55dcSeric {
2054c1e55dcSeric 	size_t	i;
2064c1e55dcSeric 
2074c1e55dcSeric 	for(i = 0; kv_type[i].key; i++)
208*a9e85050Seric 		if (!strcasecmp(kv_type[i].key, name))
2094c1e55dcSeric 			return (kv_type[i].value);
2104c1e55dcSeric 
2114c1e55dcSeric 	return (0);
2124c1e55dcSeric }
2134c1e55dcSeric 
2144c1e55dcSeric uint16_t
strtoclass(const char * name)2154c1e55dcSeric strtoclass(const char *name)
2164c1e55dcSeric {
2174c1e55dcSeric 	size_t	i;
2184c1e55dcSeric 
2194c1e55dcSeric 	for(i = 0; kv_class[i].key; i++)
220*a9e85050Seric 		if (!strcasecmp(kv_class[i].key, name))
2214c1e55dcSeric 			return (kv_class[i].value);
2224c1e55dcSeric 
2234c1e55dcSeric 	return (0);
2244c1e55dcSeric }
2254c1e55dcSeric 
226*a9e85050Seric int
strtoresopt(const char * name)227*a9e85050Seric strtoresopt(const char *name)
228*a9e85050Seric {
229*a9e85050Seric 	size_t	i;
230*a9e85050Seric 
231*a9e85050Seric 	for(i = 0; kv_resopt[i].key; i++)
232*a9e85050Seric 		if (!strcasecmp(kv_resopt[i].key, name))
233*a9e85050Seric 			return (kv_resopt[i].value);
234*a9e85050Seric 
235*a9e85050Seric 	return (0);
236*a9e85050Seric }
237*a9e85050Seric 
238*a9e85050Seric void
parseresopt(const char * name)239*a9e85050Seric parseresopt(const char *name)
240*a9e85050Seric {
241*a9e85050Seric 	static int init = 0;
242*a9e85050Seric 	int flag, neg = 0;
243*a9e85050Seric 
244*a9e85050Seric 	if (init == 0) {
245*a9e85050Seric 		res_init();
246*a9e85050Seric 		init = 1;
247*a9e85050Seric 	}
248*a9e85050Seric 
249*a9e85050Seric 	if (name[0] == '-') {
250*a9e85050Seric 		neg = 1;
251*a9e85050Seric 		name++;
252*a9e85050Seric 	}
253*a9e85050Seric 	else if (name[0] == '+')
254*a9e85050Seric 		name++;
255*a9e85050Seric 
256*a9e85050Seric 	flag = strtoresopt(name);
257*a9e85050Seric 	if (flag == 0)
258*a9e85050Seric 		errx(1, "unknown reslover option %s", name);
259*a9e85050Seric 
260*a9e85050Seric 	if (neg)
261*a9e85050Seric 		_res.options &= ~flag;
262*a9e85050Seric 	else
263*a9e85050Seric 		_res.options |= flag;
264*a9e85050Seric }
265*a9e85050Seric 
2664c1e55dcSeric void
print_hostent(struct hostent * e)2674c1e55dcSeric print_hostent(struct hostent *e)
2684c1e55dcSeric {
2694c1e55dcSeric 	char	buf[256], **c;
2704c1e55dcSeric 
2714c1e55dcSeric 	printf("name = \"%s\"\n", e->h_name);
2724c1e55dcSeric 	printf("aliases =");
2734c1e55dcSeric 	for(c = e->h_aliases; *c; c++)
2744c1e55dcSeric 		printf(" \"%s\"", *c);
2754c1e55dcSeric 	printf("\n");
2764c1e55dcSeric 	printf("addrtype = %i\n", e->h_addrtype);
2774c1e55dcSeric 	printf("addrlength = %i\n", e->h_length);
2784c1e55dcSeric 	printf("addr_list =");
2794c1e55dcSeric 	for(c = e->h_addr_list; *c; c++) {
2804c1e55dcSeric 		printf(" %s", inet_ntop(e->h_addrtype, *c, buf, sizeof buf));
2814c1e55dcSeric 	}
2824c1e55dcSeric 	printf("\n");
2834c1e55dcSeric }
2844c1e55dcSeric 
2854c1e55dcSeric void
print_netent(struct netent * e)2864c1e55dcSeric print_netent(struct netent *e)
2874c1e55dcSeric {
2884c1e55dcSeric 	char	buf[256], **c;
2894c1e55dcSeric 	uint32_t addr;
2904c1e55dcSeric 
2914c1e55dcSeric 	/* network number are given in host order */
2924c1e55dcSeric 	addr = htonl(e->n_net);
2934c1e55dcSeric 
2944c1e55dcSeric 	printf("name = \"%s\"\n", e->n_name);
2954c1e55dcSeric 	printf("aliases =");
2964c1e55dcSeric 	for (c = e->n_aliases; *c; c++)
2974c1e55dcSeric 		printf(" \"%s\"", *c);
2984c1e55dcSeric 	printf("\n");
2994c1e55dcSeric 	printf("addrtype = %i\n", e->n_addrtype);
3004c1e55dcSeric 	printf("net = %s\n", inet_ntop(e->n_addrtype, &addr, buf, sizeof buf));
3014c1e55dcSeric }
3024c1e55dcSeric 
3034c1e55dcSeric void
print_addrinfo(struct addrinfo * ai)3044c1e55dcSeric print_addrinfo(struct addrinfo *ai)
3054c1e55dcSeric {
306f2033d2fSeric 	char	buf[256], bf[64], bt[64], bp[64];
3074c1e55dcSeric 
3084c1e55dcSeric 	printf("family=%s socktype=%s protocol=%s addr=%s canonname=%s\n",
309f2033d2fSeric 		kv_lookup_name(kv_family, ai->ai_family, bf, sizeof bf),
310f2033d2fSeric 		kv_lookup_name(kv_socktype, ai->ai_socktype, bt, sizeof bt),
311f2033d2fSeric 		kv_lookup_name(kv_protocol, ai->ai_protocol, bp, sizeof bp),
3124c1e55dcSeric 		print_addr(ai->ai_addr, buf, sizeof buf),
3134c1e55dcSeric 		ai->ai_canonname);
3144c1e55dcSeric }
3154c1e55dcSeric 
3164c1e55dcSeric const char *
rrsetstrerror(int e)3174c1e55dcSeric rrsetstrerror(int e)
3184c1e55dcSeric {
3194c1e55dcSeric 	switch (e) {
3204c1e55dcSeric 	case 0:
3214c1e55dcSeric 		return "OK";
3224c1e55dcSeric 	case ERRSET_NONAME:
3234c1e55dcSeric 		return "ERRSET_NONAME";
3244c1e55dcSeric 	case ERRSET_NODATA:
3254c1e55dcSeric 		return "ERRSET_NODATA";
3264c1e55dcSeric 	case ERRSET_NOMEMORY:
3274c1e55dcSeric 		return "ERRSET_NOMEMORY";
3284c1e55dcSeric 	case ERRSET_INVAL:
3294c1e55dcSeric 		return "ERRSET_INVAL";
3304c1e55dcSeric 	case ERRSET_FAIL:
3314c1e55dcSeric 		return "ERRSET_FAIL";
3324c1e55dcSeric 	default:
3334c1e55dcSeric 		return "???";
3344c1e55dcSeric 	}
3354c1e55dcSeric }
3364c1e55dcSeric 
3374c1e55dcSeric void
print_rrsetinfo(struct rrsetinfo * rrset)3384c1e55dcSeric print_rrsetinfo(struct rrsetinfo * rrset)
3394c1e55dcSeric {
3404c1e55dcSeric 	printf("rri_flags=%u\n", rrset->rri_flags);
3414c1e55dcSeric 	printf("rri_rdclass=%u\n", rrset->rri_rdclass);
3424c1e55dcSeric 	printf("rri_rdtype=%u\n", rrset->rri_rdtype);
3434c1e55dcSeric 	printf("rri_ttl=%u\n", rrset->rri_ttl);
3444c1e55dcSeric 	printf("rri_nrdatas=%u\n", rrset->rri_nrdatas);
3454c1e55dcSeric 	printf("rri_nsigs=%u\n", rrset->rri_nsigs);
3464c1e55dcSeric 	printf("rri_name=\"%s\"\n", rrset->rri_name);
3474c1e55dcSeric }
3484c1e55dcSeric 
3494c1e55dcSeric void
print_errors(void)3504c1e55dcSeric print_errors(void)
3514c1e55dcSeric {
3524c1e55dcSeric 	switch (long_err) {
3534c1e55dcSeric 	case 0:
3544c1e55dcSeric 		return;
3554c1e55dcSeric 	case 1:
3564c1e55dcSeric 		printf("  => errno %i, h_errno %i", errno, h_errno);
3574c1e55dcSeric 		printf(", rrset_errno %i", rrset_errno);
3584c1e55dcSeric 		printf(", gai_errno %i", gai_errno);
3594c1e55dcSeric 		printf ("\n");
3604c1e55dcSeric 		return;
3614c1e55dcSeric 	default:
3624c1e55dcSeric 		printf("  => errno %i: %s\n  => h_errno %i: %s\n  => rrset_errno %i: %s\n",
3634c1e55dcSeric 		    errno, errno ? strerror(errno) : "ok",
3644c1e55dcSeric 		    h_errno, h_errno ? hstrerror(h_errno) : "ok",
3654c1e55dcSeric 		    rrset_errno, rrset_errno ? rrsetstrerror(rrset_errno) : "ok");
3664c1e55dcSeric 		printf("  => gai_errno %i: %s\n",
3674c1e55dcSeric 		    gai_errno, gai_errno ? gai_strerror(gai_errno) : "ok");
3684c1e55dcSeric 	}
3694c1e55dcSeric }
3704c1e55dcSeric 
3714c1e55dcSeric 
3724c1e55dcSeric static char *
print_host(const struct sockaddr * sa,char * buf,size_t len)3734c1e55dcSeric print_host(const struct sockaddr *sa, char *buf, size_t len)
3744c1e55dcSeric {
3754c1e55dcSeric 	switch (sa->sa_family) {
3764c1e55dcSeric 	case AF_INET:
3774c1e55dcSeric 		inet_ntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr,
3784c1e55dcSeric 			  buf, len);
3794c1e55dcSeric 		break;
3804c1e55dcSeric 	case AF_INET6:
3814c1e55dcSeric 		inet_ntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr,
3824c1e55dcSeric 			  buf, len);
3834c1e55dcSeric 		break;
3844c1e55dcSeric 	default:
3854c1e55dcSeric 		buf[0] = '\0';
3864c1e55dcSeric 	}
3874c1e55dcSeric 	return (buf);
3884c1e55dcSeric }
3894c1e55dcSeric 
3904c1e55dcSeric 
3914c1e55dcSeric char *
print_addr(const struct sockaddr * sa,char * buf,size_t len)3924c1e55dcSeric print_addr(const struct sockaddr *sa, char *buf, size_t len)
3934c1e55dcSeric {
3944c1e55dcSeric 	char	h[256];
3954c1e55dcSeric 
3964c1e55dcSeric 	print_host(sa, h, sizeof h);
3974c1e55dcSeric 
3984c1e55dcSeric 	switch (sa->sa_family) {
3994c1e55dcSeric 	case AF_INET:
4004c1e55dcSeric 		snprintf(buf, len, "%s:%i", h,
4014c1e55dcSeric 		    ntohs(((struct sockaddr_in*)(sa))->sin_port));
4024c1e55dcSeric 		break;
4034c1e55dcSeric 	case AF_INET6:
4044c1e55dcSeric 		snprintf(buf, len, "[%s]:%i", h,
4054c1e55dcSeric 		    ntohs(((struct sockaddr_in6*)(sa))->sin6_port));
4064c1e55dcSeric 		break;
4074c1e55dcSeric 	default:
4084c1e55dcSeric 		snprintf(buf, len, "?");
4094c1e55dcSeric 		break;
4104c1e55dcSeric 	}
4114c1e55dcSeric 
4124c1e55dcSeric 	return (buf);
4134c1e55dcSeric }
4144c1e55dcSeric 
4154c1e55dcSeric void
packed_init(struct packed * pack,char * data,size_t len)4164c1e55dcSeric packed_init(struct packed *pack, char *data, size_t len)
4174c1e55dcSeric {
4184c1e55dcSeric 	pack->data = data;
4194c1e55dcSeric 	pack->len = len;
4204c1e55dcSeric 	pack->offset = 0;
4214c1e55dcSeric 	pack->err = NULL;
4224c1e55dcSeric }
4234c1e55dcSeric 
4244c1e55dcSeric 
4254c1e55dcSeric static ssize_t
dname_expand(const unsigned char * data,size_t len,size_t offset,size_t * newoffset,char * dst,size_t max)4264c1e55dcSeric dname_expand(const unsigned char *data, size_t len, size_t offset,
4274c1e55dcSeric     size_t *newoffset, char *dst, size_t max)
4284c1e55dcSeric {
4294c1e55dcSeric 	size_t		 n, count, end, ptr, start;
4304c1e55dcSeric 	ssize_t		 res;
4314c1e55dcSeric 
4324c1e55dcSeric 	if (offset >= len)
4334c1e55dcSeric 		return (-1);
4344c1e55dcSeric 
4354c1e55dcSeric 	res = 0;
4364c1e55dcSeric 	end = start = offset;
4374c1e55dcSeric 
4384c1e55dcSeric 	for(; (n = data[offset]); ) {
4394c1e55dcSeric 		if ((n & 0xc0) == 0xc0) {
4404c1e55dcSeric 			if (offset + 2 > len)
4414c1e55dcSeric 				return (-1);
4424c1e55dcSeric 			ptr = 256 * (n & ~0xc0) + data[offset + 1];
4434c1e55dcSeric 			if (ptr >= start)
4444c1e55dcSeric 				return (-1);
4454c1e55dcSeric 			if (end < offset + 2)
4464c1e55dcSeric 				end = offset + 2;
4474c1e55dcSeric 			offset = ptr;
4484c1e55dcSeric 			continue;
4494c1e55dcSeric 		}
4504c1e55dcSeric 		if (offset + n + 1 > len)
4514c1e55dcSeric 			return (-1);
4524c1e55dcSeric 
4534c1e55dcSeric 
4544c1e55dcSeric 		/* copy n + at offset+1 */
4554c1e55dcSeric 		if (dst != NULL && max != 0) {
4564c1e55dcSeric 			count = (max < n + 1) ? (max) : (n + 1);
4574c1e55dcSeric 			memmove(dst, data + offset, count);
4584c1e55dcSeric 			dst += count;
4594c1e55dcSeric 			max -= count;
4604c1e55dcSeric 		}
4614c1e55dcSeric 		res += n + 1;
4624c1e55dcSeric 		offset += n + 1;
4634c1e55dcSeric 		if (end < offset)
4644c1e55dcSeric 			end = offset;
4654c1e55dcSeric 	}
4664c1e55dcSeric 	if (end < offset + 1)
4674c1e55dcSeric 		end = offset + 1;
4684c1e55dcSeric 
4694c1e55dcSeric 	if (dst != NULL && max != 0)
4704c1e55dcSeric 		dst[0] = 0;
4714c1e55dcSeric 	if (newoffset)
4724c1e55dcSeric 		*newoffset = end;
4734c1e55dcSeric 	return (res + 1);
4744c1e55dcSeric }
4754c1e55dcSeric 
4764c1e55dcSeric static int
unpack_data(struct packed * p,void * data,size_t len)4774c1e55dcSeric unpack_data(struct packed *p, void *data, size_t len)
4784c1e55dcSeric {
4794c1e55dcSeric 	if (p->err)
4804c1e55dcSeric 		return (-1);
4814c1e55dcSeric 
4824c1e55dcSeric 	if (p->len - p->offset < len) {
4834c1e55dcSeric 		p->err = "too short";
4844c1e55dcSeric 		return (-1);
4854c1e55dcSeric 	}
4864c1e55dcSeric 
4874c1e55dcSeric 	memmove(data, p->data + p->offset, len);
4884c1e55dcSeric 	p->offset += len;
4894c1e55dcSeric 
4904c1e55dcSeric 	return (0);
4914c1e55dcSeric }
4924c1e55dcSeric 
4934c1e55dcSeric static int
unpack_u16(struct packed * p,uint16_t * u16)4944c1e55dcSeric unpack_u16(struct packed *p, uint16_t *u16)
4954c1e55dcSeric {
4964c1e55dcSeric 	if (unpack_data(p, u16, 2) == -1)
4974c1e55dcSeric 		return (-1);
4984c1e55dcSeric 
4994c1e55dcSeric 	*u16 = ntohs(*u16);
5004c1e55dcSeric 
5014c1e55dcSeric 	return (0);
5024c1e55dcSeric }
5034c1e55dcSeric 
5044c1e55dcSeric static int
unpack_u32(struct packed * p,uint32_t * u32)5054c1e55dcSeric unpack_u32(struct packed *p, uint32_t *u32)
5064c1e55dcSeric {
5074c1e55dcSeric 	if (unpack_data(p, u32, 4) == -1)
5084c1e55dcSeric 		return (-1);
5094c1e55dcSeric 
5104c1e55dcSeric 	*u32 = ntohl(*u32);
5114c1e55dcSeric 
5124c1e55dcSeric 	return (0);
5134c1e55dcSeric }
5144c1e55dcSeric 
5154c1e55dcSeric static int
unpack_inaddr(struct packed * p,struct in_addr * a)5164c1e55dcSeric unpack_inaddr(struct packed *p, struct in_addr *a)
5174c1e55dcSeric {
5184c1e55dcSeric 	return (unpack_data(p, a, 4));
5194c1e55dcSeric }
5204c1e55dcSeric 
5214c1e55dcSeric static int
unpack_in6addr(struct packed * p,struct in6_addr * a6)5224c1e55dcSeric unpack_in6addr(struct packed *p, struct in6_addr *a6)
5234c1e55dcSeric {
5244c1e55dcSeric 	return (unpack_data(p, a6, 16));
5254c1e55dcSeric }
5264c1e55dcSeric 
5274c1e55dcSeric static int
unpack_dname(struct packed * p,char * dst,size_t max)5284c1e55dcSeric unpack_dname(struct packed *p, char *dst, size_t max)
5294c1e55dcSeric {
5304c1e55dcSeric 	ssize_t e;
5314c1e55dcSeric 
5324c1e55dcSeric 	if (p->err)
5334c1e55dcSeric 		return (-1);
5344c1e55dcSeric 
5354c1e55dcSeric 	e = dname_expand(p->data, p->len, p->offset, &p->offset, dst, max);
5364c1e55dcSeric 	if (e == -1) {
5374c1e55dcSeric 		p->err = "bad domain name";
5384c1e55dcSeric 		return (-1);
5394c1e55dcSeric 	}
5404c1e55dcSeric 	if (e < 0 || e > MAXDNAME) {
5414c1e55dcSeric 		p->err = "domain name too long";
5424c1e55dcSeric 		return (-1);
5434c1e55dcSeric 	}
5444c1e55dcSeric 
5454c1e55dcSeric 	return (0);
5464c1e55dcSeric }
5474c1e55dcSeric 
5484c1e55dcSeric int
unpack_header(struct packed * p,struct header * h)5494c1e55dcSeric unpack_header(struct packed *p, struct header *h)
5504c1e55dcSeric {
5514c1e55dcSeric 	if (unpack_data(p, h, HFIXEDSZ) == -1)
5524c1e55dcSeric 		return (-1);
5534c1e55dcSeric 
5544c1e55dcSeric 	h->flags = ntohs(h->flags);
5554c1e55dcSeric 	h->qdcount = ntohs(h->qdcount);
5564c1e55dcSeric 	h->ancount = ntohs(h->ancount);
5574c1e55dcSeric 	h->nscount = ntohs(h->nscount);
5584c1e55dcSeric 	h->arcount = ntohs(h->arcount);
5594c1e55dcSeric 
5604c1e55dcSeric 	return (0);
5614c1e55dcSeric }
5624c1e55dcSeric 
5634c1e55dcSeric int
unpack_query(struct packed * p,struct query * q)5644c1e55dcSeric unpack_query(struct packed *p, struct query *q)
5654c1e55dcSeric {
5664c1e55dcSeric 	unpack_dname(p, q->q_dname, sizeof(q->q_dname));
5674c1e55dcSeric 	unpack_u16(p, &q->q_type);
5684c1e55dcSeric 	unpack_u16(p, &q->q_class);
5694c1e55dcSeric 
5704c1e55dcSeric 	return (p->err) ? (-1) : (0);
5714c1e55dcSeric }
5724c1e55dcSeric 
5734c1e55dcSeric int
unpack_rr(struct packed * p,struct rr * rr)5744c1e55dcSeric unpack_rr(struct packed *p, struct rr *rr)
5754c1e55dcSeric {
5764c1e55dcSeric 	uint16_t	rdlen;
5774c1e55dcSeric 	size_t		save_offset;
5784c1e55dcSeric 
5794c1e55dcSeric 	unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname));
5804c1e55dcSeric 	unpack_u16(p, &rr->rr_type);
5814c1e55dcSeric 	unpack_u16(p, &rr->rr_class);
5824c1e55dcSeric 	unpack_u32(p, &rr->rr_ttl);
5834c1e55dcSeric 	unpack_u16(p, &rdlen);
5844c1e55dcSeric 
5854c1e55dcSeric 	if (p->err)
5864c1e55dcSeric 		return (-1);
5874c1e55dcSeric 
5884c1e55dcSeric 	if (p->len - p->offset < rdlen) {
5894c1e55dcSeric 		p->err = "too short";
5904c1e55dcSeric 		return (-1);
5914c1e55dcSeric 	}
5924c1e55dcSeric 
5934c1e55dcSeric 	save_offset = p->offset;
5944c1e55dcSeric 
5954c1e55dcSeric 	switch(rr->rr_type) {
5964c1e55dcSeric 
5974c1e55dcSeric 	case T_CNAME:
5984c1e55dcSeric 		unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname));
5994c1e55dcSeric 		break;
6004c1e55dcSeric 
6014c1e55dcSeric 	case T_MX:
6024c1e55dcSeric 		unpack_u16(p, &rr->rr.mx.preference);
6034c1e55dcSeric 		unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange));
6044c1e55dcSeric 		break;
6054c1e55dcSeric 
6064c1e55dcSeric 	case T_NS:
6074c1e55dcSeric 		unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname));
6084c1e55dcSeric 		break;
6094c1e55dcSeric 
6104c1e55dcSeric 	case T_PTR:
6114c1e55dcSeric 		unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname));
6124c1e55dcSeric 		break;
6134c1e55dcSeric 
6144c1e55dcSeric 	case T_SOA:
6154c1e55dcSeric 		unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname));
6164c1e55dcSeric 		unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname));
6174c1e55dcSeric 		unpack_u32(p, &rr->rr.soa.serial);
6184c1e55dcSeric 		unpack_u32(p, &rr->rr.soa.refresh);
6194c1e55dcSeric 		unpack_u32(p, &rr->rr.soa.retry);
6204c1e55dcSeric 		unpack_u32(p, &rr->rr.soa.expire);
6214c1e55dcSeric 		unpack_u32(p, &rr->rr.soa.minimum);
6224c1e55dcSeric 		break;
6234c1e55dcSeric 
6244c1e55dcSeric 	case T_A:
6254c1e55dcSeric 		if (rr->rr_class != C_IN)
6264c1e55dcSeric 			goto other;
6274c1e55dcSeric 		unpack_inaddr(p, &rr->rr.in_a.addr);
6284c1e55dcSeric 		break;
6294c1e55dcSeric 
6304c1e55dcSeric 	case T_AAAA:
6314c1e55dcSeric 		if (rr->rr_class != C_IN)
6324c1e55dcSeric 			goto other;
6334c1e55dcSeric 		unpack_in6addr(p, &rr->rr.in_aaaa.addr6);
6344c1e55dcSeric 		break;
6354c1e55dcSeric 	default:
6364c1e55dcSeric 	other:
6374c1e55dcSeric 		rr->rr.other.rdata = p->data + p->offset;
6384c1e55dcSeric 		rr->rr.other.rdlen = rdlen;
6394c1e55dcSeric 		p->offset += rdlen;
6404c1e55dcSeric 	}
6414c1e55dcSeric 
6424c1e55dcSeric 	if (p->err)
6434c1e55dcSeric 		return (-1);
6444c1e55dcSeric 
6454c1e55dcSeric 	/* make sure that the advertised rdlen is really ok */
6464c1e55dcSeric 	if (p->offset - save_offset != rdlen)
6474c1e55dcSeric 		p->err = "bad dlen";
6484c1e55dcSeric 
6494c1e55dcSeric 	return (p->err) ? (-1) : (0);
6504c1e55dcSeric }
6514c1e55dcSeric 
6524c1e55dcSeric int
sockaddr_from_str(struct sockaddr * sa,int family,const char * str)6534c1e55dcSeric sockaddr_from_str(struct sockaddr *sa, int family, const char *str)
6544c1e55dcSeric {
6554c1e55dcSeric 	struct in_addr		 ina;
6564c1e55dcSeric 	struct in6_addr		 in6a;
6574c1e55dcSeric 	struct sockaddr_in	*sin;
6584c1e55dcSeric 	struct sockaddr_in6	*sin6;
6594c1e55dcSeric 
6604c1e55dcSeric 	switch (family) {
6614c1e55dcSeric 	case PF_UNSPEC:
6624c1e55dcSeric 		if (sockaddr_from_str(sa, PF_INET, str) == 0)
6634c1e55dcSeric 			return (0);
6644c1e55dcSeric 		return sockaddr_from_str(sa, PF_INET6, str);
6654c1e55dcSeric 
6664c1e55dcSeric 	case PF_INET:
6674c1e55dcSeric 		if (inet_pton(PF_INET, str, &ina) != 1)
6684c1e55dcSeric 			return (-1);
6694c1e55dcSeric 
6704c1e55dcSeric 		sin = (struct sockaddr_in *)sa;
6714c1e55dcSeric 		memset(sin, 0, sizeof *sin);
6724c1e55dcSeric 		sin->sin_len = sizeof(struct sockaddr_in);
6734c1e55dcSeric 		sin->sin_family = PF_INET;
6744c1e55dcSeric 		sin->sin_addr.s_addr = ina.s_addr;
6754c1e55dcSeric 		return (0);
6764c1e55dcSeric 
6774c1e55dcSeric 	case PF_INET6:
6784c1e55dcSeric 		if (inet_pton(PF_INET6, str, &in6a) != 1)
6794c1e55dcSeric 			return (-1);
6804c1e55dcSeric 
6814c1e55dcSeric 		sin6 = (struct sockaddr_in6 *)sa;
6824c1e55dcSeric 		memset(sin6, 0, sizeof *sin6);
6834c1e55dcSeric 		sin6->sin6_len = sizeof(struct sockaddr_in6);
6844c1e55dcSeric 		sin6->sin6_family = PF_INET6;
6854c1e55dcSeric 		sin6->sin6_addr = in6a;
6864c1e55dcSeric 		return (0);
6874c1e55dcSeric 
6884c1e55dcSeric 	default:
6894c1e55dcSeric 		break;
6904c1e55dcSeric 	}
6914c1e55dcSeric 
6924c1e55dcSeric 	return (-1);
6934c1e55dcSeric }
694