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

Line Branch Exec Source
1
/*	$OpenBSD: getnameinfo_async.c,v 1.13 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 <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 <errno.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <unistd.h>
31
32
#include "asr_private.h"
33
34
static int getnameinfo_async_run(struct asr_query *, struct asr_result *);
35
static int _servname(struct asr_query *);
36
static int _numerichost(struct asr_query *);
37
38
struct asr_query *
39
getnameinfo_async(const struct sockaddr *sa, socklen_t slen, char *host,
40
    size_t hostlen, char *serv, size_t servlen, int flags, void *asr)
41
{
42
	struct asr_ctx	 *ac;
43
	struct asr_query *as;
44
45
	ac = _asr_use_resolver(asr);
46
	if ((as = _asr_async_new(ac, ASR_GETNAMEINFO)) == NULL)
47
		goto abort; /* errno set */
48
	as->as_run = getnameinfo_async_run;
49
50
	if (sa->sa_family == AF_INET)
51
		memmove(&as->as.ni.sa.sa, sa, sizeof (as->as.ni.sa.sain));
52
	else if (sa->sa_family == AF_INET6)
53
		memmove(&as->as.ni.sa.sa, sa, sizeof (as->as.ni.sa.sain6));
54
55
	as->as.ni.sa.sa.sa_len = slen;
56
	as->as.ni.hostname = host;
57
	as->as.ni.hostnamelen = hostlen;
58
	as->as.ni.servname = serv;
59
	as->as.ni.servnamelen = servlen;
60
	as->as.ni.flags = flags;
61
62
	_asr_ctx_unref(ac);
63
	return (as);
64
65
    abort:
66
	if (as)
67
		_asr_async_free(as);
68
	_asr_ctx_unref(ac);
69
	return (NULL);
70
}
71
DEF_WEAK(getnameinfo_async);
72
73
static int
74
getnameinfo_async_run(struct asr_query *as, struct asr_result *ar)
75
{
76
	void		*addr;
77
	socklen_t	 addrlen;
78
	int		 r;
79
80
    next:
81
	switch (as->as_state) {
82
83
	case ASR_STATE_INIT:
84
85
		/* Make sure the parameters are all valid. */
86
87
		if (as->as.ni.sa.sa.sa_family != AF_INET &&
88
		    as->as.ni.sa.sa.sa_family != AF_INET6) {
89
			ar->ar_gai_errno = EAI_FAMILY;
90
			async_set_state(as, ASR_STATE_HALT);
91
			break;
92
		}
93
94
		if ((as->as.ni.sa.sa.sa_family == AF_INET &&
95
		    (as->as.ni.sa.sa.sa_len != sizeof (as->as.ni.sa.sain))) ||
96
		    (as->as.ni.sa.sa.sa_family == AF_INET6 &&
97
		    (as->as.ni.sa.sa.sa_len != sizeof (as->as.ni.sa.sain6)))) {
98
			ar->ar_gai_errno = EAI_FAIL;
99
			async_set_state(as, ASR_STATE_HALT);
100
			break;
101
		}
102
103
		/* Set the service name first, if needed. */
104
		if (_servname(as) == -1) {
105
			ar->ar_gai_errno = EAI_OVERFLOW;
106
			async_set_state(as, ASR_STATE_HALT);
107
			break;
108
		}
109
110
		if (as->as.ni.hostname == NULL || as->as.ni.hostnamelen == 0) {
111
			ar->ar_gai_errno = 0;
112
			async_set_state(as, ASR_STATE_HALT);
113
			break;
114
		}
115
116
		if (as->as.ni.flags & NI_NUMERICHOST) {
117
			if (_numerichost(as) == -1) {
118
				if (errno == ENOMEM)
119
					ar->ar_gai_errno = EAI_MEMORY;
120
				else if (errno == ENOSPC)
121
					ar->ar_gai_errno = EAI_OVERFLOW;
122
				else {
123
					ar->ar_errno = errno;
124
					ar->ar_gai_errno = EAI_SYSTEM;
125
				}
126
			} else
127
				ar->ar_gai_errno = 0;
128
			async_set_state(as, ASR_STATE_HALT);
129
			break;
130
		}
131
132
		if (as->as.ni.sa.sa.sa_family == AF_INET) {
133
			addrlen = sizeof(as->as.ni.sa.sain.sin_addr);
134
			addr = &as->as.ni.sa.sain.sin_addr;
135
		} else {
136
			addrlen = sizeof(as->as.ni.sa.sain6.sin6_addr);
137
			addr = &as->as.ni.sa.sain6.sin6_addr;
138
		}
139
140
		/*
141
		 * Create a subquery to lookup the address.
142
		 */
143
		as->as_subq = _gethostbyaddr_async_ctx(addr, addrlen,
144
		    as->as.ni.sa.sa.sa_family,
145
		    as->as_ctx);
146
		if (as->as_subq == NULL) {
147
			ar->ar_gai_errno = EAI_MEMORY;
148
			async_set_state(as, ASR_STATE_HALT);
149
			break;
150
		}
151
152
		async_set_state(as, ASR_STATE_SUBQUERY);
153
		break;
154
155
	case ASR_STATE_SUBQUERY:
156
157
		if ((r = asr_run(as->as_subq, ar)) == ASYNC_COND)
158
			return (ASYNC_COND);
159
160
		/*
161
		 * Request done.
162
		 */
163
		as->as_subq = NULL;
164
165
		if (ar->ar_hostent == NULL) {
166
			if (as->as.ni.flags & NI_NAMEREQD) {
167
				ar->ar_gai_errno = EAI_NONAME;
168
			} else if (_numerichost(as) == -1) {
169
				if (errno == ENOMEM)
170
					ar->ar_gai_errno = EAI_MEMORY;
171
				else if (errno == ENOSPC)
172
					ar->ar_gai_errno = EAI_OVERFLOW;
173
				else {
174
					ar->ar_errno = errno;
175
					ar->ar_gai_errno = EAI_SYSTEM;
176
				}
177
			} else
178
				ar->ar_gai_errno = 0;
179
		} else {
180
			if (strlcpy(as->as.ni.hostname,
181
			    ar->ar_hostent->h_name,
182
			    as->as.ni.hostnamelen) >= as->as.ni.hostnamelen)
183
				ar->ar_gai_errno = EAI_OVERFLOW;
184
			else
185
				ar->ar_gai_errno = 0;
186
			free(ar->ar_hostent);
187
		}
188
189
		async_set_state(as, ASR_STATE_HALT);
190
		break;
191
192
	case ASR_STATE_HALT:
193
		return (ASYNC_DONE);
194
195
	default:
196
		ar->ar_errno = EOPNOTSUPP;
197
		ar->ar_gai_errno = EAI_SYSTEM;
198
		async_set_state(as, ASR_STATE_HALT);
199
		break;
200
	}
201
	goto next;
202
}
203
204
205
/*
206
 * Set the service name on the result buffer is not NULL.
207
 * return (-1) if the buffer is too small.
208
 */
