GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/asr/getrrsetbyname_async.c Lines: 0 219 0.0 %
Date: 2017-11-13 Branches: 0 132 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: getrrsetbyname_async.c,v 1.11 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 <sys/uio.h>
21
#include <netinet/in.h>
22
#include <arpa/nameser.h>
23
#include <netdb.h>
24
25
#include <asr.h>
26
#include <errno.h>
27
#include <resolv.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <unistd.h>
31
32
#include "asr_private.h"
33
34
static int getrrsetbyname_async_run(struct asr_query *, struct asr_result *);
35
static void get_response(struct asr_result *, const char *, int);
36
37
struct asr_query *
38
getrrsetbyname_async(const char *hostname, unsigned int rdclass,
39
    unsigned int rdtype, unsigned int flags, void *asr)
40
{
41
	struct asr_ctx	 *ac;
42
	struct asr_query *as;
43
44
	ac = _asr_use_resolver(asr);
45
	if ((as = _asr_async_new(ac, ASR_GETRRSETBYNAME)) == NULL)
46
		goto abort; /* errno set */
47
	as->as_run = getrrsetbyname_async_run;
48
49
	as->as.rrset.flags = flags;
50
	as->as.rrset.class = rdclass;
51
	as->as.rrset.type = rdtype;
52
	as->as.rrset.name = strdup(hostname);
53
	if (as->as.rrset.name == NULL)
54
		goto abort; /* errno set */
55
56
	_asr_ctx_unref(ac);
57
	return (as);
58
    abort:
59
	if (as)
60
		_asr_async_free(as);
61
62
	_asr_ctx_unref(ac);
63
	return (NULL);
64
}
65
DEF_WEAK(getrrsetbyname_async);
66
67
static int
68
getrrsetbyname_async_run(struct asr_query *as, struct asr_result *ar)
69
{
70
    next:
71
	switch (as->as_state) {
72
73
	case ASR_STATE_INIT:
74
75
		/* Check for invalid class and type. */
76
		if (as->as.rrset.class > 0xffff || as->as.rrset.type > 0xffff) {
77
			ar->ar_rrset_errno = ERRSET_INVAL;
78
			async_set_state(as, ASR_STATE_HALT);
79
			break;
80
		}
81
82
		/* Do not allow queries of class or type ANY. */
83
		if (as->as.rrset.class == 0xff || as->as.rrset.type == 0xff) {
84
			ar->ar_rrset_errno = ERRSET_INVAL;
85
			async_set_state(as, ASR_STATE_HALT);
86
			break;
87
		}
88
89
		/* Do not allow flags yet, unimplemented. */
90
		if (as->as.rrset.flags) {
91
			ar->ar_rrset_errno = ERRSET_INVAL;
92
			async_set_state(as, ASR_STATE_HALT);
93
			break;
94
		}
95
96
		/* Create a delegate the lookup to a subquery. */
97
		as->as_subq = _res_query_async_ctx(
98
		    as->as.rrset.name,
99
		    as->as.rrset.class,
100
		    as->as.rrset.type,
101
		    as->as_ctx);
102
		if (as->as_subq == NULL) {
103
			ar->ar_rrset_errno = ERRSET_FAIL;
104
			async_set_state(as, ASR_STATE_HALT);
105
			break;
106
		}
107
108
		async_set_state(as, ASR_STATE_SUBQUERY);
109
		break;
110
111
	case ASR_STATE_SUBQUERY:
112
113
		if ((asr_run(as->as_subq, ar)) == ASYNC_COND)
114
			return (ASYNC_COND);
115
116
		as->as_subq = NULL;
117
118
		/* No packet received.*/
119
		if (ar->ar_datalen == -1) {
120
			switch (ar->ar_h_errno) {
121
			case HOST_NOT_FOUND:
122
				ar->ar_rrset_errno = ERRSET_NONAME;
123
				break;
124
			case NO_DATA:
125
				ar->ar_rrset_errno = ERRSET_NODATA;
126
				break;
127
			default:
128
				ar->ar_rrset_errno = ERRSET_FAIL;
129
				break;
130
			}
131
			async_set_state(as, ASR_STATE_HALT);
132
			break;
133
		}
134
135
		/* Got a packet but no answer. */
136
		if (ar->ar_count == 0) {
137
			free(ar->ar_data);
138
			switch (ar->ar_rcode) {
139
			case NXDOMAIN:
140
				ar->ar_rrset_errno = ERRSET_NONAME;
141
				break;
142
			case NOERROR:
143
				ar->ar_rrset_errno = ERRSET_NODATA;
144
				break;
145
			default:
146
				ar->ar_rrset_errno = ERRSET_FAIL;
147
				break;
148
			}
149
			async_set_state(as, ASR_STATE_HALT);
150
			break;
151
		}
152
153
		get_response(ar, ar->ar_data, ar->ar_datalen);
154
		free(ar->ar_data);
155
		async_set_state(as, ASR_STATE_HALT);
156
		break;
157
158
	case ASR_STATE_HALT:
159
		if (ar->ar_rrset_errno)
160
			ar->ar_rrsetinfo = NULL;
161
		return (ASYNC_DONE);
162
163
	default:
164
		ar->ar_rrset_errno = ERRSET_FAIL;
165
		async_set_state(as, ASR_STATE_HALT);
166
		break;
167
	}
168
	goto next;
169
}
170
171
/* The rest of this file is taken from the orignal implementation. */
172
173
/* $OpenBSD: getrrsetbyname_async.c,v 1.11 2017/02/23 17:04:02 eric Exp $ */
174
175
/*
176
 * Copyright (c) 2001 Jakob Schlyter. All rights reserved.
177
 *
178
 * Redistribution and use in source and binary forms, with or without
179
 * modification, are permitted provided that the following conditions
180
 * are met:
181
 *
182
 * 1. Redistributions of source code must retain the above copyright
183
 *    notice, this list of conditions and the following disclaimer.
184
 *
185
 * 2. Redistributions in binary form must reproduce the above copyright
186
 *    notice, this list of conditions and the following disclaimer in the
187
 *    documentation and/or other materials provided with the distribution.
188
 *
189
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
190
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
191
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
192
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
193
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
194
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
195
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
196
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
197
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
198
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
199
 */
