GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/asr/getnameinfo.c Lines: 34 82 41.5 %
Date: 2017-11-07 Branches: 22 60 36.7 %

Line Branch Exec Source
1
/*	$OpenBSD: getnameinfo.c,v 1.8 2015/10/02 20:56:14 deraadt 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 <arpa/inet.h>
22
#include <netinet/in.h>
23
#include <netdb.h>
24
25
#include <asr.h>
26
#include <errno.h>
27
#include <resolv.h>
28
#include <string.h>
29
30
static size_t asr_print_addr(const struct sockaddr *, char *, size_t);
31
static size_t asr_print_port(const struct sockaddr *, const char *, char *, size_t);
32
33
#define SA_IN(sa) ((struct sockaddr_in*)(sa))
34
#define SA_IN6(sa) ((struct sockaddr_in6*)(sa))
35
36
/*
37
 * Print the textual representation (as given by inet_ntop(3)) of the address
38
 * set in "sa".
39
 *
40
 * Return the total length of the string it tried to create or 0 if an error
41
 * occured, in which case errno is set.  On success, the constructed string
42
 * is guaranteed to be NUL-terminated.  Overflow must be detected by checking
43
 * the returned size against buflen.
44
 *
45
 */
46
static size_t
47
asr_print_addr(const struct sockaddr *sa, char *buf, size_t buflen)
48
{
49
	unsigned int ifidx;
50
456
	char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
51
228
	char scope[IF_NAMESIZE + 1], *ifname;
52
	const void *addr;
53
	size_t s;
54
55
228
	switch(sa->sa_family) {
56
	case AF_INET:
57
		addr = &SA_IN(sa)->sin_addr;
58
		break;
59
	case AF_INET6:
60
228
		addr = &SA_IN6(sa)->sin6_addr;
61
228
		break;
62
	default:
63
		errno = EINVAL;
64
		return (0);
65
	}
66
67
228
	if (inet_ntop(sa->sa_family, addr, tmp, sizeof(tmp)) == NULL)
68
		return (0); /* errno set */
69
70
228
	s = strlcpy(buf, tmp, buflen);
71
72

456
	if (sa->sa_family == AF_INET6 && SA_IN6(sa)->sin6_scope_id) {
73
74
117
		scope[0] = SCOPE_DELIMITER;
75
117
		scope[1] = '\0';
76
77
117
		ifidx = SA_IN6(sa)->sin6_scope_id;
78
		ifname = NULL;
79
80

222
		if (IN6_IS_ADDR_LINKLOCAL(&(SA_IN6(sa)->sin6_addr)) ||
81

48
		    IN6_IS_ADDR_MC_LINKLOCAL(&(SA_IN6(sa)->sin6_addr)) ||
82
24
		    IN6_IS_ADDR_MC_INTFACELOCAL(&(SA_IN6(sa)->sin6_addr)))
83
117
			ifname = if_indextoname(ifidx, scope + 1);
84
85
117
		if (ifname == NULL)
86
			(void)snprintf(scope + 1, sizeof(scope) - 1, "%u", ifidx);
87
88
117
		if (s < buflen)
89
117
			(void)strlcat(buf, scope, buflen);
90
91
117
		s += strlen(scope);
92
117
	}
93
94
228
	return (s);
95
228
}
96
97
/*
98
 * Print the textual representation of the port set on "sa".
99
 *
100
 * If proto is not NULL, it is used as parameter to "getservbyport_r(3)" to
101
 * return a service name. If it's not set, or if no matching service is found,
102
 * it prints the portno.
103
 *
104
 * Return the total length of the string it tried to create or 0 if an error
105
 * occured, in which case errno is set.  On success, the constructed string
106
 * is guaranteed to be NUL-terminated.  Overflow must be detected by checking
107
 * the returned size against buflen.
108
 */
109
static size_t
110
asr_print_port(const struct sockaddr *sa, const char *proto, char *buf, size_t buflen)
111
{
112
	struct servent s;
113
	struct servent_data sd;
114
	int port, r, saved_errno;
115
	size_t n;
116
117
	switch(sa->sa_family) {
118
	case AF_INET:
119
		port = SA_IN(sa)->sin_port;
120
		break;
121
	case AF_INET6:
122
		port = SA_IN6(sa)->sin6_port;
123
		break;
124
	default:
125
		errno = EINVAL;
126
		return (0);
127
	}
128
129
	if (proto) {
130
		memset(&sd, 0, sizeof (sd));
131
		saved_errno = errno;
132
		if (getservbyport_r(port, proto, &s, &sd) != -1) {
133
			n = strlcpy(buf, s.s_name, buflen);
134
			endservent_r(&sd);
135
			return (n);
136
		}
137
		errno = saved_errno;
138
	}
139
140
	r = snprintf(buf, buflen, "%u", ntohs(port));
141
	if (r == -1) 	/* Actually, this can not happen */
142
		return (0);
143
144
	return (r);
145
}
146
147
int
148
getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host,
149
    size_t hostlen, char *serv, size_t servlen, int flags)
150
{
151
	struct asr_query *as;
152
456
	struct asr_result ar;
153
228
	int saved_errno = errno;
154
	const char *proto;
155
	size_t r;
156
157
	/*
158
	 * Take a shortcut if we don't care about hostname,
159
	 * or if NI_NUMERICHOST is set.
160
	 */
161

456
	if (host == NULL || hostlen == 0 ||
162
456
	    (host && hostlen && (flags & NI_NUMERICHOST))) {
163
228
		if (host) {
164
228
			r = asr_print_addr(sa, host, hostlen);
165
228
			if (r == 0)
166
				return (EAI_SYSTEM); /* errno set */
167
228
			if (r >= hostlen)
168
				return (EAI_OVERFLOW);
169
		}
170
171
228
		if (serv && servlen) {
172
			if (flags & NI_NUMERICSERV)
173
				proto = NULL;
174
			else
175
				proto = (flags & NI_DGRAM) ? "udp" : "tcp";
176
			r = asr_print_port(sa, proto, serv, servlen);
177
			if (r == 0)
178
				return (EAI_SYSTEM); /* errno set */
179
			if (r >= servlen)
180
				return (EAI_OVERFLOW);
181
		}
182
183
228
		errno = saved_errno;
184
228
		return (0);
185
	}
186
187
	res_init();
188
189
	as = getnameinfo_async(sa, salen, host, hostlen, serv, servlen, flags,
190
	    NULL);
191
	if (as == NULL) {
192
		if (errno == ENOMEM) {
193
			errno = saved_errno;
194
			return (EAI_MEMORY);
195
		}
196
		return (EAI_SYSTEM);
197
	}
198
199
	asr_run_sync(as, &ar);
200
	if (ar.ar_gai_errno == EAI_SYSTEM)
201
		errno = ar.ar_errno;
202
203
	return (ar.ar_gai_errno);
204
228
}
205
DEF_WEAK(getnameinfo);