GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/asr/asr_utils.c Lines: 24 273 8.8 %
Date: 2017-11-07 Branches: 8 125 6.4 %

Line Branch Exec Source
1
/*	$OpenBSD: asr_utils.c,v 1.18 2017/09/23 20:55:06 jca Exp $	*/
2
/*
3
 * Copyright (c) 2009-2012	Eric Faurot	<eric@faurot.net>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
#include <sys/types.h>
19
#include <sys/socket.h>
20
#include <net/if.h>
21
#include <netinet/in.h>
22
#include <arpa/inet.h>
23
#include <arpa/nameser.h>
24
#include <netdb.h>
25
26
#include <asr.h>
27
#include <ctype.h>
28
#include <errno.h>
29
#include <stdint.h>
30
#include <stdio.h>
31
#include <stdlib.h>
32
#include <string.h>
33
#include <unistd.h>
34
35
#include "asr_private.h"
36
37
static int dname_check_label(const char *, size_t);
38
static ssize_t dname_expand(const unsigned char *, size_t, size_t, size_t *,
39
    char *, size_t);
40
41
static int unpack_data(struct asr_unpack *, void *, size_t);
42
static int unpack_u16(struct asr_unpack *, uint16_t *);
43
static int unpack_u32(struct asr_unpack *, uint32_t *);
44
static int unpack_inaddr(struct asr_unpack *, struct in_addr *);
45
static int unpack_in6addr(struct asr_unpack *, struct in6_addr *);
46
static int unpack_dname(struct asr_unpack *, char *, size_t);
47
48
static int pack_data(struct asr_pack *, const void *, size_t);
49
static int pack_u16(struct asr_pack *, uint16_t);
50
static int pack_dname(struct asr_pack *, const char *);
51
52
static int
53
dname_check_label(const char *s, size_t l)
54
{
55
	if (l == 0 || l > 63)
56
		return (-1);
57
58
	return (0);
59
}
60
61
ssize_t
62
_asr_dname_from_fqdn(const char *str, char *dst, size_t max)
63
{
64
	ssize_t	 res;
65
	size_t	 l, n;
66
	char	*d;
67
68
	res = 0;
69
70
	/* special case: the root domain */
71
	if (str[0] == '.') {
72
		if (str[1] != '\0')
73
			return (-1);
74
		if (dst && max >= 1)
75
			*dst = '\0';
76
		return (1);
77
	}
78
79
	for (; *str; str = d + 1) {
80
81
		d = strchr(str, '.');
82
		if (d == NULL || d == str)
83
			return (-1);
84
85
		l = (d - str);
86
87
		if (dname_check_label(str, l) == -1)
88
			return (-1);
89
90
		res += l + 1;
91
92
		if (dst) {
93
			*dst++ = l;
94
			max -= 1;
95
			n = (l > max) ? max : l;
96
			memmove(dst, str, n);
97
			max -= n;
98
			if (max == 0)
99
				dst = NULL;
100
			else
101
				dst += n;
102
		}
103
	}
104
105
	if (dst)
106
		*dst++ = '\0';
107
108
	return (res + 1);
109
}
110
111
static ssize_t
112
dname_expand(const unsigned char *data, size_t len, size_t offset,
113
    size_t *newoffset, char *dst, size_t max)