200
201
/*
202
 * Portions Copyright (c) 1999-2001 Internet Software Consortium.
203
 *
204
 * Permission to use, copy, modify, and distribute this software for any
205
 * purpose with or without fee is hereby granted, provided that the above
206
 * copyright notice and this permission notice appear in all copies.
207
 *
208
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
209
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
210
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
211
 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
212
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
213
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
214
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
215
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
216
 */
217
218
#define MAXPACKET 1024*64
219
220
struct dns_query {
221
	char			*name;
222
	u_int16_t		type;
223
	u_int16_t		class;
224
	struct dns_query	*next;
225
};
226
227
struct dns_rr {
228
	char			*name;
229
	u_int16_t		type;
230
	u_int16_t		class;
231
	u_int16_t		ttl;
232
	u_int16_t		size;
233
	void			*rdata;
234
	struct dns_rr		*next;
235
};
236
237
struct dns_response {
238
	HEADER			header;
239
	struct dns_query	*query;
240
	struct dns_rr		*answer;
241
	struct dns_rr		*authority;
242
	struct dns_rr		*additional;
243
};
244
245
static struct dns_response *parse_dns_response(const u_char *, int);
246
static struct dns_query *parse_dns_qsection(const u_char *, int,
247
    const u_char **, int);
248
static struct dns_rr *parse_dns_rrsection(const u_char *, int, const u_char **,
249
    int);
250
251
static void free_dns_query(struct dns_query *);
252
static void free_dns_rr(struct dns_rr *);
253
static void free_dns_response(struct dns_response *);
254
255
static int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t);
256
257
static void
258
get_response(struct asr_result *ar, const char *pkt, int pktlen)
259
{
260
	struct rrsetinfo *rrset = NULL;
261
	struct dns_response *response = NULL;
262
	struct dns_rr *rr;
263
	struct rdatainfo *rdata;
264
	unsigned int index_ans, index_sig;
265
266
	/* parse result */
267
	response = parse_dns_response(pkt, pktlen);
268
	if (response == NULL) {
269
		ar->ar_rrset_errno = ERRSET_FAIL;
270
		goto fail;
271
	}
272
273
	if (response->header.qdcount != 1) {
274
		ar->ar_rrset_errno = ERRSET_FAIL;
275
		goto fail;
276
	}
277
278
	/* initialize rrset */
279
	rrset = calloc(1, sizeof(struct rrsetinfo));
280
	if (rrset == NULL) {
281
		ar->ar_rrset_errno = ERRSET_NOMEMORY;
282
		goto fail;
283
	}
284
	rrset->rri_rdclass = response->query->class;
285
	rrset->rri_rdtype = response->query->type;
286
	rrset->rri_ttl = response->answer->ttl;
287
	rrset->rri_nrdatas = response->header.ancount;
288
289
	/* check for authenticated data */
290
	if (response->header.ad == 1)
291
		rrset->rri_flags |= RRSET_VALIDATED;
292
293
	/* copy name from answer section */
294
	rrset->rri_name = strdup(response->answer->name);
295
	if (rrset->rri_name == NULL) {
296
		ar->ar_rrset_errno = ERRSET_NOMEMORY;
297
		goto fail;
298
	}
299
300
	/* count answers */
301
	rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass,
302
	    rrset->rri_rdtype);
