1 |
/* |
2 |
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
3 |
* All rights reserved. |
4 |
* |
5 |
* Redistribution and use in source and binary forms, with or without |
6 |
* modification, are permitted provided that the following conditions |
7 |
* are met: |
8 |
* 1. Redistributions of source code must retain the above copyright |
9 |
* notice, this list of conditions and the following disclaimer. |
10 |
* 2. Redistributions in binary form must reproduce the above copyright |
11 |
* notice, this list of conditions and the following disclaimer in the |
12 |
* documentation and/or other materials provided with the distribution. |
13 |
* 3. Neither the name of the project nor the names of its contributors |
14 |
* may be used to endorse or promote products derived from this software |
15 |
* without specific prior written permission. |
16 |
* |
17 |
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
18 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
21 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
22 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
23 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
24 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
25 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
26 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
27 |
* SUCH DAMAGE. |
28 |
*/ |
29 |
|
30 |
#include "stdinc.h" |
31 |
|
32 |
#include <stdarg.h> |
33 |
#include "irc_getaddrinfo.h" |
34 |
#include "ircd_defs.h" |
35 |
|
36 |
/* $Id$ */ |
37 |
|
38 |
static const char in_addrany[] = { 0, 0, 0, 0 }; |
39 |
static const char in_loopback[] = { 127, 0, 0, 1 }; |
40 |
static const char in6_addrany[] = { |
41 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
42 |
}; |
43 |
static const char in6_loopback[] = { |
44 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 |
45 |
}; |
46 |
|
47 |
static const struct afd { |
48 |
int a_af; |
49 |
int a_addrlen; |
50 |
int a_socklen; |
51 |
int a_off; |
52 |
const char *a_addrany; |
53 |
const char *a_loopback; |
54 |
int a_scoped; |
55 |
} afdl [] = { |
56 |
#define N_INET6 0 |
57 |
#ifdef IPV6 |
58 |
{PF_INET6, sizeof(struct in6_addr), |
59 |
sizeof(struct sockaddr_in6), |
60 |
offsetof(struct sockaddr_in6, sin6_addr), |
61 |
in6_addrany, in6_loopback, 1}, |
62 |
#endif |
63 |
#define N_INET 1 |
64 |
{PF_INET, sizeof(struct in_addr), |
65 |
sizeof(struct sockaddr_in), |
66 |
offsetof(struct sockaddr_in, sin_addr), |
67 |
in_addrany, in_loopback, 0}, |
68 |
{0, 0, 0, 0, NULL, NULL, 0}, |
69 |
}; |
70 |
|
71 |
struct explore { |
72 |
int e_af; |
73 |
int e_socktype; |
74 |
int e_protocol; |
75 |
const char *e_protostr; |
76 |
int e_wild; |
77 |
#define WILD_AF(ex) ((ex)->e_wild & 0x01) |
78 |
#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) |
79 |
#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) |
80 |
}; |
81 |
|
82 |
static const struct explore explore[] = { |
83 |
#ifdef IPV6 |
84 |
{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, |
85 |
{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, |
86 |
{ PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, |
87 |
#endif |
88 |
{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, |
89 |
{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, |
90 |
{ PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, |
91 |
{ PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, |
92 |
{ PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, |
93 |
{ PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, |
94 |
{ -1, 0, 0, NULL, 0 }, |
95 |
}; |
96 |
|
97 |
#define PTON_MAX 16 |
98 |
|
99 |
static int str_isnumber(const char *); |
100 |
static int explore_null(const struct addrinfo *, |
101 |
const char *, struct addrinfo **); |
102 |
static int explore_numeric(const struct addrinfo *, const char *, |
103 |
const char *, struct addrinfo **); |
104 |
static struct addrinfo *get_ai(const struct addrinfo *, |
105 |
const struct afd *, const char *); |
106 |
static int get_portmatch(const struct addrinfo *, const char *); |
107 |
static int get_port(struct addrinfo *, const char *, int); |
108 |
static const struct afd *find_afd(int); |
109 |
#if 0 |
110 |
/* We will need this should we ever want gai_strerror() */ |
111 |
static char *ai_errlist[] = { |
112 |
"Success", |
113 |
"Address family for hostname not supported", /* EAI_ADDRFAMILY */ |
114 |
"Temporary failure in name resolution", /* EAI_AGAIN */ |
115 |
"Invalid value for ai_flags", /* EAI_BADFLAGS */ |
116 |
"Non-recoverable failure in name resolution", /* EAI_FAIL */ |
117 |
"ai_family not supported", /* EAI_FAMILY */ |
118 |
"Memory allocation failure", /* EAI_MEMORY */ |
119 |
"No address associated with hostname", /* EAI_NODATA */ |
120 |
"hostname nor servname provided, or not known", /* EAI_NONAME */ |
121 |
"servname not supported for ai_socktype", /* EAI_SERVICE */ |
122 |
"ai_socktype not supported", /* EAI_SOCKTYPE */ |
123 |
"System error returned in errno", /* EAI_SYSTEM */ |
124 |
"Invalid value for hints", /* EAI_BADHINTS */ |
125 |
"Resolved protocol is unknown", /* EAI_PROTOCOL */ |
126 |
"Unknown error", /* EAI_MAX */ |
127 |
}; |
128 |
#endif |
129 |
/* XXX macros that make external reference is BAD. */ |
130 |
|
131 |
#define GET_AI(ai, afd, addr) \ |
132 |
do { \ |
133 |
/* external reference: pai, error, and label free */ \ |
134 |
(ai) = get_ai(pai, (afd), (addr)); \ |
135 |
if ((ai) == NULL) { \ |
136 |
error = EAI_MEMORY; \ |
137 |
goto free; \ |
138 |
} \ |
139 |
} while (/*CONSTCOND*/0) |
140 |
|
141 |
#define GET_PORT(ai, serv) \ |
142 |
do { \ |
143 |
/* external reference: error and label free */ \ |
144 |
error = get_port((ai), (serv), 0); \ |
145 |
if (error != 0) \ |
146 |
goto free; \ |
147 |
} while (/*CONSTCOND*/0) |
148 |
|
149 |
#define ERR(err) \ |
150 |
do { \ |
151 |
/* external reference: error, and label bad */ \ |
152 |
error = (err); \ |
153 |
goto bad; \ |
154 |
/*NOTREACHED*/ \ |
155 |
} while (/*CONSTCOND*/0) |
156 |
|
157 |
#define MATCH_FAMILY(x, y, w) \ |
158 |
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) |
159 |
#define MATCH(x, y, w) \ |
160 |
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) |
161 |
|
162 |
#if 0 |
163 |
/* We will need this should we ever want gai_strerror() */ |
164 |
char * |
165 |
irc_gai_strerror(int ecode) |
166 |
{ |
167 |
if (ecode < 0 || ecode > EAI_MAX) |
168 |
ecode = EAI_MAX; |
169 |
return ai_errlist[ecode]; |
170 |
} |
171 |
#endif |
172 |
|
173 |
void |
174 |
irc_freeaddrinfo(struct addrinfo *ai) |
175 |
{ |
176 |
struct addrinfo *next; |
177 |
|
178 |
do { |
179 |
next = ai->ai_next; |
180 |
if (ai->ai_canonname) |
181 |
free(ai->ai_canonname); |
182 |
/* no need to free(ai->ai_addr) */ |
183 |
free(ai); |
184 |
ai = next; |
185 |
} while (ai); |
186 |
} |
187 |
|
188 |
static int |
189 |
str_isnumber(const char *p) |
190 |
{ |
191 |
char *ep; |
192 |
|
193 |
if (*p == '\0') |
194 |
return NO; |
195 |
ep = NULL; |
196 |
errno = 0; |
197 |
(void)strtoul(p, &ep, 10); |
198 |
if (errno == 0 && ep && *ep == '\0') |
199 |
return YES; |
200 |
else |
201 |
return NO; |
202 |
} |
203 |
|
204 |
int |
205 |
irc_getaddrinfo(const char *hostname, const char *servname, |
206 |
const struct addrinfo *hints, struct addrinfo **res) |
207 |
{ |
208 |
struct addrinfo sentinel; |
209 |
struct addrinfo *cur; |
210 |
int error = 0; |
211 |
struct addrinfo ai; |
212 |
struct addrinfo ai0; |
213 |
struct addrinfo *pai; |
214 |
const struct explore *ex; |
215 |
|
216 |
memset(&sentinel, 0, sizeof(sentinel)); |
217 |
cur = &sentinel; |
218 |
pai = &ai; |
219 |
pai->ai_flags = 0; |
220 |
pai->ai_family = PF_UNSPEC; |
221 |
pai->ai_socktype = ANY; |
222 |
pai->ai_protocol = ANY; |
223 |
pai->ai_addrlen = 0; |
224 |
pai->ai_canonname = NULL; |
225 |
pai->ai_addr = NULL; |
226 |
pai->ai_next = NULL; |
227 |
|
228 |
if (hostname == NULL && servname == NULL) |
229 |
return EAI_NONAME; |
230 |
if (hints) { |
231 |
/* error check for hints */ |
232 |
if (hints->ai_addrlen || hints->ai_canonname || |
233 |
hints->ai_addr || hints->ai_next) |
234 |
ERR(EAI_BADHINTS); /* xxx */ |
235 |
if (hints->ai_flags & ~AI_MASK) |
236 |
ERR(EAI_BADFLAGS); |
237 |
switch (hints->ai_family) { |
238 |
case PF_UNSPEC: |
239 |
case PF_INET: |
240 |
#ifdef IPV6 |
241 |
case PF_INET6: |
242 |
#endif |
243 |
break; |
244 |
default: |
245 |
ERR(EAI_FAMILY); |
246 |
} |
247 |
memcpy(pai, hints, sizeof(*pai)); |
248 |
|
249 |
/* |
250 |
* if both socktype/protocol are specified, check if they |
251 |
* are meaningful combination. |
252 |
*/ |
253 |
if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { |
254 |
for (ex = explore; ex->e_af >= 0; ex++) { |
255 |
if (pai->ai_family != ex->e_af) |
256 |
continue; |
257 |
if (ex->e_socktype == ANY) |
258 |
continue; |
259 |
if (ex->e_protocol == ANY) |
260 |
continue; |
261 |
if (pai->ai_socktype == ex->e_socktype && |
262 |
pai->ai_protocol != ex->e_protocol) { |
263 |
ERR(EAI_BADHINTS); |
264 |
} |
265 |
} |
266 |
} |
267 |
} |
268 |
|
269 |
/* |
270 |
* check for special cases. (1) numeric servname is disallowed if |
271 |
* socktype/protocol are left unspecified. (2) servname is disallowed |
272 |
* for raw and other inet{,6} sockets. |
273 |
*/ |
274 |
if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) |
275 |
#ifdef IPV6 |
276 |
|| MATCH_FAMILY(pai->ai_family, PF_INET6, 1) |
277 |
#endif |
278 |
) { |
279 |
ai0 = *pai; /* backup *pai */ |
280 |
|
281 |
if (pai->ai_family == PF_UNSPEC) { |
282 |
#ifdef IPV6 |
283 |
pai->ai_family = PF_INET6; |
284 |
#else |
285 |
pai->ai_family = PF_INET; |
286 |
#endif |
287 |
} |
288 |
error = get_portmatch(pai, servname); |
289 |
if (error) |
290 |
ERR(error); |
291 |
|
292 |
*pai = ai0; |
293 |
} |
294 |
|
295 |
ai0 = *pai; |
296 |
|
297 |
/* NULL hostname, or numeric hostname */ |
298 |
for (ex = explore; ex->e_af >= 0; ex++) { |
299 |
*pai = ai0; |
300 |
|
301 |
/* PF_UNSPEC entries are prepared for DNS queries only */ |
302 |
if (ex->e_af == PF_UNSPEC) |
303 |
continue; |
304 |
|
305 |
if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) |
306 |
continue; |
307 |
if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) |
308 |
continue; |
309 |
if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) |
310 |
continue; |
311 |
|
312 |
if (pai->ai_family == PF_UNSPEC) |
313 |
pai->ai_family = ex->e_af; |
314 |
if (pai->ai_socktype == ANY && ex->e_socktype != ANY) |
315 |
pai->ai_socktype = ex->e_socktype; |
316 |
if (pai->ai_protocol == ANY && ex->e_protocol != ANY) |
317 |
pai->ai_protocol = ex->e_protocol; |
318 |
|
319 |
if (hostname == NULL) |
320 |
error = explore_null(pai, servname, &cur->ai_next); |
321 |
else |
322 |
error = explore_numeric(pai, hostname, servname, &cur->ai_next); |
323 |
|
324 |
if (error) |
325 |
goto free; |
326 |
|
327 |
while (cur && cur->ai_next) |
328 |
cur = cur->ai_next; |
329 |
} |
330 |
|
331 |
/* |
332 |
* XXX |
333 |
* If numreic representation of AF1 can be interpreted as FQDN |
334 |
* representation of AF2, we need to think again about the code below. |
335 |
*/ |
336 |
if (sentinel.ai_next) |
337 |
goto good; |
338 |
|
339 |
if (pai->ai_flags & AI_NUMERICHOST) |
340 |
ERR(EAI_NONAME); |
341 |
if (hostname == NULL) |
342 |
ERR(EAI_NODATA); |
343 |
|
344 |
/* XXX */ |
345 |
if (sentinel.ai_next) |
346 |
error = 0; |
347 |
|
348 |
if (error) |
349 |
goto free; |
350 |
if (error == 0) { |
351 |
if (sentinel.ai_next) { |
352 |
good: |
353 |
*res = sentinel.ai_next; |
354 |
return SUCCESS; |
355 |
} else |
356 |
error = EAI_FAIL; |
357 |
} |
358 |
free: |
359 |
bad: |
360 |
if (sentinel.ai_next) |
361 |
irc_freeaddrinfo(sentinel.ai_next); |
362 |
*res = NULL; |
363 |
return error; |
364 |
} |
365 |
|
366 |
/* |
367 |
* hostname == NULL. |
368 |
* passive socket -> anyaddr (0.0.0.0 or ::) |
369 |
* non-passive socket -> localhost (127.0.0.1 or ::1) |
370 |
*/ |
371 |
static int |
372 |
explore_null(const struct addrinfo *pai, const char *servname, struct addrinfo **res) |
373 |
{ |
374 |
int s; |
375 |
const struct afd *afd; |
376 |
struct addrinfo *cur; |
377 |
struct addrinfo sentinel; |
378 |
int error; |
379 |
|
380 |
*res = NULL; |
381 |
sentinel.ai_next = NULL; |
382 |
cur = &sentinel; |
383 |
|
384 |
/* |
385 |
* filter out AFs that are not supported by the kernel |
386 |
* XXX errno? |
387 |
*/ |
388 |
s = socket(pai->ai_family, SOCK_DGRAM, 0); |
389 |
if (s < 0) { |
390 |
#ifdef _WIN32 |
391 |
errno = WSAGetLastError(); |
392 |
#endif |
393 |
if (errno != EMFILE) |
394 |
return 0; |
395 |
} else |
396 |
#ifdef _WIN32 |
397 |
closesocket(s); |
398 |
#else |
399 |
close(s); |
400 |
#endif |
401 |
|
402 |
/* |
403 |
* if the servname does not match socktype/protocol, ignore it. |
404 |
*/ |
405 |
if (get_portmatch(pai, servname) != 0) |
406 |
return 0; |
407 |
|
408 |
afd = find_afd(pai->ai_family); |
409 |
if (afd == NULL) |
410 |
return 0; |
411 |
|
412 |
if (pai->ai_flags & AI_PASSIVE) { |
413 |
GET_AI(cur->ai_next, afd, afd->a_addrany); |
414 |
GET_PORT(cur->ai_next, servname); |
415 |
} else { |
416 |
GET_AI(cur->ai_next, afd, afd->a_loopback); |
417 |
GET_PORT(cur->ai_next, servname); |
418 |
} |
419 |
cur = cur->ai_next; |
420 |
|
421 |
*res = sentinel.ai_next; |
422 |
return 0; |
423 |
|
424 |
free: |
425 |
if (sentinel.ai_next) |
426 |
irc_freeaddrinfo(sentinel.ai_next); |
427 |
return error; |
428 |
} |
429 |
|
430 |
/* |
431 |
* numeric hostname |
432 |
*/ |
433 |
static int |
434 |
explore_numeric(const struct addrinfo *pai, const char *hostname, |
435 |
const char *servname, struct addrinfo **res) |
436 |
{ |
437 |
const struct afd *afd; |
438 |
struct addrinfo *cur; |
439 |
struct addrinfo sentinel; |
440 |
int error; |
441 |
char pton[PTON_MAX]; |
442 |
|
443 |
*res = NULL; |
444 |
sentinel.ai_next = NULL; |
445 |
cur = &sentinel; |
446 |
|
447 |
/* |
448 |
* if the servname does not match socktype/protocol, ignore it. |
449 |
*/ |
450 |
if (get_portmatch(pai, servname) != 0) |
451 |
return 0; |
452 |
|
453 |
afd = find_afd(pai->ai_family); |
454 |
if (afd == NULL) |
455 |
return 0; |
456 |
|
457 |
switch (afd->a_af) { |
458 |
#if 1 /*X/Open spec*/ |
459 |
case AF_INET: |
460 |
if (inet_aton(hostname, (struct in_addr *)pton) == 1) { |
461 |
if (pai->ai_family == afd->a_af || |
462 |
pai->ai_family == PF_UNSPEC /*?*/) { |
463 |
GET_AI(cur->ai_next, afd, pton); |
464 |
GET_PORT(cur->ai_next, servname); |
465 |
while (cur && cur->ai_next) |
466 |
cur = cur->ai_next; |
467 |
} else |
468 |
ERR(EAI_FAMILY); /*xxx*/ |
469 |
} |
470 |
break; |
471 |
#endif |
472 |
default: |
473 |
if (inet_pton(afd->a_af, hostname, pton) == 1) { |
474 |
if (pai->ai_family == afd->a_af || |
475 |
pai->ai_family == PF_UNSPEC /*?*/) { |
476 |
GET_AI(cur->ai_next, afd, pton); |
477 |
GET_PORT(cur->ai_next, servname); |
478 |
while (cur && cur->ai_next) |
479 |
cur = cur->ai_next; |
480 |
} else |
481 |
ERR(EAI_FAMILY); /* XXX */ |
482 |
} |
483 |
break; |
484 |
} |
485 |
|
486 |
*res = sentinel.ai_next; |
487 |
return 0; |
488 |
|
489 |
free: |
490 |
bad: |
491 |
if (sentinel.ai_next) |
492 |
irc_freeaddrinfo(sentinel.ai_next); |
493 |
return error; |
494 |
} |
495 |
|
496 |
static struct addrinfo * |
497 |
get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) |
498 |
{ |
499 |
char *p; |
500 |
struct addrinfo *ai; |
501 |
|
502 |
ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) |
503 |
+ (afd->a_socklen)); |
504 |
if (ai == NULL) |
505 |
return NULL; |
506 |
|
507 |
memcpy(ai, pai, sizeof(struct addrinfo)); |
508 |
ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); |
509 |
memset(ai->ai_addr, 0, (size_t)afd->a_socklen); |
510 |
ai->ai_addrlen = afd->a_socklen; |
511 |
ai->ai_addr->sa_family = ai->ai_family = afd->a_af; |
512 |
p = (char *)(void *)(ai->ai_addr); |
513 |
memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); |
514 |
return ai; |
515 |
} |
516 |
|
517 |
static int |
518 |
get_portmatch(const struct addrinfo *ai, const char *servname) |
519 |
{ |
520 |
/* get_port does not touch first argument. when matchonly == 1. */ |
521 |
/* LINTED const cast */ |
522 |
return(get_port((struct addrinfo *)ai, servname, 1)); |
523 |
} |
524 |
|
525 |
static int |
526 |
get_port(struct addrinfo *ai, const char *servname, int matchonly) |
527 |
{ |
528 |
const char *proto; |
529 |
struct servent *sp; |
530 |
int port; |
531 |
int allownumeric; |
532 |
|
533 |
if (servname == NULL) |
534 |
return 0; |
535 |
switch (ai->ai_family) { |
536 |
case AF_INET: |
537 |
#ifdef AF_INET6 |
538 |
case AF_INET6: |
539 |
#endif |
540 |
break; |
541 |
default: |
542 |
return 0; |
543 |
} |
544 |
|
545 |
switch (ai->ai_socktype) { |
546 |
case SOCK_RAW: |
547 |
return EAI_SERVICE; |
548 |
case SOCK_DGRAM: |
549 |
case SOCK_STREAM: |
550 |
allownumeric = 1; |
551 |
break; |
552 |
case ANY: |
553 |
allownumeric = 0; |
554 |
break; |
555 |
default: |
556 |
return EAI_SOCKTYPE; |
557 |
} |
558 |
|
559 |
if (str_isnumber(servname)) { |
560 |
if (!allownumeric) |
561 |
return EAI_SERVICE; |
562 |
port = atoi(servname); |
563 |
if (port < 0 || port > 65535) |
564 |
return EAI_SERVICE; |
565 |
port = htons(port); |
566 |
} else { |
567 |
switch (ai->ai_socktype) { |
568 |
case SOCK_DGRAM: |
569 |
proto = "udp"; |
570 |
break; |
571 |
case SOCK_STREAM: |
572 |
proto = "tcp"; |
573 |
break; |
574 |
default: |
575 |
proto = NULL; |
576 |
break; |
577 |
} |
578 |
|
579 |
if ((sp = getservbyname(servname, proto)) == NULL) |
580 |
return EAI_SERVICE; |
581 |
port = sp->s_port; |
582 |
} |
583 |
|
584 |
if (!matchonly) { |
585 |
switch (ai->ai_family) { |
586 |
case AF_INET: |
587 |
((struct sockaddr_in *)(void *) |
588 |
ai->ai_addr)->sin_port = port; |
589 |
break; |
590 |
#ifdef IPV6 |
591 |
case AF_INET6: |
592 |
((struct sockaddr_in6 *)(void *) |
593 |
ai->ai_addr)->sin6_port = port; |
594 |
break; |
595 |
#endif |
596 |
} |
597 |
} |
598 |
|
599 |
return 0; |
600 |
} |
601 |
|
602 |
static const struct afd * |
603 |
find_afd(int af) |
604 |
{ |
605 |
const struct afd *afd; |
606 |
|
607 |
if (af == PF_UNSPEC) |
608 |
return(NULL); |
609 |
|
610 |
for (afd = afdl; afd->a_af; afd++) |
611 |
{ |
612 |
if (afd->a_af == af) |
613 |
return(afd); |
614 |
} |
615 |
|
616 |
return(NULL); |
617 |
} |