GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/asr/gethostnamadr_async.c Lines: 0 276 0.0 %
Date: 2017-11-07 Branches: 0 188 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: gethostnamadr_async.c,v 1.43 2017/02/23 17:04:02 eric Exp $	*/
2
/*
3
 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
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 <netinet/in.h>
21
#include <arpa/inet.h>
22
#include <arpa/nameser.h>
23
#include <netdb.h>
24
25
#include <asr.h>
26
#include <ctype.h>
27
#include <errno.h>
28
#include <resolv.h> /* for res_hnok */
29
#include <stdlib.h>
30
#include <string.h>
31
#include <unistd.h>
32
#include <limits.h>
33
34
#include "asr_private.h"
35
36
#define MAXALIASES	35
37
#define MAXADDRS	35
38
39
struct hostent_ext {
40
	struct hostent	 h;
41
	char		*aliases[MAXALIASES + 1];
42
	char		*addrs[MAXADDRS + 1];
43
	char		*end;
44
	char		*pos;
45
};
46
47
static int gethostnamadr_async_run(struct asr_query *, struct asr_result *);
48
static struct hostent_ext *hostent_alloc(int);
49
static int hostent_set_cname(struct hostent_ext *, const char *, int);
50
static int hostent_add_alias(struct hostent_ext *, const char *, int);
51
static int hostent_add_addr(struct hostent_ext *, const void *, size_t);
52
static struct hostent_ext *hostent_from_addr(int, const char *, const char *);
53
static struct hostent_ext *hostent_file_match(FILE *, int, int, const char *,
54
    int);
55
static struct hostent_ext *hostent_from_packet(int, int, char *, size_t);
56
57
struct asr_query *
58
gethostbyname_async(const char *name, void *asr)
59
{
60
	return gethostbyname2_async(name, AF_INET, asr);
61
}
62
DEF_WEAK(gethostbyname_async);
63
64
struct asr_query *
65
gethostbyname2_async(const char *name, int af, void *asr)
66
{
67
	struct asr_ctx	 *ac;
68
	struct asr_query *as;
69
70
	/* the original segfaults */
71
	if (name == NULL) {
72
		errno = EINVAL;
73
		return (NULL);
74
	}
75
76
	ac = _asr_use_resolver(asr);
77
	if ((as = _asr_async_new(ac, ASR_GETHOSTBYNAME)) == NULL)
78
		goto abort; /* errno set */
79
	as->as_run = gethostnamadr_async_run;
80
81
	as->as.hostnamadr.family = af;
82
	if (af == AF_INET)
83
		as->as.hostnamadr.addrlen = INADDRSZ;
84
	else if (af == AF_INET6)
85
		as->as.hostnamadr.addrlen = IN6ADDRSZ;
86
	as->as.hostnamadr.name = strdup(name);
87
	if (as->as.hostnamadr.name == NULL)
88
		goto abort; /* errno set */
89
90
	_asr_ctx_unref(ac);
91
	return (as);
92
93
    abort:
94
	if (as)
95
		_asr_async_free(as);
96
	_asr_ctx_unref(ac);
97
	return (NULL);
98
}
99
DEF_WEAK(gethostbyname2_async);
100
101
struct asr_query *
102
gethostbyaddr_async(const void *addr, socklen_t len, int af, void *asr)
103
{
104
	struct asr_ctx	 *ac;
105
	struct asr_query *as;
106
107
	ac = _asr_use_resolver(asr);
108
	as = _gethostbyaddr_async_ctx(addr, len, af, ac);
109
	_asr_ctx_unref(ac);
110
111
	return (as);
112
}
113
DEF_WEAK(gethostbyaddr_async);
114
115
struct asr_query *
116
_gethostbyaddr_async_ctx(const void *addr, socklen_t len, int af,
117
    struct asr_ctx *ac)