303
	rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass,
304
	    T_RRSIG);
305
306
	/* allocate memory for answers */
307
	rrset->rri_rdatas = calloc(rrset->rri_nrdatas,
308
	    sizeof(struct rdatainfo));
309
	if (rrset->rri_rdatas == NULL) {
310
		ar->ar_rrset_errno = ERRSET_NOMEMORY;
311
		goto fail;
312
	}
313
314
	/* allocate memory for signatures */
315
	rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo));
316
	if (rrset->rri_sigs == NULL) {
317
		ar->ar_rrset_errno = ERRSET_NOMEMORY;
318
		goto fail;
319
	}
320
321
	/* copy answers & signatures */
322
	for (rr = response->answer, index_ans = 0, index_sig = 0;
323
	    rr; rr = rr->next) {
324
325
		rdata = NULL;
326
327
		if (rr->class == rrset->rri_rdclass &&
328
		    rr->type  == rrset->rri_rdtype)
329
			rdata = &rrset->rri_rdatas[index_ans++];
330
331
		if (rr->class == rrset->rri_rdclass &&
332
		    rr->type  == T_RRSIG)
333
			rdata = &rrset->rri_sigs[index_sig++];
334
335
		if (rdata) {
336
			rdata->rdi_length = rr->size;
337
			rdata->rdi_data   = malloc(rr->size);
338
339
			if (rdata->rdi_data == NULL) {
340
				ar->ar_rrset_errno = ERRSET_NOMEMORY;
341
				goto fail;
342
			}
343
			memcpy(rdata->rdi_data, rr->rdata, rr->size);
344
		}
345
	}
346
	free_dns_response(response);
347
348
	ar->ar_rrsetinfo = rrset;
349
	ar->ar_rrset_errno = ERRSET_SUCCESS;
350
	return;
351
352
fail:
353
	if (rrset != NULL)
354
		freerrset(rrset);
355
	if (response != NULL)
356
		free_dns_response(response);
357
}
358
359
/*
360
 * DNS response parsing routines
361
 */
362
static struct dns_response *
363
parse_dns_response(const u_char *answer, int size)
364
{
365
	struct dns_response *resp;
366
	const u_char *cp;
367
368
	/* allocate memory for the response */
369
	resp = calloc(1, sizeof(*resp));
370
	if (resp == NULL)
371
		return (NULL);
372
373
	/* initialize current pointer */
374
	cp = answer;
375
376
	/* copy header */
377
	memcpy(&resp->header, cp, HFIXEDSZ);
378
	cp += HFIXEDSZ;
379
380
	/* fix header byte order */
381
	resp->header.qdcount = ntohs(resp->header.qdcount);
382
	resp->header.ancount = ntohs(resp->header.ancount);
383
	resp->header.nscount = ntohs(resp->header.nscount);
384
	resp->header.arcount = ntohs(resp->header.arcount);
385
386
	/* there must be at least one query */
387
	if (resp->header.qdcount < 1) {
388
		free_dns_response(resp);
389
		return (NULL);
390
	}
391
392
	/* parse query section */
393
	resp->query = parse_dns_qsection(answer, size, &cp,
394
	    resp->header.qdcount);
395
	if (resp->header.qdcount && resp->query == NULL) {
396
		free_dns_response(resp);
397
		return (NULL);
398
	}
399
400
	/* parse answer section */
401
	resp->answer = parse_dns_rrsection(answer, size, &cp,
402
	    resp->header.ancount);
403
	if (resp->header.ancount && resp->answer == NULL) {
404
		free_dns_response(resp);
405
		return (NULL);
406
	}
407
408
	/* parse authority section */
409
	resp->authority = parse_dns_rrsection(answer, size, &cp,
410
	    resp->header.nscount);
411
	if (resp->header.nscount && resp->authority == NULL) {
412
		free_dns_response(resp);
413
		return (NULL);
414
	}
415
416
	/* parse additional section */
417
	resp->additional = parse_dns_rrsection(answer, size, &cp,
418
	    resp->header.arcount);
419
	if (resp->header.arcount && resp->additional == NULL) {
420
		free_dns_response(resp);
421
		return (NULL);
422
	}
423
424
	return (resp);
425
}
426
427
static struct dns_query *
428
parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count)
429
{
430
	struct dns_query *head, *curr, *prev;
431
	int i, length;
432
	char name[MAXDNAME];
433
434
	for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
435
436
		/* allocate and initialize struct */
437
		curr = calloc(1, sizeof(struct dns_query));
438
		if (curr == NULL) {
439
			free_dns_query(head);
440
			return (NULL);
441
		}
442
		if (head == NULL)
443
			head = curr;
444
		if (prev != NULL)
445
			prev->next = curr;
446
447
		/* name */
448
		length = dn_expand(answer, answer + size, *cp, name,
449
		    sizeof(name));
450
		if (length < 0) {
451
			free_dns_query(head);
452
			return (NULL);
453
		}
454
		curr->name = strdup(name);
455
		if (curr->name == NULL) {
456
			free_dns_query(head);
457
			return (NULL);
458
		}
459
		*cp += length;
460
461
		/* type */
462
		curr->type = _getshort(*cp);
463
		*cp += INT16SZ;
464
465
		/* class */
466
		curr->class = _getshort(*cp);
467
		*cp += INT16SZ;
468
	}