114
{
115
	size_t		 n, count, end, ptr, start;
116
	ssize_t		 res;
117
118
	if (offset >= len)
119
		return (-1);
120
121
	res = 0;
122
	end = start = offset;
123
124
	for (; (n = data[offset]); ) {
125
		if ((n & 0xc0) == 0xc0) {
126
			if (offset + 2 > len)
127
				return (-1);
128
			ptr = 256 * (n & ~0xc0) + data[offset + 1];
129
			if (ptr >= start)
130
				return (-1);
131
			if (end < offset + 2)
132
				end = offset + 2;
133
			offset = start = ptr;
134
			continue;
135
		}
136
		if (offset + n + 1 > len)
137
			return (-1);
138
139
		if (dname_check_label(data + offset + 1, n) == -1)
140
			return (-1);
141
142
		/* copy n + at offset+1 */
143
		if (dst != NULL && max != 0) {
144
			count = (max < n + 1) ? (max) : (n + 1);
145
			memmove(dst, data + offset, count);
146
			dst += count;
147
			max -= count;
148
		}
149
		res += n + 1;
150
		offset += n + 1;
151
		if (end < offset)
152
			end = offset;
153
	}
154
	if (end < offset + 1)
155
		end = offset + 1;
156
157
	if (dst != NULL && max != 0)
158
		dst[0] = 0;
159
	if (newoffset)
160
		*newoffset = end;
161
	return (res + 1);
162
}
163
164
void
165
_asr_pack_init(struct asr_pack *pack, char *buf, size_t len)
166
{
167
	pack->buf = buf;
168
	pack->len = len;
169
	pack->offset = 0;
170
	pack->err = 0;
171
}
172
173
void
174
_asr_unpack_init(struct asr_unpack *unpack, const char *buf, size_t len)
175
{
176
	unpack->buf = buf;
177
	unpack->len = len;
178
	unpack->offset = 0;
179
	unpack->err = 0;
180
}
181
182
static int
183
unpack_data(struct asr_unpack *p, void *data, size_t len)
184
{
185
	if (p->err)
186
		return (-1);
187
188
	if (p->len - p->offset < len) {
189
		p->err = EOVERFLOW;
190
		return (-1);
191
	}
192
193
	memmove(data, p->buf + p->offset, len);
194
	p->offset += len;
195
196
	return (0);
197
}
198
199
static int
200
unpack_u16(struct asr_unpack *p, uint16_t *u16)
201
{
202
	if (unpack_data(p, u16, 2) == -1)
203
		return (-1);
204
205
	*u16 = ntohs(*u16);
206
207
	return (0);
208
}
209
210
static int
211
unpack_u32(struct asr_unpack *p, uint32_t *u32)
212
{
213
	if (unpack_data(p, u32, 4) == -1)
214
		return (-1);
215
216
	*u32 = ntohl(*u32);
217
218
	return (0);
219
}
220
221
static int
222
unpack_inaddr(struct asr_unpack *p, struct in_addr *a)
223
{
224
	return (unpack_data(p, a, 4));
225
}
226
227
static int
228
unpack_in6addr(struct asr_unpack *p, struct in6_addr *a6)
229
{
230
	return (unpack_data(p, a6, 16));
231
}
232
233
static int
234
unpack_dname(struct asr_unpack *p, char *dst, size_t max)
235
{
236
	ssize_t e;
237
238
	if (p->err)
239
		return (-1);
240
241
	e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max);
242
	if (e == -1) {
243
		p->err = EINVAL;
244
		return (-1);
245
	}
246
	if (e < 0 || e > MAXDNAME) {
247
		p->err = ERANGE;
248
		return (-1);
249
	}
250
251
	return (0);
252
}
253
254
int
255
_asr_unpack_header(struct asr_unpack *p, struct asr_dns_header *h)
256
{
257
	if (unpack_data(p, h, HFIXEDSZ) == -1)
258
		return (-1);
259
260
	h->flags = ntohs(h->flags);
261
	h->qdcount = ntohs(h->qdcount);
262
	h->ancount = ntohs(h->ancount);
263
	h->nscount = ntohs(h->nscount);
264
	h->arcount = ntohs(h->arcount);
265
266
	return (0);
267
}
268
269
int
270
_asr_unpack_query(struct asr_unpack *p, struct asr_dns_query *q)
271
{
272
	unpack_dname(p, q->q_dname, sizeof(q->q_dname));
273
	unpack_u16(p, &q->q_type);
274
	unpack_u16(p, &q->q_class);
275
276
	return (p->err) ? (-1) : (0);
277
}
278
279
int
280
_asr_unpack_rr(struct asr_unpack *p, struct asr_dns_rr *rr)
281
{
282
	uint16_t	rdlen;
283
	size_t		save_offset;
284
285
	unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname));
286
	unpack_u16(p, &rr->rr_type);
287
	unpack_u16(p, &rr->rr_class);
288
	unpack_u32(p, &rr->rr_ttl);
289
	unpack_u16(p, &rdlen);
290
291
	if (p->err)
292
		return (-1);
293
294
	if (p->len - p->offset < rdlen) {
295
		p->err = EOVERFLOW;
296
		return (-1);
297
	}
298
299
	save_offset = p->offset;
300
301
	switch (rr->rr_type) {
302
303
	case T_CNAME:
304
		unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname));
305
		break;
306
307
	case T_MX:
308
		unpack_u16(p, &rr->rr.mx.preference);
309
		unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange));
310
		break;
311
312
	case T_NS:
313
		unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname));
314
		break;
315
316
	case T_PTR:
317
		unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname));
318
		break;
319
320
	case T_SOA:
321
		unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname));
322
		unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname));
323
		unpack_u32(p, &rr->rr.soa.serial);
324
		unpack_u32(p, &rr->rr.soa.refresh);
325
		unpack_u32(p, &rr->rr.soa.retry);
326
		unpack_u32(p, &rr->rr.soa.expire);