209
static int
210
_servname(struct asr_query *as)
211
{
212
	struct servent		 s;
213
	struct servent_data	 sd;
214
	int			 port, r;
215
	char			*buf = as->as.ni.servname;
216
	size_t			 buflen = as->as.ni.servnamelen;
217
218
	if (as->as.ni.servname == NULL || as->as.ni.servnamelen == 0)
219
		return (0);
220
221
	if (as->as.ni.sa.sa.sa_family == AF_INET)
222
		port = as->as.ni.sa.sain.sin_port;
223
	else
224
		port = as->as.ni.sa.sain6.sin6_port;
225
226
	if (!(as->as.ni.flags & NI_NUMERICSERV)) {
227
		memset(&sd, 0, sizeof (sd));
228
		if (getservbyport_r(port,
229
		    (as->as.ni.flags & NI_DGRAM) ? "udp" : "tcp",
230
		    &s, &sd) != -1) {
231
			r = strlcpy(buf, s.s_name, buflen) >= buflen;
232
			endservent_r(&sd);
233
			return (r ? -1 : 0);
234
		}
235
	}
236
237
	r = snprintf(buf, buflen, "%u", ntohs(port));
238
	if (r == -1 || r >= (int)buflen)
239
		return (-1);
240
241
	return (0);
242
}
243
244
/*
245
 * Write the numeric address
246
 */
247
static int
248
_numerichost(struct asr_query *as)
249
{
250
	unsigned int	ifidx;
251
	char		scope[IF_NAMESIZE + 1], *ifname;
252
	void		*addr;
253
	char		*buf = as->as.ni.hostname;
254
	size_t		 buflen = as->as.ni.hostnamelen;
255
256
	if (as->as.ni.sa.sa.sa_family == AF_INET)
257
		addr = &as->as.ni.sa.sain.sin_addr;
258
	else
259
		addr = &as->as.ni.sa.sain6.sin6_addr;
260
261
	if (inet_ntop(as->as.ni.sa.sa.sa_family, addr, buf, buflen) == NULL)
262
		return (-1); /* errno set */
263
264
	if (as->as.ni.sa.sa.sa_family == AF_INET6 &&
265
	    as->as.ni.sa.sain6.sin6_scope_id) {
266
267
		scope[0] = SCOPE_DELIMITER;
268
		scope[1] = '\0';
269
270
		ifidx = as->as.ni.sa.sain6.sin6_scope_id;
271
		ifname = NULL;
272
273
		if (IN6_IS_ADDR_LINKLOCAL(&as->as.ni.sa.sain6.sin6_addr) ||
274
		    IN6_IS_ADDR_MC_LINKLOCAL(&as->as.ni.sa.sain6.sin6_addr) ||
275
		    IN6_IS_ADDR_MC_INTFACELOCAL(&as->as.ni.sa.sain6.sin6_addr))
276
			ifname = if_indextoname(ifidx, scope + 1);
277
278
		if (ifname == NULL)
279
			snprintf(scope + 1, sizeof(scope) - 1, "%u", ifidx);
280
281
		strlcat(buf, scope, buflen);
282
	}
283
284
	return (0);
285
}