469
470
	return (head);
471
}
472
473
static struct dns_rr *
474
parse_dns_rrsection(const u_char *answer, int size, const u_char **cp,
475
    int count)
476
{
477
	struct dns_rr *head, *curr, *prev;
478
	int i, length;
479
	char name[MAXDNAME];
480
481
	for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
482
483
		/* allocate and initialize struct */
484
		curr = calloc(1, sizeof(struct dns_rr));
485
		if (curr == NULL) {
486
			free_dns_rr(head);
487
			return (NULL);
488
		}
489
		if (head == NULL)
490
			head = curr;
491
		if (prev != NULL)
492
			prev->next = curr;
493
494
		/* name */
495
		length = dn_expand(answer, answer + size, *cp, name,
496
		    sizeof(name));
497
		if (length < 0) {
498
			free_dns_rr(head);
499
			return (NULL);
500
		}
501
		curr->name = strdup(name);
502
		if (curr->name == NULL) {
503
			free_dns_rr(head);
504
			return (NULL);
505
		}
506
		*cp += length;
507
508
		/* type */
509
		curr->type = _getshort(*cp);
510
		*cp += INT16SZ;
511
512
		/* class */
513
		curr->class = _getshort(*cp);
514
		*cp += INT16SZ;
515
516
		/* ttl */
517
		curr->ttl = _getlong(*cp);
518
		*cp += INT32SZ;
519
520
		/* rdata size */
521
		curr->size = _getshort(*cp);
522
		*cp += INT16SZ;
523
524
		/* rdata itself */
525
		curr->rdata = malloc(curr->size);
526
		if (curr->rdata == NULL) {
527
			free_dns_rr(head);
528
			return (NULL);
529
		}
530
		memcpy(curr->rdata, *cp, curr->size);
531
		*cp += curr->size;
532
	}
533
534
	return (head);
535
}
536
537
static void
538
free_dns_query(struct dns_query *p)
539
{
540
	if (p == NULL)
541
		return;
542
543
	if (p->name)
544
		free(p->name);
545
	free_dns_query(p->next);
546
	free(p);
547
}
548
549
static void
550
free_dns_rr(struct dns_rr *p)
551
{
552
	if (p == NULL)
553
		return;
554
555
	if (p->name)
556
		free(p->name);
557
	if (p->rdata)
558
		free(p->rdata);
559
	free_dns_rr(p->next);
560
	free(p);
561
}
562
563
static void
564
free_dns_response(struct dns_response *p)
565
{
566
	if (p == NULL)
567
		return;
568
569
	free_dns_query(p->query);
570
	free_dns_rr(p->answer);
571
	free_dns_rr(p->authority);
572
	free_dns_rr(p->additional);
573
	free(p);
574
}
575
576
static int
577
count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type)
578
{
579
	int n = 0;
580
581
	while (p) {
582
		if (p->class == class && p->type == type)
583
			n++;
584
		p = p->next;
585
	}
586
587
	return (n);
588
}