327
		unpack_u32(p, &rr->rr.soa.minimum);
328
		break;
329
330
	case T_A:
331
		if (rr->rr_class != C_IN)
332
			goto other;
333
		unpack_inaddr(p, &rr->rr.in_a.addr);
334
		break;
335
336
	case T_AAAA:
337
		if (rr->rr_class != C_IN)
338
			goto other;
339
		unpack_in6addr(p, &rr->rr.in_aaaa.addr6);
340
		break;
341
	default:
342
	other:
343
		rr->rr.other.rdata = p->buf + p->offset;
344
		rr->rr.other.rdlen = rdlen;
345
		p->offset += rdlen;
346
	}
347
348
	if (p->err)
349
		return (-1);
350
351
	/* make sure that the advertised rdlen is really ok */
352
	if (p->offset - save_offset != rdlen)
353
		p->err = EINVAL;
354
355
	return (p->err) ? (-1) : (0);
356
}
357
358
static int
359
pack_data(struct asr_pack *p, const void *data, size_t len)
360
{
361
	if (p->err)
362
		return (-1);
363
364
	if (p->len < p->offset + len) {
365
		p->err = EOVERFLOW;
366
		return (-1);
367
	}
368
369
	memmove(p->buf + p->offset, data, len);
370
	p->offset += len;
371
372
	return (0);
373
}
374
375
static int
376
pack_u16(struct asr_pack *p, uint16_t v)
377
{
378
	v = htons(v);
379
380
	return (pack_data(p, &v, 2));
381
}
382
383
static int
384
pack_dname(struct asr_pack *p, const char *dname)
385
{
386
	/* dname compression would be nice to have here.
387
	 * need additionnal context.
388
	 */
389
	return (pack_data(p, dname, strlen(dname) + 1));
390
}
391
392
int
393
_asr_pack_header(struct asr_pack *p, const struct asr_dns_header *h)
394
{
395
	struct asr_dns_header c;
396
397
	c.id = h->id;
398
	c.flags = htons(h->flags);
399
	c.qdcount = htons(h->qdcount);
400
	c.ancount = htons(h->ancount);
401
	c.nscount = htons(h->nscount);
402
	c.arcount = htons(h->arcount);
403
404
	return (pack_data(p, &c, HFIXEDSZ));
405
}
406
407
int
408
_asr_pack_query(struct asr_pack *p, uint16_t type, uint16_t class, const char *dname)
409
{
410
	pack_dname(p, dname);
411
	pack_u16(p, type);
412
	pack_u16(p, class);
413
414
	return (p->err) ? (-1) : (0);
415
}
416
417
int
418
_asr_pack_edns0(struct asr_pack *p, uint16_t pktsz, int dnssec_do)
419
{
420
	DPRINT("asr EDNS0 pktsz:%hu dnssec:%s\n", pktsz,
421
	    dnssec_do ? "yes" : "no");
422
423
	pack_dname(p, "");	/* root */
424
	pack_u16(p, T_OPT);	/* OPT */
425
	pack_u16(p, pktsz);	/* UDP payload size */
426
427
	/* extended RCODE and flags */
428
	pack_u16(p, 0);
429
	pack_u16(p, dnssec_do ? DNS_MESSAGEEXTFLAG_DO : 0);
430
431
	pack_u16(p, 0);		/* RDATA len */
432
433
	return (p->err) ? (-1) : (0);
434
}
435
436
int
437
_asr_sockaddr_from_str(struct sockaddr *sa, int family, const char *str)
438
{
439
212
	struct in_addr		 ina;
440
106
	struct in6_addr		 in6a;
441
	struct sockaddr_in	*sin;
442
	struct sockaddr_in6	*sin6;
443
	char			*cp, *str2;
444
106
	const char		*errstr;
445
446

106
	switch (family) {
447
	case PF_UNSPEC:
448
36
		if (_asr_sockaddr_from_str(sa, PF_INET, str) == 0)
449
36
			return (0);
450
		return _asr_sockaddr_from_str(sa, PF_INET6, str);
451
452
	case PF_INET:
453
36
		if (inet_pton(PF_INET, str, &ina) != 1)
454
			return (-1);
455
456
36
		sin = (struct sockaddr_in *)sa;
457
36
		memset(sin, 0, sizeof *sin);
458
36
		sin->sin_len = sizeof(struct sockaddr_in);
459
36
		sin->sin_family = PF_INET;
460
36
		sin->sin_addr.s_addr = ina.s_addr;
461
36
		return (0);
462
463
	case PF_INET6:
464
34
		cp = strchr(str, SCOPE_DELIMITER);
465
34
		if (cp) {
466
			str2 = strdup(str);
467
			if (str2 == NULL)
468
				return (-1);
469
			str2[cp - str] = '\0';
470
			if (inet_pton(PF_INET6, str2, &in6a) != 1) {
471
				free(str2);
472
				return (-1);
473
			}
474
			cp++;
475
			free(str2);
476
34
		} else if (inet_pton(PF_INET6, str, &in6a) != 1)
477
			return (-1);
478
479
34
		sin6 = (struct sockaddr_in6 *)sa;
480
34
		memset(sin6, 0, sizeof *sin6);
481
34
		sin6->sin6_len = sizeof(struct sockaddr_in6);
482
34
		sin6->sin6_family = PF_INET6;
483
34
		sin6->sin6_addr = in6a;
484
485
34
		if (cp == NULL)
486
34
			return (0);
487
488
		if (IN6_IS_ADDR_LINKLOCAL(&in6a) ||
489
		    IN6_IS_ADDR_MC_LINKLOCAL(&in6a) ||
490
		    IN6_IS_ADDR_MC_INTFACELOCAL(&in6a))
491
			if ((sin6->sin6_scope_id = if_nametoindex(cp)))
492
				return (0);
493
494
		sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr);
495
		if (errstr)
496
			return (-1);
497
		return (0);
498
499
	default:
500
		break;
501
	}