118
{
119
	struct asr_query *as;
120
121
	if ((as = _asr_async_new(ac, ASR_GETHOSTBYADDR)) == NULL)
122
		goto abort; /* errno set */
123
	as->as_run = gethostnamadr_async_run;
124
125
	as->as.hostnamadr.family = af;
126
	as->as.hostnamadr.addrlen = len;
127
	if (len > 0)
128
		memmove(as->as.hostnamadr.addr, addr, (len > 16) ? 16 : len);
129
130
	return (as);
131
132
    abort:
133
	if (as)
134
		_asr_async_free(as);
135
	return (NULL);
136
}
137
138
static int
139
gethostnamadr_async_run(struct asr_query *as, struct asr_result *ar)
140
{
141
	struct hostent_ext	*h;
142
	int			 r, type, saved_errno;
143
	FILE			*f;
144
	char			 name[MAXDNAME], *data, addr[16], *c;
145
146
    next:
147
	switch (as->as_state) {
148
149
	case ASR_STATE_INIT:
150
151
		if (as->as.hostnamadr.family != AF_INET &&
152
		    as->as.hostnamadr.family != AF_INET6) {
153
			ar->ar_h_errno = NETDB_INTERNAL;
154
			ar->ar_errno = EAFNOSUPPORT;
155
			async_set_state(as, ASR_STATE_HALT);
156
			break;
157
		}
158
159
		if ((as->as.hostnamadr.family == AF_INET &&
160
		     as->as.hostnamadr.addrlen != INADDRSZ) ||
161
		    (as->as.hostnamadr.family == AF_INET6 &&
162
		     as->as.hostnamadr.addrlen != IN6ADDRSZ)) {
163
			ar->ar_h_errno = NETDB_INTERNAL;
164
			ar->ar_errno = EINVAL;
165
			async_set_state(as, ASR_STATE_HALT);
166
			break;
167
		}
168
169
		if (as->as_type == ASR_GETHOSTBYNAME) {
170
171
			if (as->as.hostnamadr.name[0] == '\0') {
172
				ar->ar_h_errno = NO_DATA;
173
				async_set_state(as, ASR_STATE_HALT);
174
				break;
175
			}
176
177
			/* Name might be an IP address string */
178
			for (c = as->as.hostnamadr.name; *c; c++)
179
				if (!isdigit((unsigned char)*c) &&
180
				     *c != '.' && *c != ':')
181
					break;
182
			if (*c == 0 &&
183
			    inet_pton(as->as.hostnamadr.family,
184
			    as->as.hostnamadr.name, addr) == 1) {
185
				h = hostent_from_addr(as->as.hostnamadr.family,
186
				    as->as.hostnamadr.name, addr);
187
				if (h == NULL) {
188
					ar->ar_errno = errno;
189
					ar->ar_h_errno = NETDB_INTERNAL;
190
				}
191
				else {
192
					ar->ar_hostent = &h->h;
193
					ar->ar_h_errno = NETDB_SUCCESS;
194
				}
195
				async_set_state(as, ASR_STATE_HALT);
196
				break;
197
			}
198
		}
199
		async_set_state(as, ASR_STATE_NEXT_DB);
200
		break;
201
202
	case ASR_STATE_NEXT_DB:
203
204
		if (_asr_iter_db(as) == -1) {
205
			async_set_state(as, ASR_STATE_NOT_FOUND);
206
			break;
207
		}
208
209
		switch (AS_DB(as)) {
210
211
		case ASR_DB_DNS:
212
213
			/* Create a subquery to do the DNS lookup */
214
215
			if (as->as_type == ASR_GETHOSTBYNAME) {
216
				type = (as->as.hostnamadr.family == AF_INET) ?
217
				    T_A : T_AAAA;
218
				as->as_subq = _res_search_async_ctx(
219
				    as->as.hostnamadr.name,
220
				    C_IN, type, as->as_ctx);
221
			} else {
222
				_asr_addr_as_fqdn(as->as.hostnamadr.addr,
223
				    as->as.hostnamadr.family,
224
				    name, sizeof(name));
225
				as->as_subq = _res_query_async_ctx(
226
				    name, C_IN, T_PTR, as->as_ctx);
227
			}
228
229
			if (as->as_subq == NULL) {
230
				ar->ar_errno = errno;
231
				ar->ar_h_errno = NETDB_INTERNAL;
232
				async_set_state(as, ASR_STATE_HALT);
233
				break;
234
			}
235
236
			async_set_state(as, ASR_STATE_SUBQUERY);
237
			break;
238
239
		case ASR_DB_FILE:
240
241
			/* Try to find a match in the host file */
242
243
			if ((f = fopen(_PATH_HOSTS, "re")) == NULL)
244
				break;
245
246
			if (as->as_type == ASR_GETHOSTBYNAME)
247
				data = as->as.hostnamadr.name;
248
			else
249
				data = as->as.hostnamadr.addr;
250
251
			h = hostent_file_match(f, as->as_type,
252
			    as->as.hostnamadr.family, data,
253
			    as->as.hostnamadr.addrlen);
254
			saved_errno = errno;
255
			fclose(f);
256
			errno = saved_errno;
257
258
			if (h == NULL) {
259
				if (errno) {
260
					ar->ar_errno = errno;
261
					ar->ar_h_errno = NETDB_INTERNAL;
262
					async_set_state(as, ASR_STATE_HALT);
263
				}
264
				/* otherwise not found */
265
				break;
266
			}
267
			ar->ar_hostent = &h->h;
268
			ar->ar_h_errno = NETDB_SUCCESS;
269
			async_set_state(as, ASR_STATE_HALT);
270
			break;
271
		}
272
		break;
273
274
	case ASR_STATE_SUBQUERY:
275
276
		/* Run the DNS subquery. */
277
278
		if ((r = asr_run(as->as_subq, ar)) == ASYNC_COND)
279
			return (ASYNC_COND);
280
281
		/* Done. */
282
		as->as_subq = NULL;
283
284
		if (ar->ar_datalen == -1) {
285
			async_set_state(as, ASR_STATE_NEXT_DB);
286
			break;
287
		}
288
289
		/* If we got a packet but no anwser, use the next DB. */
290
		if (ar->ar_count == 0) {
291
			free(ar->ar_data);
292
			as->as.hostnamadr.subq_h_errno = ar->ar_h_errno;
293
			async_set_state(as, ASR_STATE_NEXT_DB);
294
			break;
295
		}
296
297
		/* Read the hostent from the packet. */
298
299
		h = hostent_from_packet(as->as_type,
300
		    as->as.hostnamadr.family, ar->ar_data, ar->ar_datalen);
301
		free(ar->ar_data);
302
		if (h == NULL) {
303
			ar->ar_errno = errno;
304
			ar->ar_h_errno = NETDB_INTERNAL;
305
			async_set_state(as, ASR_STATE_HALT);
306
			break;
307
		}
308
309
		if (as->as_type == ASR_GETHOSTBYADDR) {
310
			if (hostent_add_addr(h, as->as.hostnamadr.addr,
311
			    as->as.hostnamadr.addrlen) == -1) {
312
				free(h);
313
				ar->ar_errno = errno;
314
				ar->ar_h_errno = NETDB_INTERNAL;
315
				async_set_state(as, ASR_STATE_HALT);
316
				break;
317
			}
318
		}
319
320
		/*
321
		 * No valid hostname or address found in the dns packet.
322
		 * Ignore it.
323
		 */
324
		if ((as->as_type == ASR_GETHOSTBYNAME &&
325
		     h->h.h_addr_list[0] == NULL) ||
326
		    h->h.h_name == NULL) {
327
			free(h);
328
			async_set_state(as, ASR_STATE_NEXT_DB);
329
			break;
330
		}
331
332
		ar->ar_hostent = &h->h;
333
		ar->ar_h_errno = NETDB_SUCCESS;
334
		async_set_state(as, ASR_STATE_HALT);
335
		break;
336
337
	case ASR_STATE_NOT_FOUND:
338
		ar->ar_errno = 0;
339
		if (as->as.hostnamadr.subq_h_errno)
340
			ar->ar_h_errno = as->as.hostnamadr.subq_h_errno;
341
		else
342
			ar->ar_h_errno = HOST_NOT_FOUND;
343
		async_set_state(as, ASR_STATE_HALT);
344
		break;
345
346
	case ASR_STATE_HALT:
347
		if (ar->ar_h_errno)
348
			ar->ar_hostent = NULL;
349
		else
350
			ar->ar_errno = 0;
351
		return (ASYNC_DONE);
352
353
	default:
354
		ar->ar_errno = EOPNOTSUPP;
355
		ar->ar_h_errno = NETDB_INTERNAL;
356
		ar->ar_gai_errno = EAI_SYSTEM;
357
		async_set_state(as, ASR_STATE_HALT);
358
		break;
359
	}
360
	goto next;
361
}
362
363
/*
364
 * Create a hostent from a numeric address string.
365
 */
