xref: /openbsd-src/lib/libc/asr/asr_utils.c (revision c6fa5c87fc30caefdb4576dbebb85c7c875d4321)
1*c6fa5c87Sjca /*	$OpenBSD: asr_utils.c,v 1.16 2017/02/19 12:02:30 jca Exp $	*/
2b44da627Seric /*
3b44da627Seric  * Copyright (c) 2009-2012	Eric Faurot	<eric@faurot.net>
4b44da627Seric  *
5b44da627Seric  * Permission to use, copy, modify, and distribute this software for any
6b44da627Seric  * purpose with or without fee is hereby granted, provided that the above
7b44da627Seric  * copyright notice and this permission notice appear in all copies.
8b44da627Seric  *
9b44da627Seric  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10b44da627Seric  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11b44da627Seric  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12b44da627Seric  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13b44da627Seric  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14b44da627Seric  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15b44da627Seric  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16b44da627Seric  */
17b44da627Seric 
18b44da627Seric #include <sys/types.h>
19b44da627Seric #include <sys/socket.h>
20c4cedadeSeric #include <net/if.h>
21b44da627Seric #include <netinet/in.h>
22b44da627Seric #include <arpa/inet.h>
23b44da627Seric #include <arpa/nameser.h>
24d216d6b1Seric #include <netdb.h>
25b44da627Seric 
26d216d6b1Seric #include <asr.h>
27b44da627Seric #include <ctype.h>
28b44da627Seric #include <errno.h>
29c4cedadeSeric #include <stdint.h>
30b44da627Seric #include <stdio.h>
31c4cedadeSeric #include <stdlib.h>
32b44da627Seric #include <string.h>
33b44da627Seric #include <unistd.h>
34b44da627Seric 
35b44da627Seric #include "asr_private.h"
36b44da627Seric 
37b44da627Seric static int dname_check_label(const char *, size_t);
38b44da627Seric static ssize_t dname_expand(const unsigned char *, size_t, size_t, size_t *,
39b44da627Seric     char *, size_t);
40b44da627Seric 
41f90bf415Seric static int unpack_data(struct asr_unpack *, void *, size_t);
42f90bf415Seric static int unpack_u16(struct asr_unpack *, uint16_t *);
43f90bf415Seric static int unpack_u32(struct asr_unpack *, uint32_t *);
44f90bf415Seric static int unpack_inaddr(struct asr_unpack *, struct in_addr *);
45f90bf415Seric static int unpack_in6addr(struct asr_unpack *, struct in6_addr *);
46f90bf415Seric static int unpack_dname(struct asr_unpack *, char *, size_t);
47b44da627Seric 
48f90bf415Seric static int pack_data(struct asr_pack *, const void *, size_t);
49f90bf415Seric static int pack_u16(struct asr_pack *, uint16_t);
50f90bf415Seric static int pack_dname(struct asr_pack *, const char *);
51b44da627Seric 
52b44da627Seric static int
53b44da627Seric dname_check_label(const char *s, size_t l)
54b44da627Seric {
55b44da627Seric 	if (l == 0 || l > 63)
56b44da627Seric 		return (-1);
57b44da627Seric 
58b44da627Seric 	return (0);
59b44da627Seric }
60b44da627Seric 
61b44da627Seric ssize_t
62253ef892Sderaadt _asr_dname_from_fqdn(const char *str, char *dst, size_t max)
63b44da627Seric {
64b44da627Seric 	ssize_t	 res;
65b44da627Seric 	size_t	 l, n;
66b44da627Seric 	char	*d;
67b44da627Seric 
68b44da627Seric 	res = 0;
69b44da627Seric 
70b44da627Seric 	/* special case: the root domain */
71b44da627Seric 	if (str[0] == '.') {
72b44da627Seric 		if (str[1] != '\0')
73b44da627Seric 			return (-1);
74b44da627Seric 		if (dst && max >= 1)
75b44da627Seric 			*dst = '\0';
76b44da627Seric 		return (1);
77b44da627Seric 	}
78b44da627Seric 
79b44da627Seric 	for (; *str; str = d + 1) {
80b44da627Seric 
81b44da627Seric 		d = strchr(str, '.');
82b44da627Seric 		if (d == NULL || d == str)
83b44da627Seric 			return (-1);
84b44da627Seric 
85b44da627Seric 		l = (d - str);
86b44da627Seric 
87b44da627Seric 		if (dname_check_label(str, l) == -1)
88b44da627Seric 			return (-1);
89b44da627Seric 
90b44da627Seric 		res += l + 1;
91b44da627Seric 
92b44da627Seric 		if (dst) {
93b44da627Seric 			*dst++ = l;
94b44da627Seric 			max -= 1;
95b44da627Seric 			n = (l > max) ? max : l;
96b44da627Seric 			memmove(dst, str, n);
97b44da627Seric 			max -= n;
98b44da627Seric 			if (max == 0)
99b44da627Seric 				dst = NULL;
100b44da627Seric 			else
101b44da627Seric 				dst += n;
102b44da627Seric 		}
103b44da627Seric 	}
104b44da627Seric 
105b44da627Seric 	if (dst)
106b44da627Seric 		*dst++ = '\0';
107b44da627Seric 
108b44da627Seric 	return (res + 1);
109b44da627Seric }
110b44da627Seric 
111b44da627Seric static ssize_t
112b44da627Seric dname_expand(const unsigned char *data, size_t len, size_t offset,
113b44da627Seric     size_t *newoffset, char *dst, size_t max)
114b44da627Seric {
115b44da627Seric 	size_t		 n, count, end, ptr, start;
116b44da627Seric 	ssize_t		 res;
117b44da627Seric 
118b44da627Seric 	if (offset >= len)
119b44da627Seric 		return (-1);
120b44da627Seric 
121b44da627Seric 	res = 0;
122b44da627Seric 	end = start = offset;
123b44da627Seric 
124b44da627Seric 	for (; (n = data[offset]); ) {
125b44da627Seric 		if ((n & 0xc0) == 0xc0) {
126b44da627Seric 			if (offset + 2 > len)
127b44da627Seric 				return (-1);
128b44da627Seric 			ptr = 256 * (n & ~0xc0) + data[offset + 1];
129b44da627Seric 			if (ptr >= start)
130b44da627Seric 				return (-1);
131b44da627Seric 			if (end < offset + 2)
132b44da627Seric 				end = offset + 2;
1336f68500aSeric 			offset = start = ptr;
134b44da627Seric 			continue;
135b44da627Seric 		}
136b44da627Seric 		if (offset + n + 1 > len)
137b44da627Seric 			return (-1);
138b44da627Seric 
139b44da627Seric 		if (dname_check_label(data + offset + 1, n) == -1)
140b44da627Seric 			return (-1);
141b44da627Seric 
142b44da627Seric 		/* copy n + at offset+1 */
143b44da627Seric 		if (dst != NULL && max != 0) {
144b44da627Seric 			count = (max < n + 1) ? (max) : (n + 1);
145b44da627Seric 			memmove(dst, data + offset, count);
146b44da627Seric 			dst += count;
147b44da627Seric 			max -= count;
148b44da627Seric 		}
149b44da627Seric 		res += n + 1;
150b44da627Seric 		offset += n + 1;
151b44da627Seric 		if (end < offset)
152b44da627Seric 			end = offset;
153b44da627Seric 	}
154b44da627Seric 	if (end < offset + 1)
155b44da627Seric 		end = offset + 1;
156b44da627Seric 
157b44da627Seric 	if (dst != NULL && max != 0)
158b44da627Seric 		dst[0] = 0;
159b44da627Seric 	if (newoffset)
160b44da627Seric 		*newoffset = end;
161b44da627Seric 	return (res + 1);
162b44da627Seric }
163b44da627Seric 
164b44da627Seric void
165253ef892Sderaadt _asr_pack_init(struct asr_pack *pack, char *buf, size_t len)
166b44da627Seric {
167975956b6Seric 	pack->buf = buf;
168b44da627Seric 	pack->len = len;
169b44da627Seric 	pack->offset = 0;
17092f75510Seric 	pack->err = 0;
171b44da627Seric }
172b44da627Seric 
173975956b6Seric void
174253ef892Sderaadt _asr_unpack_init(struct asr_unpack *unpack, const char *buf, size_t len)
175975956b6Seric {
176975956b6Seric 	unpack->buf = buf;
177975956b6Seric 	unpack->len = len;
178975956b6Seric 	unpack->offset = 0;
17992f75510Seric 	unpack->err = 0;
180975956b6Seric }
181975956b6Seric 
182b44da627Seric static int
183f90bf415Seric unpack_data(struct asr_unpack *p, void *data, size_t len)
184b44da627Seric {
185b44da627Seric 	if (p->err)
186b44da627Seric 		return (-1);
187b44da627Seric 
188b44da627Seric 	if (p->len - p->offset < len) {
18992f75510Seric 		p->err = EOVERFLOW;
190b44da627Seric 		return (-1);
191b44da627Seric 	}
192b44da627Seric 
193975956b6Seric 	memmove(data, p->buf + p->offset, len);
194b44da627Seric 	p->offset += len;
195b44da627Seric 
196b44da627Seric 	return (0);
197b44da627Seric }
198b44da627Seric 
199b44da627Seric static int
200f90bf415Seric unpack_u16(struct asr_unpack *p, uint16_t *u16)
201b44da627Seric {
202b44da627Seric 	if (unpack_data(p, u16, 2) == -1)
203b44da627Seric 		return (-1);
204b44da627Seric 
205b44da627Seric 	*u16 = ntohs(*u16);
206b44da627Seric 
207b44da627Seric 	return (0);
208b44da627Seric }
209b44da627Seric 
210b44da627Seric static int
211f90bf415Seric unpack_u32(struct asr_unpack *p, uint32_t *u32)
212b44da627Seric {
213b44da627Seric 	if (unpack_data(p, u32, 4) == -1)
214b44da627Seric 		return (-1);
215b44da627Seric 
216b44da627Seric 	*u32 = ntohl(*u32);
217b44da627Seric 
218b44da627Seric 	return (0);
219b44da627Seric }
220b44da627Seric 
221b44da627Seric static int
222f90bf415Seric unpack_inaddr(struct asr_unpack *p, struct in_addr *a)
223b44da627Seric {
224b44da627Seric 	return (unpack_data(p, a, 4));
225b44da627Seric }
226b44da627Seric 
227b44da627Seric static int
228f90bf415Seric unpack_in6addr(struct asr_unpack *p, struct in6_addr *a6)
229b44da627Seric {
230b44da627Seric 	return (unpack_data(p, a6, 16));
231b44da627Seric }
232b44da627Seric 
233b44da627Seric static int
234f90bf415Seric unpack_dname(struct asr_unpack *p, char *dst, size_t max)
235b44da627Seric {
236b44da627Seric 	ssize_t e;
237b44da627Seric 
238b44da627Seric 	if (p->err)
239b44da627Seric 		return (-1);
240b44da627Seric 
241975956b6Seric 	e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max);
242b44da627Seric 	if (e == -1) {
24392f75510Seric 		p->err = EINVAL;
244b44da627Seric 		return (-1);
245b44da627Seric 	}
246b44da627Seric 	if (e < 0 || e > MAXDNAME) {
24792f75510Seric 		p->err = ERANGE;
248b44da627Seric 		return (-1);
249b44da627Seric 	}
250b44da627Seric 
251b44da627Seric 	return (0);
252b44da627Seric }
253b44da627Seric 
254b44da627Seric int
255253ef892Sderaadt _asr_unpack_header(struct asr_unpack *p, struct asr_dns_header *h)
256b44da627Seric {
257b44da627Seric 	if (unpack_data(p, h, HFIXEDSZ) == -1)
258b44da627Seric 		return (-1);
259b44da627Seric 
260b44da627Seric 	h->flags = ntohs(h->flags);
261b44da627Seric 	h->qdcount = ntohs(h->qdcount);
262b44da627Seric 	h->ancount = ntohs(h->ancount);
263b44da627Seric 	h->nscount = ntohs(h->nscount);
264b44da627Seric 	h->arcount = ntohs(h->arcount);
265b44da627Seric 
266b44da627Seric 	return (0);
267b44da627Seric }
268b44da627Seric 
269b44da627Seric int
270253ef892Sderaadt _asr_unpack_query(struct asr_unpack *p, struct asr_dns_query *q)
271b44da627Seric {
272b44da627Seric 	unpack_dname(p, q->q_dname, sizeof(q->q_dname));
273b44da627Seric 	unpack_u16(p, &q->q_type);
274b44da627Seric 	unpack_u16(p, &q->q_class);
275b44da627Seric 
276b44da627Seric 	return (p->err) ? (-1) : (0);
277b44da627Seric }
278b44da627Seric 
279b44da627Seric int
280253ef892Sderaadt _asr_unpack_rr(struct asr_unpack *p, struct asr_dns_rr *rr)
281b44da627Seric {
282b44da627Seric 	uint16_t	rdlen;
283b44da627Seric 	size_t		save_offset;
284b44da627Seric 
285b44da627Seric 	unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname));
286b44da627Seric 	unpack_u16(p, &rr->rr_type);
287b44da627Seric 	unpack_u16(p, &rr->rr_class);
288b44da627Seric 	unpack_u32(p, &rr->rr_ttl);
289b44da627Seric 	unpack_u16(p, &rdlen);
290b44da627Seric 
291b44da627Seric 	if (p->err)
292b44da627Seric 		return (-1);
293b44da627Seric 
294b44da627Seric 	if (p->len - p->offset < rdlen) {
29592f75510Seric 		p->err = EOVERFLOW;
296b44da627Seric 		return (-1);
297b44da627Seric 	}
298b44da627Seric 
299b44da627Seric 	save_offset = p->offset;
300b44da627Seric 
301b44da627Seric 	switch (rr->rr_type) {
302b44da627Seric 
303b44da627Seric 	case T_CNAME:
304b44da627Seric 		unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname));
305b44da627Seric 		break;
306b44da627Seric 
307b44da627Seric 	case T_MX:
308b44da627Seric 		unpack_u16(p, &rr->rr.mx.preference);
309b44da627Seric 		unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange));
310b44da627Seric 		break;
311b44da627Seric 
312b44da627Seric 	case T_NS:
313b44da627Seric 		unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname));
314b44da627Seric 		break;
315b44da627Seric 
316b44da627Seric 	case T_PTR:
317b44da627Seric 		unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname));
318b44da627Seric 		break;
319b44da627Seric 
320b44da627Seric 	case T_SOA:
321b44da627Seric 		unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname));
322b44da627Seric 		unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname));
323b44da627Seric 		unpack_u32(p, &rr->rr.soa.serial);
324b44da627Seric 		unpack_u32(p, &rr->rr.soa.refresh);
325b44da627Seric 		unpack_u32(p, &rr->rr.soa.retry);
326b44da627Seric 		unpack_u32(p, &rr->rr.soa.expire);
327b44da627Seric 		unpack_u32(p, &rr->rr.soa.minimum);
328b44da627Seric 		break;
329b44da627Seric 
330b44da627Seric 	case T_A:
331b44da627Seric 		if (rr->rr_class != C_IN)
332b44da627Seric 			goto other;
333b44da627Seric 		unpack_inaddr(p, &rr->rr.in_a.addr);
334b44da627Seric 		break;
335b44da627Seric 
336b44da627Seric 	case T_AAAA:
337b44da627Seric 		if (rr->rr_class != C_IN)
338b44da627Seric 			goto other;
339b44da627Seric 		unpack_in6addr(p, &rr->rr.in_aaaa.addr6);
340b44da627Seric 		break;
341b44da627Seric 	default:
342b44da627Seric 	other:
343975956b6Seric 		rr->rr.other.rdata = p->buf + p->offset;
344b44da627Seric 		rr->rr.other.rdlen = rdlen;
345b44da627Seric 		p->offset += rdlen;
346b44da627Seric 	}
347b44da627Seric 
348b44da627Seric 	if (p->err)
349b44da627Seric 		return (-1);
350b44da627Seric 
351b44da627Seric 	/* make sure that the advertised rdlen is really ok */
352b44da627Seric 	if (p->offset - save_offset != rdlen)
35392f75510Seric 		p->err = EINVAL;
354b44da627Seric 
355b44da627Seric 	return (p->err) ? (-1) : (0);
356b44da627Seric }
357b44da627Seric 
358b44da627Seric static int
359f90bf415Seric pack_data(struct asr_pack *p, const void *data, size_t len)
360b44da627Seric {
361b44da627Seric 	if (p->err)
362b44da627Seric 		return (-1);
363b44da627Seric 
364b44da627Seric 	if (p->len < p->offset + len) {
36592f75510Seric 		p->err = EOVERFLOW;
366b44da627Seric 		return (-1);
367b44da627Seric 	}
368b44da627Seric 
369975956b6Seric 	memmove(p->buf + p->offset, data, len);
370b44da627Seric 	p->offset += len;
371b44da627Seric 
372b44da627Seric 	return (0);
373b44da627Seric }
374b44da627Seric 
375b44da627Seric static int
376f90bf415Seric pack_u16(struct asr_pack *p, uint16_t v)
377b44da627Seric {
378b44da627Seric 	v = htons(v);
379b44da627Seric 
380b44da627Seric 	return (pack_data(p, &v, 2));
381b44da627Seric }
382b44da627Seric 
383b44da627Seric static int
3842aa4cd21Sjca pack_u32(struct asr_pack *p, uint32_t v)
3852aa4cd21Sjca {
3862aa4cd21Sjca 	v = htonl(v);
3872aa4cd21Sjca 
3882aa4cd21Sjca 	return (pack_data(p, &v, 4));
3892aa4cd21Sjca }
3902aa4cd21Sjca 
3912aa4cd21Sjca static int
392f90bf415Seric pack_dname(struct asr_pack *p, const char *dname)
393b44da627Seric {
394b44da627Seric 	/* dname compression would be nice to have here.
395b44da627Seric 	 * need additionnal context.
396b44da627Seric 	 */
397b44da627Seric 	return (pack_data(p, dname, strlen(dname) + 1));
398b44da627Seric }
399b44da627Seric 
400b44da627Seric int
401253ef892Sderaadt _asr_pack_header(struct asr_pack *p, const struct asr_dns_header *h)
402b44da627Seric {
403f90bf415Seric 	struct asr_dns_header c;
404b44da627Seric 
405b44da627Seric 	c.id = h->id;
406b44da627Seric 	c.flags = htons(h->flags);
407b44da627Seric 	c.qdcount = htons(h->qdcount);
408b44da627Seric 	c.ancount = htons(h->ancount);
409b44da627Seric 	c.nscount = htons(h->nscount);
410b44da627Seric 	c.arcount = htons(h->arcount);
411b44da627Seric 
412b44da627Seric 	return (pack_data(p, &c, HFIXEDSZ));
413b44da627Seric }
414b44da627Seric 
415b44da627Seric int
416253ef892Sderaadt _asr_pack_query(struct asr_pack *p, uint16_t type, uint16_t class, const char *dname)
417b44da627Seric {
418b44da627Seric 	pack_dname(p, dname);
419b44da627Seric 	pack_u16(p, type);
420b44da627Seric 	pack_u16(p, class);
421b44da627Seric 
422b44da627Seric 	return (p->err) ? (-1) : (0);
423b44da627Seric }
424b44da627Seric 
425b44da627Seric int
4262aa4cd21Sjca _asr_pack_edns0(struct asr_pack *p, uint16_t pktsz)
4272aa4cd21Sjca {
4282aa4cd21Sjca 	pack_dname(p, "");	/* root */
429*c6fa5c87Sjca 	pack_u16(p, T_OPT);	/* OPT */
4302aa4cd21Sjca 	pack_u16(p, pktsz);	/* UDP payload size */
4312aa4cd21Sjca 	pack_u32(p, 0);		/* extended RCODE and flags */
4322aa4cd21Sjca 	pack_u16(p, 0);		/* RDATA len */
4332aa4cd21Sjca 
4342aa4cd21Sjca 	return (p->err) ? (-1) : (0);
4352aa4cd21Sjca }
4362aa4cd21Sjca 
4372aa4cd21Sjca int
438253ef892Sderaadt _asr_sockaddr_from_str(struct sockaddr *sa, int family, const char *str)
439b44da627Seric {
440b44da627Seric 	struct in_addr		 ina;
441b44da627Seric 	struct in6_addr		 in6a;
442b44da627Seric 	struct sockaddr_in	*sin;
443b44da627Seric 	struct sockaddr_in6	*sin6;
444c4cedadeSeric 	char			*cp, *str2;
445c4cedadeSeric 	const char		*errstr;
446b44da627Seric 
447b44da627Seric 	switch (family) {
448b44da627Seric 	case PF_UNSPEC:
449253ef892Sderaadt 		if (_asr_sockaddr_from_str(sa, PF_INET, str) == 0)
450b44da627Seric 			return (0);
451253ef892Sderaadt 		return _asr_sockaddr_from_str(sa, PF_INET6, str);
452b44da627Seric 
453b44da627Seric 	case PF_INET:
454b44da627Seric 		if (inet_pton(PF_INET, str, &ina) != 1)
455b44da627Seric 			return (-1);
456b44da627Seric 
457b44da627Seric 		sin = (struct sockaddr_in *)sa;
458b44da627Seric 		memset(sin, 0, sizeof *sin);
459b44da627Seric 		sin->sin_len = sizeof(struct sockaddr_in);
460b44da627Seric 		sin->sin_family = PF_INET;
461b44da627Seric 		sin->sin_addr.s_addr = ina.s_addr;
462b44da627Seric 		return (0);
463b44da627Seric 
464b44da627Seric 	case PF_INET6:
465c4cedadeSeric 		cp = strchr(str, SCOPE_DELIMITER);
466c4cedadeSeric 		if (cp) {
467c4cedadeSeric 			str2 = strdup(str);
468c4cedadeSeric 			if (str2 == NULL)
469c4cedadeSeric 				return (-1);
470c4cedadeSeric 			str2[cp - str] = '\0';
471c4cedadeSeric 			if (inet_pton(PF_INET6, str2, &in6a) != 1) {
472c4cedadeSeric 				free(str2);
473c4cedadeSeric 				return (-1);
474c4cedadeSeric 			}
475c4cedadeSeric 			cp++;
476c4cedadeSeric 			free(str2);
477c4cedadeSeric 		} else if (inet_pton(PF_INET6, str, &in6a) != 1)
478b44da627Seric 			return (-1);
479b44da627Seric 
480b44da627Seric 		sin6 = (struct sockaddr_in6 *)sa;
481b44da627Seric 		memset(sin6, 0, sizeof *sin6);
482b44da627Seric 		sin6->sin6_len = sizeof(struct sockaddr_in6);
483b44da627Seric 		sin6->sin6_family = PF_INET6;
484b44da627Seric 		sin6->sin6_addr = in6a;
485c4cedadeSeric 
486c4cedadeSeric 		if (cp == NULL)
487c4cedadeSeric 			return (0);
488c4cedadeSeric 
489c4cedadeSeric 		if (IN6_IS_ADDR_LINKLOCAL(&in6a) ||
490c4cedadeSeric 		    IN6_IS_ADDR_MC_LINKLOCAL(&in6a) ||
491c4cedadeSeric 		    IN6_IS_ADDR_MC_INTFACELOCAL(&in6a))
492c4cedadeSeric 			if ((sin6->sin6_scope_id = if_nametoindex(cp)))
493c4cedadeSeric 				return (0);
494c4cedadeSeric 
495c4cedadeSeric 		sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr);
496c4cedadeSeric 		if (errstr)
497c4cedadeSeric 			return (-1);
498b44da627Seric 		return (0);
499b44da627Seric 
500b44da627Seric 	default:
501b44da627Seric 		break;
502b44da627Seric 	}
503b44da627Seric 
504b44da627Seric 	return (-1);
505b44da627Seric }
5065bd9e5c2Seric 
5075bd9e5c2Seric ssize_t
508253ef892Sderaadt _asr_addr_as_fqdn(const char *addr, int family, char *dst, size_t max)
5095bd9e5c2Seric {
5105bd9e5c2Seric 	const struct in6_addr	*in6_addr;
5115bd9e5c2Seric 	in_addr_t		 in_addr;
5125bd9e5c2Seric 
5135bd9e5c2Seric 	switch (family) {
5145bd9e5c2Seric 	case AF_INET:
5155bd9e5c2Seric 		in_addr = ntohl(*((const in_addr_t *)addr));
5165bd9e5c2Seric 		snprintf(dst, max,
5175bd9e5c2Seric 		    "%d.%d.%d.%d.in-addr.arpa.",
5185bd9e5c2Seric 		    in_addr & 0xff,
5195bd9e5c2Seric 		    (in_addr >> 8) & 0xff,
5205bd9e5c2Seric 		    (in_addr >> 16) & 0xff,
5215bd9e5c2Seric 		    (in_addr >> 24) & 0xff);
5225bd9e5c2Seric 		break;
5235bd9e5c2Seric 	case AF_INET6:
5245bd9e5c2Seric 		in6_addr = (const struct in6_addr *)addr;
5255bd9e5c2Seric 		snprintf(dst, max,
5265bd9e5c2Seric 		    "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
5275bd9e5c2Seric 		    "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
5285bd9e5c2Seric 		    "ip6.arpa.",
5295bd9e5c2Seric 		    in6_addr->s6_addr[15] & 0xf,
5305bd9e5c2Seric 		    (in6_addr->s6_addr[15] >> 4) & 0xf,
5315bd9e5c2Seric 		    in6_addr->s6_addr[14] & 0xf,
5325bd9e5c2Seric 		    (in6_addr->s6_addr[14] >> 4) & 0xf,
5335bd9e5c2Seric 		    in6_addr->s6_addr[13] & 0xf,
5345bd9e5c2Seric 		    (in6_addr->s6_addr[13] >> 4) & 0xf,
5355bd9e5c2Seric 		    in6_addr->s6_addr[12] & 0xf,
5365bd9e5c2Seric 		    (in6_addr->s6_addr[12] >> 4) & 0xf,
5375bd9e5c2Seric 		    in6_addr->s6_addr[11] & 0xf,
5385bd9e5c2Seric 		    (in6_addr->s6_addr[11] >> 4) & 0xf,
5395bd9e5c2Seric 		    in6_addr->s6_addr[10] & 0xf,
5405bd9e5c2Seric 		    (in6_addr->s6_addr[10] >> 4) & 0xf,
5415bd9e5c2Seric 		    in6_addr->s6_addr[9] & 0xf,
5425bd9e5c2Seric 		    (in6_addr->s6_addr[9] >> 4) & 0xf,
5435bd9e5c2Seric 		    in6_addr->s6_addr[8] & 0xf,
5445bd9e5c2Seric 		    (in6_addr->s6_addr[8] >> 4) & 0xf,
5455bd9e5c2Seric 		    in6_addr->s6_addr[7] & 0xf,
5465bd9e5c2Seric 		    (in6_addr->s6_addr[7] >> 4) & 0xf,
5475bd9e5c2Seric 		    in6_addr->s6_addr[6] & 0xf,
5485bd9e5c2Seric 		    (in6_addr->s6_addr[6] >> 4) & 0xf,
5495bd9e5c2Seric 		    in6_addr->s6_addr[5] & 0xf,
5505bd9e5c2Seric 		    (in6_addr->s6_addr[5] >> 4) & 0xf,
5515bd9e5c2Seric 		    in6_addr->s6_addr[4] & 0xf,
5525bd9e5c2Seric 		    (in6_addr->s6_addr[4] >> 4) & 0xf,
5535bd9e5c2Seric 		    in6_addr->s6_addr[3] & 0xf,
5545bd9e5c2Seric 		    (in6_addr->s6_addr[3] >> 4) & 0xf,
5555bd9e5c2Seric 		    in6_addr->s6_addr[2] & 0xf,
5565bd9e5c2Seric 		    (in6_addr->s6_addr[2] >> 4) & 0xf,
5575bd9e5c2Seric 		    in6_addr->s6_addr[1] & 0xf,
5585bd9e5c2Seric 		    (in6_addr->s6_addr[1] >> 4) & 0xf,
5595bd9e5c2Seric 		    in6_addr->s6_addr[0] & 0xf,
5605bd9e5c2Seric 		    (in6_addr->s6_addr[0] >> 4) & 0xf);
5615bd9e5c2Seric 		break;
5625bd9e5c2Seric 	default:
5635bd9e5c2Seric 		return (-1);
5645bd9e5c2Seric 	}
5655bd9e5c2Seric 	return (0);
5665bd9e5c2Seric }
567