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

Line Branch Exec Source
1
/*	$OpenBSD: getnetnamadr_async.c,v 1.25 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 <errno.h>
27
#include <resolv.h> /* for res_hnok */
28
#include <stdlib.h>
29
#include <string.h>
30
#include <unistd.h>
31
32
#include "asr_private.h"
33
34
#define MAXALIASES	16
35
36
struct netent_ext {
37
	struct netent	 n;
38
	char		*aliases[MAXALIASES + 1];
39
	char		*end;
40
	char		*pos;
41
};
42
43
static int getnetnamadr_async_run(struct asr_query *, struct asr_result *);
44
static struct netent_ext *netent_alloc(int);
45
static int netent_set_cname(struct netent_ext *, const char *, int);
46
static int netent_add_alias(struct netent_ext *, const char *, int);
47
static struct netent_ext *netent_file_match(FILE *, int, const char *);
48
static struct netent_ext *netent_from_packet(int, char *, size_t);
49
50
struct asr_query *
51
getnetbyname_async(const char *name, void *asr)
52
{
53
	struct asr_ctx	 *ac;
54
	struct asr_query *as;
55
56
	/* The current resolver segfaults. */
57
	if (name == NULL) {
58
		errno = EINVAL;
59
		return (NULL);
60
	}
61
62
	ac = _asr_use_resolver(asr);
63
	if ((as = _asr_async_new(ac, ASR_GETNETBYNAME)) == NULL)
64
		goto abort; /* errno set */
65
	as->as_run = getnetnamadr_async_run;
66
67
	as->as.netnamadr.family = AF_INET;
68
	as->as.netnamadr.name = strdup(name);
69
	if (as->as.netnamadr.name == NULL)
70
		goto abort; /* errno set */
71
72
	_asr_ctx_unref(ac);
73
	return (as);
74
75
    abort:
76
	if (as)
77
		_asr_async_free(as);
78
	_asr_ctx_unref(ac);
79
	return (NULL);
80
}
81
DEF_WEAK(getnetbyname_async);
82
83
struct asr_query *
84
getnetbyaddr_async(in_addr_t net, int family, void *asr)
85
{
86
	struct asr_ctx	 *ac;
87
	struct asr_query *as;
88
89
	ac = _asr_use_resolver(asr);
90
	if ((as = _asr_async_new(ac, ASR_GETNETBYADDR)) == NULL)
91
		goto abort; /* errno set */
92
	as->as_run = getnetnamadr_async_run;
93
94
	as->as.netnamadr.family = family;
95
	as->as.netnamadr.addr = net;
96
97
	_asr_ctx_unref(ac);
98
	return (as);
99
100
    abort:
101
	if (as)
102
		_asr_async_free(as);
103
	_asr_ctx_unref(ac);
104
	return (NULL);
105
}
106
DEF_WEAK(getnetbyaddr_async);
107
108
static int
109
getnetnamadr_async_run(struct asr_query *as, struct asr_result *ar)
110
{
111
	struct netent_ext	*n;
112
	int			 r, type, saved_errno;
113
	FILE			*f;
114
	char			 dname[MAXDNAME], *name, *data;
115
	in_addr_t		 in;
116
117
    next:
118
	switch (as->as_state) {
119
120
	case ASR_STATE_INIT:
121
122
		if (as->as.netnamadr.family != AF_INET) {
123
			ar->ar_h_errno = NETDB_INTERNAL;
124
			ar->ar_errno = EAFNOSUPPORT;
125
			async_set_state(as, ASR_STATE_HALT);
126
			break;
127
		}
128
129
		if (as->as_type == ASR_GETNETBYNAME &&
130
		    as->as.netnamadr.name[0] == '\0') {
131
			ar->ar_h_errno = NO_DATA;
132
			async_set_state(as, ASR_STATE_HALT);
133
			break;
134
		}
135
136
		async_set_state(as, ASR_STATE_NEXT_DB);
137
		break;
138
139
	case ASR_STATE_NEXT_DB:
140
141
		if (_asr_iter_db(as) == -1) {
142
			async_set_state(as, ASR_STATE_NOT_FOUND);
143
			break;
144
		}
145
146
		switch (AS_DB(as)) {
147
		case ASR_DB_DNS:
148
149
			if (as->as_type == ASR_GETNETBYNAME) {
150
				type = T_A;
151
				/*
152
				 * I think we want to do the former, but our
153
				 * resolver is doing the following, so let's
154
				 * preserve bugward-compatibility there.
155
				 */
156
				type = T_PTR;
157
				name = as->as.netnamadr.name;
158
				as->as_subq = _res_search_async_ctx(
159
				    name, C_IN, type, as->as_ctx);
160
			} else {
161
				type = T_PTR;
162
				name = dname;
163
164
				in = htonl(as->as.netnamadr.addr);
165
				_asr_addr_as_fqdn((char *)&in,
166
				    as->as.netnamadr.family,
167
				    dname, sizeof(dname));
168
				as->as_subq = _res_query_async_ctx(
169
				    name, C_IN, type, as->as_ctx);
170
			}
171
172
			if (as->as_subq == NULL) {
173
				ar->ar_errno = errno;
174
				ar->ar_h_errno = NETDB_INTERNAL;
175
				async_set_state(as, ASR_STATE_HALT);
176
				break;
177
			}
178
			async_set_state(as, ASR_STATE_SUBQUERY);
179
			break;
180
181
		case ASR_DB_FILE:
182
183
			if ((f = fopen(_PATH_NETWORKS, "re")) == NULL)
184
				break;
185
186
			if (as->as_type == ASR_GETNETBYNAME)
187
				data = as->as.netnamadr.name;
188
			else
189
				data = (void *)&as->as.netnamadr.addr;
190
191
			n = netent_file_match(f, as->as_type, data);
192
			saved_errno = errno;
193
			fclose(f);
194
			errno = saved_errno;
195
			if (n == NULL) {
196
				if (errno) {
197
					ar->ar_errno = errno;
198
					ar->ar_h_errno = NETDB_INTERNAL;
199
					async_set_state(as, ASR_STATE_HALT);
200
				}
201
				/* otherwise not found */
202
				break;
203
			}
204
205
			ar->ar_netent = &n->n;
206
			ar->ar_h_errno = NETDB_SUCCESS;
207
			async_set_state(as, ASR_STATE_HALT);
208
			break;
209
		}
210
		break;
211
212
	case ASR_STATE_SUBQUERY:
213
214
		if ((r = asr_run(as->as_subq, ar)) == ASYNC_COND)
215
			return (ASYNC_COND);
216
		as->as_subq = NULL;
217
218
		if (ar->ar_datalen == -1) {
219
			async_set_state(as, ASR_STATE_NEXT_DB);
220
			break;
221
		}
222
223
		/* Got packet, but no answer */
224
		if (ar->ar_count == 0) {
225
			free(ar->ar_data);
226
			async_set_state(as, ASR_STATE_NEXT_DB);
227
			break;
228
		}
229
230
		n = netent_from_packet(as->as_type, ar->ar_data,
231
		    ar->ar_datalen);
232
		free(ar->ar_data);
233
		if (n == NULL) {
234
			ar->ar_errno = errno;
235
			ar->ar_h_errno = NETDB_INTERNAL;
236
			async_set_state(as, ASR_STATE_HALT);
237
			break;
238
		}
239
240
		if (as->as_type == ASR_GETNETBYADDR)
241
			n->n.n_net = as->as.netnamadr.addr;
242
243
		/*
244
		 * No valid hostname or address found in the dns packet.
245
		 * Ignore it.
246
		 */
247
		if ((as->as_type == ASR_GETNETBYNAME && n->n.n_net == 0) ||
248
		    n->n.n_name == NULL) {
249
			free(n);
250
			async_set_state(as, ASR_STATE_NEXT_DB);
251
			break;
252
		}
253
254
		ar->ar_netent = &n->n;
255
		ar->ar_h_errno = NETDB_SUCCESS;
256
		async_set_state(as, ASR_STATE_HALT);
257
		break;
258
259
	case ASR_STATE_NOT_FOUND:
260
261
		ar->ar_errno = 0;
262
		ar->ar_h_errno = HOST_NOT_FOUND;
263
		async_set_state(as, ASR_STATE_HALT);
264
		break;
265
266
	case ASR_STATE_HALT:
267
268
		if (ar->ar_h_errno)
269
			ar->ar_netent = NULL;
270
		else
271
			ar->ar_errno = 0;
272
		return (ASYNC_DONE);
273
274
	default:
275
		ar->ar_errno = EOPNOTSUPP;
276
		ar->ar_h_errno = NETDB_INTERNAL;
277
		ar->ar_gai_errno = EAI_SYSTEM;
278
		async_set_state(as, ASR_STATE_HALT);
279
		break;
280
	}
281
	goto next;
282
}
283
284
static struct netent_ext *
285
netent_file_match(FILE *f, int reqtype, const char *data)
286
{
287
	struct netent_ext	*e;
288
	char			*tokens[MAXTOKEN], buf[BUFSIZ + 1];
289
	int			 n, i;
290
	in_addr_t		 net;
291
292
	for (;;) {
293
		n = _asr_parse_namedb_line(f, tokens, MAXTOKEN, buf, sizeof(buf));
294
		if (n == -1) {
295
			errno = 0; /* ignore errors reading the file */
296
			return (NULL);
297
		}
298
299
		/* there must be an address and at least one name */
300
		if (n < 2)
301
			continue;
302
303
		if (reqtype == ASR_GETNETBYADDR) {
304
			net = inet_network(tokens[1]);
305
			if (memcmp(&net, data, sizeof net) == 0)
306
				goto found;
307
		} else {
308
			for (i = 0; i < n; i++) {
309
				if (i == 1)
310
					continue;
311
				if (strcasecmp(data, tokens[i]))
312
					continue;
313
				goto found;
314
			}
315
		}
316
	}
317
318
found:
319
	if ((e = netent_alloc(AF_INET)) == NULL)
320
		return (NULL);
321
	if (netent_set_cname(e, tokens[0], 0) == -1)
322
		goto fail;
323
	for (i = 2; i < n; i ++)
324
		if (netent_add_alias(e, tokens[i], 0) == -1)
325
			goto fail;
326
	e->n.n_net = inet_network(tokens[1]);
327
	return (e);
328
fail:
329
	free(e);
330
	return (NULL);
331
}
332
333
static struct netent_ext *
334
netent_from_packet(int reqtype, char *pkt, size_t pktlen)
335
{
336
	struct netent_ext	*n;
337
	struct asr_unpack	 p;
338
	struct asr_dns_header	 hdr;
339
	struct asr_dns_query	 q;
340
	struct asr_dns_rr	 rr;
341
342
	if ((n = netent_alloc(AF_INET)) == NULL)
343
		return (NULL);
344
345
	_asr_unpack_init(&p, pkt, pktlen);
346
	_asr_unpack_header(&p, &hdr);
347
	for (; hdr.qdcount; hdr.qdcount--)
348
		_asr_unpack_query(&p, &q);
349
	for (; hdr.ancount; hdr.ancount--) {
350
		_asr_unpack_rr(&p, &rr);
351
		if (rr.rr_class != C_IN)
352
			continue;
353
		switch (rr.rr_type) {
354
		case T_CNAME:
355
			if (reqtype == ASR_GETNETBYNAME) {
356
				if (netent_add_alias(n, rr.rr_dname, 1) == -1)
357
					goto fail;
358
			} else {
359
				if (netent_set_cname(n, rr.rr_dname, 1) == -1)
360
					goto fail;
361
			}
362
			break;
363
364
		case T_PTR:
365
			if (reqtype != ASR_GETNETBYADDR)
366
				continue;
367
			if (netent_set_cname(n, rr.rr.ptr.ptrname, 1) == -1)
368
				goto fail;
369
			/* XXX See if we need to have MULTI_PTRS_ARE_ALIASES */
370
			break;
371
372
		case T_A:
373
			if (n->n.n_addrtype != AF_INET)
374
				break;
375
			if (netent_set_cname(n, rr.rr_dname, 1) ==  -1)
376
				goto fail;
377
			n->n.n_net = ntohl(rr.rr.in_a.addr.s_addr);
378
			break;
379
		}
380
	}
381
382
	return (n);
383
fail:
384
	free(n);
385
	return (NULL);
386
}
387
388
static struct netent_ext *
389
netent_alloc(int family)
390
{
391
	struct netent_ext	*n;
392
	size_t			 alloc;
393
394
	alloc = sizeof(*n) + 1024;
395
	if ((n = calloc(1, alloc)) == NULL)
396
		return (NULL);
397
398
	n->n.n_addrtype = family;
399
	n->n.n_aliases = n->aliases;
400
	n->pos = (char *)(n) + sizeof(*n);
401
	n->end = n->pos + 1024;
402
403
	return (n);
404
}
405
406
static int
407
netent_set_cname(struct netent_ext *n, const char *name, int isdname)
408
{
409
	char	buf[MAXDNAME];
410
	size_t	l;
411
412
	if (n->n.n_name)
413
		return (-1);
414
415
	if (isdname) {
416
		_asr_strdname(name, buf, sizeof buf);
417
		buf[strlen(buf) - 1] = '\0';
418
		if (!res_hnok(buf))
419
			return (-1);
420
		name = buf;
421
	}
422
423
	l = strlen(name) + 1;
424
	if (n->pos + l >= n->end)
425
		return (-1);
426
427
	n->n.n_name = n->pos;
428
	memmove(n->pos, name, l);
429
	n->pos += l;
430
431
	return (0);
432
}
433
434
static int
435
netent_add_alias(struct netent_ext *n, const char *name, int isdname)
436
{
437
	char	buf[MAXDNAME];
438
	size_t	i, l;
439
440
	for (i = 0; i < MAXALIASES; i++)
441
		if (n->aliases[i] == NULL)
442
			break;
443
	if (i == MAXALIASES)
444
		return (-1);
445
446
	if (isdname) {
447
		_asr_strdname(name, buf, sizeof buf);
448
		buf[strlen(buf)-1] = '\0';
449
		if (!res_hnok(buf))
450
			return (-1);
451
		name = buf;
452
	}
453
454
	l = strlen(name) + 1;
455
	if (n->pos + l >= n->end)
456
		return (-1);
457
458
	n->aliases[i] = n->pos;
459
	memmove(n->pos, name, l);
460
	n->pos += l;
461
	return (0);
462
}