502
503
	return (-1);
504
106
}
505
506
ssize_t
507
_asr_addr_as_fqdn(const char *addr, int family, char *dst, size_t max)
508
{
509
	const struct in6_addr	*in6_addr;
510
	in_addr_t		 in_addr;
511
512
	switch (family) {
513
	case AF_INET:
514
		in_addr = ntohl(*((const in_addr_t *)addr));
515
		snprintf(dst, max,
516
		    "%d.%d.%d.%d.in-addr.arpa.",
517
		    in_addr & 0xff,
518
		    (in_addr >> 8) & 0xff,
519
		    (in_addr >> 16) & 0xff,
520
		    (in_addr >> 24) & 0xff);
521
		break;
522
	case AF_INET6:
523
		in6_addr = (const struct in6_addr *)addr;
524
		snprintf(dst, max,
525
		    "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
526
		    "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
527
		    "ip6.arpa.",
528
		    in6_addr->s6_addr[15] & 0xf,
529
		    (in6_addr->s6_addr[15] >> 4) & 0xf,
530
		    in6_addr->s6_addr[14] & 0xf,
531
		    (in6_addr->s6_addr[14] >> 4) & 0xf,
532
		    in6_addr->s6_addr[13] & 0xf,
533
		    (in6_addr->s6_addr[13] >> 4) & 0xf,
534
		    in6_addr->s6_addr[12] & 0xf,
535
		    (in6_addr->s6_addr[12] >> 4) & 0xf,
536
		    in6_addr->s6_addr[11] & 0xf,
537
		    (in6_addr->s6_addr[11] >> 4) & 0xf,
538
		    in6_addr->s6_addr[10] & 0xf,
539
		    (in6_addr->s6_addr[10] >> 4) & 0xf,
540
		    in6_addr->s6_addr[9] & 0xf,
541
		    (in6_addr->s6_addr[9] >> 4) & 0xf,
542
		    in6_addr->s6_addr[8] & 0xf,
543
		    (in6_addr->s6_addr[8] >> 4) & 0xf,
544
		    in6_addr->s6_addr[7] & 0xf,
545
		    (in6_addr->s6_addr[7] >> 4) & 0xf,
546
		    in6_addr->s6_addr[6] & 0xf,
547
		    (in6_addr->s6_addr[6] >> 4) & 0xf,
548
		    in6_addr->s6_addr[5] & 0xf,
549
		    (in6_addr->s6_addr[5] >> 4) & 0xf,
550
		    in6_addr->s6_addr[4] & 0xf,
551
		    (in6_addr->s6_addr[4] >> 4) & 0xf,
552
		    in6_addr->s6_addr[3] & 0xf,
553
		    (in6_addr->s6_addr[3] >> 4) & 0xf,
554
		    in6_addr->s6_addr[2] & 0xf,
555
		    (in6_addr->s6_addr[2] >> 4) & 0xf,
556
		    in6_addr->s6_addr[1] & 0xf,
557
		    (in6_addr->s6_addr[1] >> 4) & 0xf,
558
		    in6_addr->s6_addr[0] & 0xf,
559
		    (in6_addr->s6_addr[0] >> 4) & 0xf);
560
		break;
561
	default:
562
		return (-1);
563
	}
564
	return (0);
565
}