366
static struct hostent_ext *
367
hostent_from_addr(int family, const char *name, const char *addr)
368
{
369
	struct	 hostent_ext *h;
370
371
	if ((h = hostent_alloc(family)) == NULL)
372
		return (NULL);
373
	if (hostent_set_cname(h, name, 0) == -1)
374
		goto fail;
375
	if (hostent_add_addr(h, addr, h->h.h_length) == -1)
376
		goto fail;
377
	return (h);
378
fail:
379
	free(h);
380
	return (NULL);
381
}
382
383
/*
384
 * Lookup the first matching entry in the hostfile, either by address or by
385
 * name depending on reqtype, and build a hostent from the line.
386
 */
387
static struct hostent_ext *
388
hostent_file_match(FILE *f, int reqtype, int family, const char *data,
389
    int datalen)
390
{
391
	char	*tokens[MAXTOKEN], addr[16], buf[BUFSIZ + 1];
392
	struct	 hostent_ext *h;
393
	int	 n, i;
394
395
	for (;;) {
396
		n = _asr_parse_namedb_line(f, tokens, MAXTOKEN, buf, sizeof(buf));
397
		if (n == -1) {
398
			errno = 0; /* ignore errors reading the file */
399
			return (NULL);
400
		}
401
402
		/* there must be an address and at least one name */
403
		if (n < 2)
404
			continue;
405
406
		if (reqtype == ASR_GETHOSTBYNAME) {
407
			for (i = 1; i < n; i++) {
408
				if (strcasecmp(data, tokens[i]))
409
					continue;
410
				if (inet_pton(family, tokens[0], addr) == 1)
411
					goto found;
412
			}
413
		} else {
414
			if (inet_pton(family, tokens[0], addr) == 1 &&
415
			    memcmp(addr, data, datalen) == 0)
416
				goto found;
417
		}
418
	}
419
420
found:
421
	if ((h = hostent_alloc(family)) == NULL)
422
		return (NULL);
423
	if (hostent_set_cname(h, tokens[1], 0) == -1)
424
		goto fail;
425
	for (i = 2; i < n; i ++)
426
		if (hostent_add_alias(h, tokens[i], 0) == -1)
427
			goto fail;
428
	if (hostent_add_addr(h, addr, h->h.h_length) == -1)
429
		goto fail;
430
	return (h);
431
fail:
432
	free(h);
433
	return (NULL);
434
}
435
436
/*
437
 * Fill the hostent from the given DNS packet.
438
 */
