getaddrinfo.c revision 1.1 1 1.1 elric /* $NetBSD: getaddrinfo.c,v 1.1 2011/04/13 18:15:41 elric Exp $ */
2 1.1 elric
3 1.1 elric /*
4 1.1 elric * Copyright (c) 1999 - 2001 Kungliga Tekniska Hgskolan
5 1.1 elric * (Royal Institute of Technology, Stockholm, Sweden).
6 1.1 elric * All rights reserved.
7 1.1 elric *
8 1.1 elric * Redistribution and use in source and binary forms, with or without
9 1.1 elric * modification, are permitted provided that the following conditions
10 1.1 elric * are met:
11 1.1 elric *
12 1.1 elric * 1. Redistributions of source code must retain the above copyright
13 1.1 elric * notice, this list of conditions and the following disclaimer.
14 1.1 elric *
15 1.1 elric * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 elric * notice, this list of conditions and the following disclaimer in the
17 1.1 elric * documentation and/or other materials provided with the distribution.
18 1.1 elric *
19 1.1 elric * 3. Neither the name of the Institute nor the names of its contributors
20 1.1 elric * may be used to endorse or promote products derived from this software
21 1.1 elric * without specific prior written permission.
22 1.1 elric *
23 1.1 elric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 1.1 elric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 1.1 elric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 1.1 elric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 1.1 elric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 1.1 elric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 1.1 elric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 1.1 elric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 1.1 elric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 1.1 elric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 1.1 elric * SUCH DAMAGE.
34 1.1 elric */
35 1.1 elric
36 1.1 elric #include <config.h>
37 1.1 elric
38 1.1 elric #include <krb5/roken.h>
39 1.1 elric
40 1.1 elric /*
41 1.1 elric * uses hints->ai_socktype and hints->ai_protocol
42 1.1 elric */
43 1.1 elric
44 1.1 elric static int
45 1.1 elric get_port_protocol_socktype (const char *servname,
46 1.1 elric const struct addrinfo *hints,
47 1.1 elric int *port,
48 1.1 elric int *protocol,
49 1.1 elric int *socktype)
50 1.1 elric {
51 1.1 elric struct servent *se;
52 1.1 elric const char *proto_str = NULL;
53 1.1 elric
54 1.1 elric *socktype = 0;
55 1.1 elric
56 1.1 elric if (hints != NULL && hints->ai_protocol != 0) {
57 1.1 elric struct protoent *protoent = getprotobynumber (hints->ai_protocol);
58 1.1 elric
59 1.1 elric if (protoent == NULL)
60 1.1 elric return EAI_SOCKTYPE; /* XXX */
61 1.1 elric
62 1.1 elric proto_str = protoent->p_name;
63 1.1 elric *protocol = protoent->p_proto;
64 1.1 elric }
65 1.1 elric
66 1.1 elric if (hints != NULL)
67 1.1 elric *socktype = hints->ai_socktype;
68 1.1 elric
69 1.1 elric if (*socktype == SOCK_STREAM) {
70 1.1 elric se = getservbyname (servname, proto_str ? proto_str : "tcp");
71 1.1 elric if (proto_str == NULL)
72 1.1 elric *protocol = IPPROTO_TCP;
73 1.1 elric } else if (*socktype == SOCK_DGRAM) {
74 1.1 elric se = getservbyname (servname, proto_str ? proto_str : "udp");
75 1.1 elric if (proto_str == NULL)
76 1.1 elric *protocol = IPPROTO_UDP;
77 1.1 elric } else if (*socktype == 0) {
78 1.1 elric if (proto_str != NULL) {
79 1.1 elric se = getservbyname (servname, proto_str);
80 1.1 elric } else {
81 1.1 elric se = getservbyname (servname, "tcp");
82 1.1 elric *protocol = IPPROTO_TCP;
83 1.1 elric *socktype = SOCK_STREAM;
84 1.1 elric if (se == NULL) {
85 1.1 elric se = getservbyname (servname, "udp");
86 1.1 elric *protocol = IPPROTO_UDP;
87 1.1 elric *socktype = SOCK_DGRAM;
88 1.1 elric }
89 1.1 elric }
90 1.1 elric } else
91 1.1 elric return EAI_SOCKTYPE;
92 1.1 elric
93 1.1 elric if (se == NULL) {
94 1.1 elric char *endstr;
95 1.1 elric
96 1.1 elric *port = htons(strtol (servname, &endstr, 10));
97 1.1 elric if (servname == endstr)
98 1.1 elric return EAI_NONAME;
99 1.1 elric } else {
100 1.1 elric *port = se->s_port;
101 1.1 elric }
102 1.1 elric return 0;
103 1.1 elric }
104 1.1 elric
105 1.1 elric static int
106 1.1 elric add_one (int port, int protocol, int socktype,
107 1.1 elric struct addrinfo ***ptr,
108 1.1 elric int (*func)(struct addrinfo *, void *data, int port),
109 1.1 elric void *data,
110 1.1 elric char *canonname)
111 1.1 elric {
112 1.1 elric struct addrinfo *a;
113 1.1 elric int ret;
114 1.1 elric
115 1.1 elric a = malloc (sizeof (*a));
116 1.1 elric if (a == NULL)
117 1.1 elric return EAI_MEMORY;
118 1.1 elric memset (a, 0, sizeof(*a));
119 1.1 elric a->ai_flags = 0;
120 1.1 elric a->ai_next = NULL;
121 1.1 elric a->ai_protocol = protocol;
122 1.1 elric a->ai_socktype = socktype;
123 1.1 elric a->ai_canonname = canonname;
124 1.1 elric ret = (*func)(a, data, port);
125 1.1 elric if (ret) {
126 1.1 elric free (a);
127 1.1 elric return ret;
128 1.1 elric }
129 1.1 elric **ptr = a;
130 1.1 elric *ptr = &a->ai_next;
131 1.1 elric return 0;
132 1.1 elric }
133 1.1 elric
134 1.1 elric static int
135 1.1 elric const_v4 (struct addrinfo *a, void *data, int port)
136 1.1 elric {
137 1.1 elric struct sockaddr_in *sin4;
138 1.1 elric struct in_addr *addr = (struct in_addr *)data;
139 1.1 elric
140 1.1 elric a->ai_family = PF_INET;
141 1.1 elric a->ai_addrlen = sizeof(*sin4);
142 1.1 elric a->ai_addr = malloc (sizeof(*sin4));
143 1.1 elric if (a->ai_addr == NULL)
144 1.1 elric return EAI_MEMORY;
145 1.1 elric sin4 = (struct sockaddr_in *)a->ai_addr;
146 1.1 elric memset (sin4, 0, sizeof(*sin4));
147 1.1 elric sin4->sin_family = AF_INET;
148 1.1 elric sin4->sin_port = port;
149 1.1 elric sin4->sin_addr = *addr;
150 1.1 elric return 0;
151 1.1 elric }
152 1.1 elric
153 1.1 elric #ifdef HAVE_IPV6
154 1.1 elric static int
155 1.1 elric const_v6 (struct addrinfo *a, void *data, int port)
156 1.1 elric {
157 1.1 elric struct sockaddr_in6 *sin6;
158 1.1 elric struct in6_addr *addr = (struct in6_addr *)data;
159 1.1 elric
160 1.1 elric a->ai_family = PF_INET6;
161 1.1 elric a->ai_addrlen = sizeof(*sin6);
162 1.1 elric a->ai_addr = malloc (sizeof(*sin6));
163 1.1 elric if (a->ai_addr == NULL)
164 1.1 elric return EAI_MEMORY;
165 1.1 elric sin6 = (struct sockaddr_in6 *)a->ai_addr;
166 1.1 elric memset (sin6, 0, sizeof(*sin6));
167 1.1 elric sin6->sin6_family = AF_INET6;
168 1.1 elric sin6->sin6_port = port;
169 1.1 elric sin6->sin6_addr = *addr;
170 1.1 elric return 0;
171 1.1 elric }
172 1.1 elric #endif
173 1.1 elric
174 1.1 elric /* this is mostly a hack for some versions of AIX that has a prototype
175 1.1 elric for in6addr_loopback but no actual symbol in libc */
176 1.1 elric #if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT)
177 1.1 elric #define in6addr_loopback _roken_in6addr_loopback
178 1.1 elric struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
179 1.1 elric #endif
180 1.1 elric
181 1.1 elric static int
182 1.1 elric get_null (const struct addrinfo *hints,
183 1.1 elric int port, int protocol, int socktype,
184 1.1 elric struct addrinfo **res)
185 1.1 elric {
186 1.1 elric struct in_addr v4_addr;
187 1.1 elric #ifdef HAVE_IPV6
188 1.1 elric struct in6_addr v6_addr;
189 1.1 elric #endif
190 1.1 elric struct addrinfo *first = NULL;
191 1.1 elric struct addrinfo **current = &first;
192 1.1 elric int family = PF_UNSPEC;
193 1.1 elric int ret;
194 1.1 elric
195 1.1 elric if (hints != NULL)
196 1.1 elric family = hints->ai_family;
197 1.1 elric
198 1.1 elric if (hints && hints->ai_flags & AI_PASSIVE) {
199 1.1 elric v4_addr.s_addr = INADDR_ANY;
200 1.1 elric #ifdef HAVE_IPV6
201 1.1 elric v6_addr = in6addr_any;
202 1.1 elric #endif
203 1.1 elric } else {
204 1.1 elric v4_addr.s_addr = htonl(INADDR_LOOPBACK);
205 1.1 elric #ifdef HAVE_IPV6
206 1.1 elric v6_addr = in6addr_loopback;
207 1.1 elric #endif
208 1.1 elric }
209 1.1 elric
210 1.1 elric #ifdef HAVE_IPV6
211 1.1 elric if (family == PF_INET6 || family == PF_UNSPEC) {
212 1.1 elric ret = add_one (port, protocol, socktype,
213 1.1 elric ¤t, const_v6, &v6_addr, NULL);
214 1.1 elric }
215 1.1 elric #endif
216 1.1 elric if (family == PF_INET || family == PF_UNSPEC) {
217 1.1 elric ret = add_one (port, protocol, socktype,
218 1.1 elric ¤t, const_v4, &v4_addr, NULL);
219 1.1 elric }
220 1.1 elric *res = first;
221 1.1 elric return 0;
222 1.1 elric }
223 1.1 elric
224 1.1 elric static int
225 1.1 elric add_hostent (int port, int protocol, int socktype,
226 1.1 elric struct addrinfo ***current,
227 1.1 elric int (*func)(struct addrinfo *, void *data, int port),
228 1.1 elric struct hostent *he, int *flags)
229 1.1 elric {
230 1.1 elric int ret;
231 1.1 elric char *canonname = NULL;
232 1.1 elric char **h;
233 1.1 elric
234 1.1 elric if (*flags & AI_CANONNAME) {
235 1.1 elric struct hostent *he2 = NULL;
236 1.1 elric const char *tmp_canon;
237 1.1 elric
238 1.1 elric tmp_canon = hostent_find_fqdn (he);
239 1.1 elric if (strchr (tmp_canon, '.') == NULL) {
240 1.1 elric int error;
241 1.1 elric
242 1.1 elric he2 = getipnodebyaddr (he->h_addr_list[0], he->h_length,
243 1.1 elric he->h_addrtype, &error);
244 1.1 elric if (he2 != NULL) {
245 1.1 elric const char *tmp = hostent_find_fqdn (he2);
246 1.1 elric
247 1.1 elric if (strchr (tmp, '.') != NULL)
248 1.1 elric tmp_canon = tmp;
249 1.1 elric }
250 1.1 elric }
251 1.1 elric
252 1.1 elric canonname = strdup (tmp_canon);
253 1.1 elric if (he2 != NULL)
254 1.1 elric freehostent (he2);
255 1.1 elric if (canonname == NULL)
256 1.1 elric return EAI_MEMORY;
257 1.1 elric }
258 1.1 elric
259 1.1 elric for (h = he->h_addr_list; *h != NULL; ++h) {
260 1.1 elric ret = add_one (port, protocol, socktype,
261 1.1 elric current, func, *h, canonname);
262 1.1 elric if (ret)
263 1.1 elric return ret;
264 1.1 elric if (*flags & AI_CANONNAME) {
265 1.1 elric *flags &= ~AI_CANONNAME;
266 1.1 elric canonname = NULL;
267 1.1 elric }
268 1.1 elric }
269 1.1 elric return 0;
270 1.1 elric }
271 1.1 elric
272 1.1 elric static int
273 1.1 elric get_number (const char *nodename,
274 1.1 elric const struct addrinfo *hints,
275 1.1 elric int port, int protocol, int socktype,
276 1.1 elric struct addrinfo **res)
277 1.1 elric {
278 1.1 elric struct addrinfo *first = NULL;
279 1.1 elric struct addrinfo **current = &first;
280 1.1 elric int family = PF_UNSPEC;
281 1.1 elric int ret;
282 1.1 elric
283 1.1 elric if (hints != NULL) {
284 1.1 elric family = hints->ai_family;
285 1.1 elric }
286 1.1 elric
287 1.1 elric #ifdef HAVE_IPV6
288 1.1 elric if (family == PF_INET6 || family == PF_UNSPEC) {
289 1.1 elric struct in6_addr v6_addr;
290 1.1 elric
291 1.1 elric if (inet_pton (PF_INET6, nodename, &v6_addr) == 1) {
292 1.1 elric ret = add_one (port, protocol, socktype,
293 1.1 elric ¤t, const_v6, &v6_addr, NULL);
294 1.1 elric *res = first;
295 1.1 elric return ret;
296 1.1 elric }
297 1.1 elric }
298 1.1 elric #endif
299 1.1 elric if (family == PF_INET || family == PF_UNSPEC) {
300 1.1 elric struct in_addr v4_addr;
301 1.1 elric
302 1.1 elric if (inet_pton (PF_INET, nodename, &v4_addr) == 1) {
303 1.1 elric ret = add_one (port, protocol, socktype,
304 1.1 elric ¤t, const_v4, &v4_addr, NULL);
305 1.1 elric *res = first;
306 1.1 elric return ret;
307 1.1 elric }
308 1.1 elric }
309 1.1 elric return EAI_NONAME;
310 1.1 elric }
311 1.1 elric
312 1.1 elric static int
313 1.1 elric get_nodes (const char *nodename,
314 1.1 elric const struct addrinfo *hints,
315 1.1 elric int port, int protocol, int socktype,
316 1.1 elric struct addrinfo **res)
317 1.1 elric {
318 1.1 elric struct addrinfo *first = NULL;
319 1.1 elric struct addrinfo **current = &first;
320 1.1 elric int family = PF_UNSPEC;
321 1.1 elric int flags = 0;
322 1.1 elric int ret = EAI_NONAME;
323 1.1 elric int error;
324 1.1 elric
325 1.1 elric if (hints != NULL) {
326 1.1 elric family = hints->ai_family;
327 1.1 elric flags = hints->ai_flags;
328 1.1 elric }
329 1.1 elric
330 1.1 elric #ifdef HAVE_IPV6
331 1.1 elric if (family == PF_INET6 || family == PF_UNSPEC) {
332 1.1 elric struct hostent *he;
333 1.1 elric
334 1.1 elric he = getipnodebyname (nodename, PF_INET6, 0, &error);
335 1.1 elric
336 1.1 elric if (he != NULL) {
337 1.1 elric ret = add_hostent (port, protocol, socktype,
338 1.1 elric ¤t, const_v6, he, &flags);
339 1.1 elric freehostent (he);
340 1.1 elric }
341 1.1 elric }
342 1.1 elric #endif
343 1.1 elric if (family == PF_INET || family == PF_UNSPEC) {
344 1.1 elric struct hostent *he;
345 1.1 elric
346 1.1 elric he = getipnodebyname (nodename, PF_INET, 0, &error);
347 1.1 elric
348 1.1 elric if (he != NULL) {
349 1.1 elric ret = add_hostent (port, protocol, socktype,
350 1.1 elric ¤t, const_v4, he, &flags);
351 1.1 elric freehostent (he);
352 1.1 elric }
353 1.1 elric }
354 1.1 elric *res = first;
355 1.1 elric return ret;
356 1.1 elric }
357 1.1 elric
358 1.1 elric /*
359 1.1 elric * hints:
360 1.1 elric *
361 1.1 elric * struct addrinfo {
362 1.1 elric * int ai_flags;
363 1.1 elric * int ai_family;
364 1.1 elric * int ai_socktype;
365 1.1 elric * int ai_protocol;
366 1.1 elric * ...
367 1.1 elric * };
368 1.1 elric */
369 1.1 elric
370 1.1 elric ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
371 1.1 elric getaddrinfo(const char *nodename,
372 1.1 elric const char *servname,
373 1.1 elric const struct addrinfo *hints,
374 1.1 elric struct addrinfo **res)
375 1.1 elric {
376 1.1 elric int ret;
377 1.1 elric int port = 0;
378 1.1 elric int protocol = 0;
379 1.1 elric int socktype = 0;
380 1.1 elric
381 1.1 elric *res = NULL;
382 1.1 elric
383 1.1 elric if (servname == NULL && nodename == NULL)
384 1.1 elric return EAI_NONAME;
385 1.1 elric
386 1.1 elric if (hints != NULL
387 1.1 elric && hints->ai_family != PF_UNSPEC
388 1.1 elric && hints->ai_family != PF_INET
389 1.1 elric #ifdef HAVE_IPV6
390 1.1 elric && hints->ai_family != PF_INET6
391 1.1 elric #endif
392 1.1 elric )
393 1.1 elric return EAI_FAMILY;
394 1.1 elric
395 1.1 elric if (servname != NULL) {
396 1.1 elric ret = get_port_protocol_socktype (servname, hints,
397 1.1 elric &port, &protocol, &socktype);
398 1.1 elric if (ret)
399 1.1 elric return ret;
400 1.1 elric }
401 1.1 elric if (nodename != NULL) {
402 1.1 elric ret = get_number (nodename, hints, port, protocol, socktype, res);
403 1.1 elric if (ret) {
404 1.1 elric if(hints && hints->ai_flags & AI_NUMERICHOST)
405 1.1 elric ret = EAI_NONAME;
406 1.1 elric else
407 1.1 elric ret = get_nodes (nodename, hints, port, protocol, socktype,
408 1.1 elric res);
409 1.1 elric }
410 1.1 elric } else {
411 1.1 elric ret = get_null (hints, port, protocol, socktype, res);
412 1.1 elric }
413 1.1 elric if (ret)
414 1.1 elric freeaddrinfo (*res);
415 1.1 elric return ret;
416 1.1 elric }
417