xref: /openbsd-src/lib/libc/asr/asr_utils.c (revision 373da8abb60949de81b32d3c8eaecdaabf17bdaa)
1*373da8abSflorian /*	$OpenBSD: asr_utils.c,v 1.22 2023/11/20 12:15:16 florian 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
dname_check_label(const char * s,size_t l)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
_asr_dname_from_fqdn(const char * str,char * dst,size_t max)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
dname_expand(const unsigned char * data,size_t len,size_t offset,size_t * newoffset,char * dst,size_t max)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) {
12643f5d167Smillert 			if (offset + 1 >= 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 		}
13643f5d167Smillert 		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
_asr_pack_init(struct asr_pack * pack,char * buf,size_t len)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
_asr_unpack_init(struct asr_unpack * unpack,const char * buf,size_t len)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
unpack_data(struct asr_unpack * p,void * data,size_t len)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
unpack_u16(struct asr_unpack * p,uint16_t * u16)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
unpack_u32(struct asr_unpack * p,uint32_t * u32)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
unpack_inaddr(struct asr_unpack * p,struct in_addr * a)222f90bf415Seric unpack_inaddr(struct asr_unpack *p, struct in_addr *a)
223b44da627Seric {
224b44da627Seric 	return (unpack_data(p, a, 4));
225b44da627Seric }
226b44da627Seric 
227b44da627Seric static int
unpack_in6addr(struct asr_unpack * p,struct in6_addr * a6)228f90bf415Seric unpack_in6addr(struct asr_unpack *p, struct in6_addr *a6)
229b44da627Seric {
230b44da627Seric 	return (unpack_data(p, a6, 16));
231b44da627Seric }
232b44da627Seric 
233b44da627Seric static int
unpack_dname(struct asr_unpack * p,char * dst,size_t max)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
_asr_unpack_header(struct asr_unpack * p,struct asr_dns_header * h)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
_asr_unpack_query(struct asr_unpack * p,struct asr_dns_query * q)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
_asr_unpack_rr(struct asr_unpack * p,struct asr_dns_rr * rr)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
pack_data(struct asr_pack * p,const void * data,size_t len)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
pack_u16(struct asr_pack * p,uint16_t v)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
pack_dname(struct asr_pack * p,const char * dname)384f90bf415Seric pack_dname(struct asr_pack *p, const char *dname)
385b44da627Seric {
386b44da627Seric 	/* dname compression would be nice to have here.
3872c53affbSjmc 	 * need additional context.
388b44da627Seric 	 */
389b44da627Seric 	return (pack_data(p, dname, strlen(dname) + 1));
390b44da627Seric }
391b44da627Seric 
392b44da627Seric int
_asr_pack_header(struct asr_pack * p,const struct asr_dns_header * h)393253ef892Sderaadt _asr_pack_header(struct asr_pack *p, const struct asr_dns_header *h)
394b44da627Seric {
395f90bf415Seric 	struct asr_dns_header c;
396b44da627Seric 
397b44da627Seric 	c.id = h->id;
398b44da627Seric 	c.flags = htons(h->flags);
399b44da627Seric 	c.qdcount = htons(h->qdcount);
400b44da627Seric 	c.ancount = htons(h->ancount);
401b44da627Seric 	c.nscount = htons(h->nscount);
402b44da627Seric 	c.arcount = htons(h->arcount);
403b44da627Seric 
404b44da627Seric 	return (pack_data(p, &c, HFIXEDSZ));
405b44da627Seric }
406b44da627Seric 
407b44da627Seric int
_asr_pack_query(struct asr_pack * p,uint16_t type,uint16_t class,const char * dname)408253ef892Sderaadt _asr_pack_query(struct asr_pack *p, uint16_t type, uint16_t class, const char *dname)
409b44da627Seric {
410b44da627Seric 	pack_dname(p, dname);
411b44da627Seric 	pack_u16(p, type);
412b44da627Seric 	pack_u16(p, class);
413b44da627Seric 
414b44da627Seric 	return (p->err) ? (-1) : (0);
415b44da627Seric }
416b44da627Seric 
417b44da627Seric int
_asr_pack_edns0(struct asr_pack * p,uint16_t pktsz,int dnssec_do)418d4d39a6fSjca _asr_pack_edns0(struct asr_pack *p, uint16_t pktsz, int dnssec_do)
4192aa4cd21Sjca {
420d4d39a6fSjca 	DPRINT("asr EDNS0 pktsz:%hu dnssec:%s\n", pktsz,
421d4d39a6fSjca 	    dnssec_do ? "yes" : "no");
422d4d39a6fSjca 
4232aa4cd21Sjca 	pack_dname(p, "");	/* root */
424c6fa5c87Sjca 	pack_u16(p, T_OPT);	/* OPT */
4252aa4cd21Sjca 	pack_u16(p, pktsz);	/* UDP payload size */
426d4d39a6fSjca 
427d4d39a6fSjca 	/* extended RCODE and flags */
428d4d39a6fSjca 	pack_u16(p, 0);
429d4d39a6fSjca 	pack_u16(p, dnssec_do ? DNS_MESSAGEEXTFLAG_DO : 0);
430d4d39a6fSjca 
4312aa4cd21Sjca 	pack_u16(p, 0);		/* RDATA len */
4322aa4cd21Sjca 
4332aa4cd21Sjca 	return (p->err) ? (-1) : (0);
4342aa4cd21Sjca }
4352aa4cd21Sjca 
4362aa4cd21Sjca int
_asr_sockaddr_from_str(struct sockaddr * sa,int family,const char * str)437253ef892Sderaadt _asr_sockaddr_from_str(struct sockaddr *sa, int family, const char *str)
438b44da627Seric {
439b44da627Seric 	struct in_addr		 ina;
440b44da627Seric 	struct in6_addr		 in6a;
441b44da627Seric 	struct sockaddr_in	*sin;
442b44da627Seric 	struct sockaddr_in6	*sin6;
443c4cedadeSeric 	char			*cp, *str2;
444c4cedadeSeric 	const char		*errstr;
445b44da627Seric 
446b44da627Seric 	switch (family) {
447b44da627Seric 	case PF_UNSPEC:
448253ef892Sderaadt 		if (_asr_sockaddr_from_str(sa, PF_INET, str) == 0)
449b44da627Seric 			return (0);
450253ef892Sderaadt 		return _asr_sockaddr_from_str(sa, PF_INET6, str);
451b44da627Seric 
452b44da627Seric 	case PF_INET:
453b44da627Seric 		if (inet_pton(PF_INET, str, &ina) != 1)
454b44da627Seric 			return (-1);
455b44da627Seric 
456b44da627Seric 		sin = (struct sockaddr_in *)sa;
457b44da627Seric 		memset(sin, 0, sizeof *sin);
458b44da627Seric 		sin->sin_len = sizeof(struct sockaddr_in);
459b44da627Seric 		sin->sin_family = PF_INET;
460b44da627Seric 		sin->sin_addr.s_addr = ina.s_addr;
461b44da627Seric 		return (0);
462b44da627Seric 
463b44da627Seric 	case PF_INET6:
464c4cedadeSeric 		cp = strchr(str, SCOPE_DELIMITER);
465c4cedadeSeric 		if (cp) {
466c4cedadeSeric 			str2 = strdup(str);
467c4cedadeSeric 			if (str2 == NULL)
468c4cedadeSeric 				return (-1);
469c4cedadeSeric 			str2[cp - str] = '\0';
470c4cedadeSeric 			if (inet_pton(PF_INET6, str2, &in6a) != 1) {
471c4cedadeSeric 				free(str2);
472c4cedadeSeric 				return (-1);
473c4cedadeSeric 			}
474c4cedadeSeric 			cp++;
475c4cedadeSeric 			free(str2);
476c4cedadeSeric 		} else if (inet_pton(PF_INET6, str, &in6a) != 1)
477b44da627Seric 			return (-1);
478b44da627Seric 
479b44da627Seric 		sin6 = (struct sockaddr_in6 *)sa;
480b44da627Seric 		memset(sin6, 0, sizeof *sin6);
481b44da627Seric 		sin6->sin6_len = sizeof(struct sockaddr_in6);
482b44da627Seric 		sin6->sin6_family = PF_INET6;
483b44da627Seric 		sin6->sin6_addr = in6a;
484c4cedadeSeric 
485c4cedadeSeric 		if (cp == NULL)
486c4cedadeSeric 			return (0);
487c4cedadeSeric 
488c4cedadeSeric 		if (IN6_IS_ADDR_LINKLOCAL(&in6a) ||
489c4cedadeSeric 		    IN6_IS_ADDR_MC_LINKLOCAL(&in6a) ||
490c4cedadeSeric 		    IN6_IS_ADDR_MC_INTFACELOCAL(&in6a))
491c4cedadeSeric 			if ((sin6->sin6_scope_id = if_nametoindex(cp)))
492c4cedadeSeric 				return (0);
493c4cedadeSeric 
494c4cedadeSeric 		sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr);
495c4cedadeSeric 		if (errstr)
496c4cedadeSeric 			return (-1);
497b44da627Seric 		return (0);
498b44da627Seric 
499b44da627Seric 	default:
500b44da627Seric 		break;
501b44da627Seric 	}
502b44da627Seric 
503b44da627Seric 	return (-1);
504b44da627Seric }
5055bd9e5c2Seric 
5065bd9e5c2Seric ssize_t
_asr_addr_as_fqdn(const char * addr,int family,char * dst,size_t max)507253ef892Sderaadt _asr_addr_as_fqdn(const char *addr, int family, char *dst, size_t max)
5085bd9e5c2Seric {
5095bd9e5c2Seric 	const struct in6_addr	*in6_addr;
5105bd9e5c2Seric 	in_addr_t		 in_addr;
5115bd9e5c2Seric 
5125bd9e5c2Seric 	switch (family) {
5135bd9e5c2Seric 	case AF_INET:
5145bd9e5c2Seric 		in_addr = ntohl(*((const in_addr_t *)addr));
5155bd9e5c2Seric 		snprintf(dst, max,
5165bd9e5c2Seric 		    "%d.%d.%d.%d.in-addr.arpa.",
5175bd9e5c2Seric 		    in_addr & 0xff,
5185bd9e5c2Seric 		    (in_addr >> 8) & 0xff,
5195bd9e5c2Seric 		    (in_addr >> 16) & 0xff,
5205bd9e5c2Seric 		    (in_addr >> 24) & 0xff);
5215bd9e5c2Seric 		break;
5225bd9e5c2Seric 	case AF_INET6:
5235bd9e5c2Seric 		in6_addr = (const struct in6_addr *)addr;
5245bd9e5c2Seric 		snprintf(dst, max,
5255bd9e5c2Seric 		    "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
5265bd9e5c2Seric 		    "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
5275bd9e5c2Seric 		    "ip6.arpa.",
5285bd9e5c2Seric 		    in6_addr->s6_addr[15] & 0xf,
5295bd9e5c2Seric 		    (in6_addr->s6_addr[15] >> 4) & 0xf,
5305bd9e5c2Seric 		    in6_addr->s6_addr[14] & 0xf,
5315bd9e5c2Seric 		    (in6_addr->s6_addr[14] >> 4) & 0xf,
5325bd9e5c2Seric 		    in6_addr->s6_addr[13] & 0xf,
5335bd9e5c2Seric 		    (in6_addr->s6_addr[13] >> 4) & 0xf,
5345bd9e5c2Seric 		    in6_addr->s6_addr[12] & 0xf,
5355bd9e5c2Seric 		    (in6_addr->s6_addr[12] >> 4) & 0xf,
5365bd9e5c2Seric 		    in6_addr->s6_addr[11] & 0xf,
5375bd9e5c2Seric 		    (in6_addr->s6_addr[11] >> 4) & 0xf,
5385bd9e5c2Seric 		    in6_addr->s6_addr[10] & 0xf,
5395bd9e5c2Seric 		    (in6_addr->s6_addr[10] >> 4) & 0xf,
5405bd9e5c2Seric 		    in6_addr->s6_addr[9] & 0xf,
5415bd9e5c2Seric 		    (in6_addr->s6_addr[9] >> 4) & 0xf,
5425bd9e5c2Seric 		    in6_addr->s6_addr[8] & 0xf,
5435bd9e5c2Seric 		    (in6_addr->s6_addr[8] >> 4) & 0xf,
5445bd9e5c2Seric 		    in6_addr->s6_addr[7] & 0xf,
5455bd9e5c2Seric 		    (in6_addr->s6_addr[7] >> 4) & 0xf,
5465bd9e5c2Seric 		    in6_addr->s6_addr[6] & 0xf,
5475bd9e5c2Seric 		    (in6_addr->s6_addr[6] >> 4) & 0xf,
5485bd9e5c2Seric 		    in6_addr->s6_addr[5] & 0xf,
5495bd9e5c2Seric 		    (in6_addr->s6_addr[5] >> 4) & 0xf,
5505bd9e5c2Seric 		    in6_addr->s6_addr[4] & 0xf,
5515bd9e5c2Seric 		    (in6_addr->s6_addr[4] >> 4) & 0xf,
5525bd9e5c2Seric 		    in6_addr->s6_addr[3] & 0xf,
5535bd9e5c2Seric 		    (in6_addr->s6_addr[3] >> 4) & 0xf,
5545bd9e5c2Seric 		    in6_addr->s6_addr[2] & 0xf,
5555bd9e5c2Seric 		    (in6_addr->s6_addr[2] >> 4) & 0xf,
5565bd9e5c2Seric 		    in6_addr->s6_addr[1] & 0xf,
5575bd9e5c2Seric 		    (in6_addr->s6_addr[1] >> 4) & 0xf,
5585bd9e5c2Seric 		    in6_addr->s6_addr[0] & 0xf,
5595bd9e5c2Seric 		    (in6_addr->s6_addr[0] >> 4) & 0xf);
5605bd9e5c2Seric 		break;
5615bd9e5c2Seric 	default:
5625bd9e5c2Seric 		return (-1);
5635bd9e5c2Seric 	}
5645bd9e5c2Seric 	return (0);
5655bd9e5c2Seric }
5661b04c78cSflorian 
5671b04c78cSflorian int
hnok_lenient(const char * dn)5681b04c78cSflorian hnok_lenient(const char *dn)
5691b04c78cSflorian {
5701b04c78cSflorian 	int pch = '\0', ch = *dn++;
5711b04c78cSflorian 
5721b04c78cSflorian 	while (ch != '\0') {
5731b04c78cSflorian 		/* can't start with . or - */
5741b04c78cSflorian 		if (pch == '\0' && (ch == '.' || ch == '-'))
5751b04c78cSflorian 			return 0;
5761b04c78cSflorian 		if (pch == '.' && ch == '.')
5771b04c78cSflorian 			return 0;
5781b04c78cSflorian 		if (!(isalpha((unsigned char)ch) || isdigit((unsigned char)ch) ||
5791b04c78cSflorian 		    ch == '.' || ch == '-' || ch == '_'))
5801b04c78cSflorian 			return 0;
5811b04c78cSflorian 		pch = ch; ch = *dn++;
5821b04c78cSflorian 	}
5831b04c78cSflorian 	return 1;
5841b04c78cSflorian }
585*373da8abSflorian 
586*373da8abSflorian /* Check if the hostname is localhost or if it's in the localhost domain */
587*373da8abSflorian int
_asr_is_localhost(const char * hn)588*373da8abSflorian _asr_is_localhost(const char *hn)
589*373da8abSflorian {
590*373da8abSflorian 	size_t	 hnlen, localhostlen;
591*373da8abSflorian 
592*373da8abSflorian 	if (hn == NULL)
593*373da8abSflorian 		return 0;
594*373da8abSflorian 
595*373da8abSflorian 	if (strcasecmp(hn, "localhost") == 0 ||
596*373da8abSflorian 	    strcasecmp(hn, "localhost.") == 0)
597*373da8abSflorian 		return 1;
598*373da8abSflorian 
599*373da8abSflorian 	hnlen = strlen(hn);
600*373da8abSflorian 	localhostlen = strlen(".localhost");
601*373da8abSflorian 
602*373da8abSflorian 	if (hnlen < localhostlen)
603*373da8abSflorian 		return 0;
604*373da8abSflorian 
605*373da8abSflorian 	if (strcasecmp(hn + hnlen - localhostlen, ".localhost") == 0)
606*373da8abSflorian 		return 1;
607*373da8abSflorian 
608*373da8abSflorian 	localhostlen++;
609*373da8abSflorian 	if (hnlen < localhostlen)
610*373da8abSflorian 		return 0;
611*373da8abSflorian 
612*373da8abSflorian 	if (strcasecmp(hn + hnlen - localhostlen, ".localhost.") == 0)
613*373da8abSflorian 		return 1;
614*373da8abSflorian 
615*373da8abSflorian 	return 0;
616*373da8abSflorian }
617