439
static struct hostent_ext *
440
hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen)
441
{
442
	struct hostent_ext	*h;
443
	struct asr_unpack	 p;
444
	struct asr_dns_header	 hdr;
445
	struct asr_dns_query	 q;
446
	struct asr_dns_rr	 rr;
447
	char			 dname[MAXDNAME];
448
449
	if ((h = hostent_alloc(family)) == NULL)
450
		return (NULL);
451
452
	_asr_unpack_init(&p, pkt, pktlen);
453
	_asr_unpack_header(&p, &hdr);
454
	for (; hdr.qdcount; hdr.qdcount--)
455
		_asr_unpack_query(&p, &q);
456
	strlcpy(dname, q.q_dname, sizeof(dname));
457
458
	for (; hdr.ancount; hdr.ancount--) {
459
		_asr_unpack_rr(&p, &rr);
460
		if (rr.rr_class != C_IN)
461
			continue;
462
		switch (rr.rr_type) {
463
464
		case T_CNAME:
465
			if (reqtype == ASR_GETHOSTBYNAME) {
466
				if (hostent_add_alias(h, rr.rr_dname, 1) == -1)
467
					goto fail;
468
			} else {
469
				if (strcasecmp(rr.rr_dname, dname) == 0)
470
					strlcpy(dname, rr.rr.cname.cname,
471
					    sizeof(dname));
472
			}
473
			break;
474
475
		case T_PTR:
476
			if (reqtype != ASR_GETHOSTBYADDR)
477
				break;
478
			if (strcasecmp(rr.rr_dname, dname) != 0)
479
				continue;
480
			if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1)
481
				hostent_add_alias(h, rr.rr.ptr.ptrname, 1);
482
			break;
483
484
		case T_A:
485
			if (reqtype != ASR_GETHOSTBYNAME)
486
				break;
487
			if (family != AF_INET)
488
				break;
489
			if (hostent_set_cname(h, rr.rr_dname, 1) == -1)
490
				;
491
			if (hostent_add_addr(h, &rr.rr.in_a.addr, 4) == -1)
492
				goto fail;
493
			break;
494
495
		case T_AAAA:
496
			if (reqtype != ASR_GETHOSTBYNAME)
497
				break;
498
			if (family != AF_INET6)
499
				break;
500
			if (hostent_set_cname(h, rr.rr_dname, 1) == -1)
501
				;
502
			if (hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16) == -1)
503
				goto fail;
504
			break;
505
		}
506
	}
507
508
	return (h);
509
fail:
510
	free(h);
511
	return (NULL);
512
}
513
514
static struct hostent_ext *
515
hostent_alloc(int family)
516
{
517
	struct hostent_ext	*h;
518
	size_t			alloc;
519
520
	alloc = sizeof(*h) + 1024;
521
	if ((h = calloc(1, alloc)) == NULL)
522
		return (NULL);
523
524
	h->h.h_addrtype = family;
525
	h->h.h_length = (family == AF_INET) ? 4 : 16;
526
	h->h.h_aliases = h->aliases;
527
	h->h.h_addr_list = h->addrs;
528
	h->pos = (char *)(h) + sizeof(*h);
529
	h->end = h->pos + 1024;
530
531
	return (h);
532
}
533
534
static int
535
hostent_set_cname(struct hostent_ext *h, const char *name, int isdname)
536
{
537
	char	buf[MAXDNAME];
538
	size_t	n;
539
540
	if (h->h.h_name)
541
		return (-1);
542
543
	if (isdname) {
544
		_asr_strdname(name, buf, sizeof buf);
545
		buf[strlen(buf) - 1] = '\0';
546
		if (!res_hnok(buf))
547
			return (-1);
548
		name = buf;
549
	}
550
551
	n = strlen(name) + 1;
552
	if (h->pos + n >= h->end)
553
		return (-1);
554
555
	h->h.h_name = h->pos;
556
	memmove(h->pos, name, n);
557
	h->pos += n;
558
	return (0);
559
}
560
561
static int
562
hostent_add_alias(struct hostent_ext *h, const char *name, int isdname)
563
{
564
	char	buf[MAXDNAME];
565
	size_t	i, n;
566
567
	for (i = 0; i < MAXALIASES; i++)
568
		if (h->aliases[i] == NULL)
569
			break;
570
	if (i == MAXALIASES)
571
		return (0);
572
573
	if (isdname) {
574
		_asr_strdname(name, buf, sizeof buf);
575
		buf[strlen(buf)-1] = '\0';
576
		if (!res_hnok(buf))
577
			return (-1);
578
		name = buf;
579
	}
580
581
	n = strlen(name) + 1;
582
	if (h->pos + n >= h->end)
583
		return (0);
584
585
	h->aliases[i] = h->pos;
586
	memmove(h->pos, name, n);
587
	h->pos += n;
588
	return (0);
589
}
590
591
static int
592
hostent_add_addr(struct hostent_ext *h, const void *addr, size_t size)
593
{
594
	int	i;
595
596
	for (i = 0; i < MAXADDRS; i++)
597
		if (h->addrs[i] == NULL)
598
			break;
599
	if (i == MAXADDRS)
600
		return (0);
601
602
	if (h->pos + size >= h->end)
603
		return (0);
604
605
	h->addrs[i] = h->pos;
606
	memmove(h->pos, addr, size);
607
	h->pos += size;
608
	return (0);
609
}