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 "config.h"
31
32 #include <sofia-sip/su.h>
33 #include <sofia-sip/su_addrinfo.h>
34
35 #ifndef IN_LOOPBACKNET
36 #define IN_LOOPBACKNET 127
37 #endif
38
39 #ifndef IN_EXPERIMENTAL
40 #define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000)
41 #endif
42
43 #if !HAVE_GETADDRINFO
44
45 #include <string.h>
46 #include <stddef.h>
47 #include <stdlib.h>
48 #include <ctype.h>
49
50 #ifndef EAI_NODATA
51 #define EAI_NODATA 7
52 #endif
53
54 /*
55 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
56 *
57 * Issues to be discussed:
58 * - Thread safe-ness must be checked.
59 * - Return values. There are nonstandard return values defined and used
60 * in the source code. This is because RFC2133 is silent about which error
61 * code must be returned for which situation.
62 * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
63 */
64
65 #if defined(__KAME__) && defined(INET6)
66 # define FAITH
67 #endif
68
69 #define SUCCESS 0
70 #define GAI_ANY 0
71 #define YES 1
72 #define NO 0
73
74 #undef SU_HAVE_IN6
75
76 #ifdef FAITH
77 static int translate = NO;
78 static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT;
79 #endif
80
81 static const char in_addrany[] = { 0, 0, 0, 0 };
82 static const char in6_addrany[] = {
83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
84
85 };
86 static const char in_loopback[] = { 127, 0, 0, 1 };
87 static const char in6_loopback[] = {
88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
89 };
90
91 struct sockinet {
92 u_char si_len;
93 u_char si_family;
94 u_short si_port;
95 };
96
97 static struct gai_afd {
98 int a_af;
99 int a_addrlen;
100 int a_socklen;
101 int a_off;
102 const char *a_addrany;
103 const char *a_loopback;
104 } gai_afdl [] = {
105 #if SU_HAVE_IN6
106 #define N_INET6 0
107 {PF_INET6, sizeof(struct in6_addr),
108 sizeof(struct sockaddr_in6),
109 offsetof(struct sockaddr_in6, sin6_addr),
110 in6_addrany, in6_loopback},
111 #define N_INET 1
112 #else
113 #define N_INET 0
114 #endif
115 {PF_INET, sizeof(struct in_addr),
116 sizeof(struct sockaddr_in),
117 offsetof(struct sockaddr_in, sin_addr),
118 in_addrany, in_loopback},
119 {0, 0, 0, 0, NULL, NULL},
120 };
121
122 #if SU_HAVE_IN6
123 #define PTON_MAX 16
124 #else
125 #define PTON_MAX 4
126 #endif
127
128 #if SU_HAVE_IN6 && !defined(s6_addr8)
129 # define s6_addr8 s6_addr
130 #endif
131
132 #if !SU_HAVE_IN6
133 #if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
134 #else
135 extern int h_errno;
136 #endif
137 #endif
138
139 static int get_name(const char *, struct gai_afd *,
140 struct addrinfo **, char *, struct addrinfo *,
141 int);
142 static int get_addr(const char *, int, struct addrinfo **,
143 struct addrinfo *, int);
144 static int str_isnumber(const char *);
145
146 #define GET_CANONNAME(ai, str) \
147 if (pai->ai_flags & AI_CANONNAME) {\
148 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
149 strcpy((ai)->ai_canonname, (str));\
150 } else {\
151 error = EAI_MEMORY;\
152 goto free;\
153 }\
154 }
155
156 #if SU_HAVE_SOCKADDR_SA_LEN
157 #define GET_AI(ai, gai_afd, addr, port) {\
158 char *p;\
159 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
160 ((gai_afd)->a_socklen)))\
161 == NULL) goto free;\
162 memcpy(ai, pai, sizeof(struct addrinfo));\
163 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
164 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
165 (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\
166 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
167 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
168 p = (char *)((ai)->ai_addr);\
169 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
170 }
171 #else
172 #define GET_AI(ai, gai_afd, addr, port) {\
173 char *p;\
174 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
175 ((gai_afd)->a_socklen)))\
176 == NULL) goto free;\
177 memcpy(ai, pai, sizeof(struct addrinfo));\
178 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
179 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
180 (ai)->ai_addrlen = (gai_afd)->a_socklen; \
181 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
182 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
183 p = (char *)((ai)->ai_addr);\
184 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
185 }
186 #endif
187
188 #define ERR(err) { error = (err); goto bad; }
189
190 static int
str_isnumber(p)191 str_isnumber(p)
192 const char *p;
193 {
194 char *q = (char *)p;
195 while (*q) {
196 if (! isdigit(*q))
197 return NO;
198 q++;
199 }
200 return YES;
201 }
202
203 static
204 int
getaddrinfo(hostname,servname,hints,res)205 getaddrinfo(hostname, servname, hints, res)
206 const char *hostname, *servname;
207 const struct addrinfo *hints;
208 struct addrinfo **res;
209 {
210 struct addrinfo sentinel;
211 struct addrinfo *top = NULL;
212 struct addrinfo *cur;
213 int i, error = 0;
214 char pton[PTON_MAX];
215 struct addrinfo ai;
216 struct addrinfo *pai;
217 u_short port;
218
219 #ifdef FAITH
220 static int firsttime = 1;
221
222 if (firsttime) {
223 /* translator hack */
224 {
225 char *q = getenv("GAI");
226 if (q && su_inet_pton(AF_INET6, q, &faith_prefix) == 1)
227 translate = YES;
228 }
229 firsttime = 0;
230 }
231 #endif
232
233 /* initialize file static vars */
234 sentinel.ai_next = NULL;
235 cur = &sentinel;
236 pai = &ai;
237 pai->ai_flags = 0;
238 pai->ai_family = PF_UNSPEC;
239 pai->ai_socktype = GAI_ANY;
240 pai->ai_protocol = GAI_ANY;
241 pai->ai_addrlen = 0;
242 pai->ai_canonname = NULL;
243 pai->ai_addr = NULL;
244 pai->ai_next = NULL;
245 port = GAI_ANY;
246
247 if (hostname == NULL && servname == NULL)
248 return EAI_NONAME;
249 if (hints) {
250 /* error check for hints */
251 if (hints->ai_addrlen || hints->ai_canonname ||
252 hints->ai_addr || hints->ai_next)
253 ERR(EAI_BADHINTS); /* xxx */
254 if (hints->ai_flags & ~AI_MASK)
255 ERR(EAI_BADFLAGS);
256 switch (hints->ai_family) {
257 case PF_UNSPEC:
258 case PF_INET:
259 #if SU_HAVE_IN6
260 case PF_INET6:
261 #endif
262 break;
263 default:
264 ERR(EAI_FAMILY);
265 }
266 memcpy(pai, hints, sizeof(*pai));
267 switch (pai->ai_socktype) {
268 case GAI_ANY:
269 switch (pai->ai_protocol) {
270 case GAI_ANY:
271 break;
272 case IPPROTO_UDP:
273 pai->ai_socktype = SOCK_DGRAM;
274 break;
275 case IPPROTO_TCP:
276 pai->ai_socktype = SOCK_STREAM;
277 break;
278 #if HAVE_SCTP
279 case IPPROTO_SCTP:
280 pai->ai_socktype = SOCK_STREAM;
281 break;
282 #endif
283 default:
284 pai->ai_socktype = SOCK_RAW;
285 break;
286 }
287 break;
288 case SOCK_RAW:
289 break;
290 case SOCK_DGRAM:
291 if (pai->ai_protocol != IPPROTO_UDP &&
292 #if HAVE_SCTP
293 pai->ai_protocol != IPPROTO_SCTP &&
294 #endif
295 pai->ai_protocol != GAI_ANY)
296 ERR(EAI_BADHINTS); /*xxx*/
297 if (pai->ai_protocol == GAI_ANY)
298 pai->ai_protocol = IPPROTO_UDP;
299 break;
300 case SOCK_STREAM:
301 if (pai->ai_protocol != IPPROTO_TCP &&
302 #if HAVE_SCTP
303 pai->ai_protocol != IPPROTO_SCTP &&
304 #endif
305 pai->ai_protocol != GAI_ANY)
306 ERR(EAI_BADHINTS); /*xxx*/
307 if (pai->ai_protocol == GAI_ANY)
308 pai->ai_protocol = IPPROTO_TCP;
309 break;
310 #if HAVE_SCTP
311 case SOCK_SEQPACKET:
312 if (pai->ai_protocol != IPPROTO_SCTP &&
313 pai->ai_protocol != GAI_ANY)
314 ERR(EAI_BADHINTS); /*xxx*/
315
316 if (pai->ai_protocol == GAI_ANY)
317 pai->ai_protocol = IPPROTO_SCTP;
318 break;
319 #endif
320 default:
321 ERR(EAI_SOCKTYPE);
322 break;
323 }
324 }
325
326 /*
327 * service port
328 */
329 if (servname) {
330 if (str_isnumber(servname)) {
331 if (pai->ai_socktype == GAI_ANY) {
332 /* caller accept *GAI_ANY* socktype */
333 pai->ai_socktype = SOCK_DGRAM;
334 pai->ai_protocol = IPPROTO_UDP;
335 }
336 port = htons(atoi(servname));
337 } else {
338 struct servent *sp;
339 char *proto;
340
341 proto = NULL;
342 switch (pai->ai_socktype) {
343 case GAI_ANY:
344 proto = NULL;
345 break;
346 case SOCK_DGRAM:
347 proto = "udp";
348 break;
349 case SOCK_STREAM:
350 proto = "tcp";
351 break;
352 default:
353 fprintf(stderr, "panic!\n");
354 break;
355 }
356 if ((sp = getservbyname(servname, proto)) == NULL)
357 ERR(EAI_SERVICE);
358 port = sp->s_port;
359 if (pai->ai_socktype == GAI_ANY) {
360 if (strcmp(sp->s_proto, "udp") == 0) {
361 pai->ai_socktype = SOCK_DGRAM;
362 pai->ai_protocol = IPPROTO_UDP;
363 } else if (strcmp(sp->s_proto, "tcp") == 0) {
364 pai->ai_socktype = SOCK_STREAM;
365 pai->ai_protocol = IPPROTO_TCP;
366 #if HAVE_SCTP
367 } else if (strcmp(sp->s_proto, "sctp") == 0) {
368 pai->ai_socktype = SOCK_STREAM;
369 pai->ai_protocol = IPPROTO_SCTP;
370 #endif
371 } else
372 ERR(EAI_PROTOCOL); /*xxx*/
373 }
374 }
375 }
376
377 /*
378 * hostname == NULL.
379 * passive socket -> anyaddr (0.0.0.0 or ::)
380 * non-passive socket -> localhost (127.0.0.1 or ::1)
381 */
382 if (hostname == NULL) {
383 struct gai_afd *gai_afd;
384
385 for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
386 if (!(pai->ai_family == PF_UNSPEC
387 || pai->ai_family == gai_afd->a_af)) {
388 continue;
389 }
390
391 if (pai->ai_flags & AI_PASSIVE) {
392 GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
393 /* xxx meaningless?
394 * GET_CANONNAME(cur->ai_next, "anyaddr");
395 */
396 } else {
397 GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,
398 port);
399 /* xxx meaningless?
400 * GET_CANONNAME(cur->ai_next, "localhost");
401 */
402 }
403 cur = cur->ai_next;
404 }
405 top = sentinel.ai_next;
406 if (top)
407 goto good;
408 else
409 ERR(EAI_FAMILY);
410 }
411
412 /* hostname as numeric name */
413 for (i = 0; gai_afdl[i].a_af; i++) {
414 if (su_inet_pton(gai_afdl[i].a_af, hostname, pton)) {
415 u_long v4a;
416 u_char pfx;
417
418 switch (gai_afdl[i].a_af) {
419 case AF_INET:
420 v4a = ((struct in_addr *)pton)->s_addr;
421 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
422 pai->ai_flags &= ~AI_CANONNAME;
423 v4a >>= IN_CLASSA_NSHIFT;
424 if (v4a == 0 || v4a == IN_LOOPBACKNET)
425 pai->ai_flags &= ~AI_CANONNAME;
426 break;
427 #if SU_HAVE_IN6
428 case AF_INET6:
429 pfx = ((struct in6_addr *)pton)->s6_addr8[0];
430 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
431 pai->ai_flags &= ~AI_CANONNAME;
432 break;
433 #endif
434 }
435
436 if (pai->ai_family == gai_afdl[i].a_af ||
437 pai->ai_family == PF_UNSPEC) {
438 if (! (pai->ai_flags & AI_CANONNAME)) {
439 GET_AI(top, &gai_afdl[i], pton, port);
440 goto good;
441 }
442 /*
443 * if AI_CANONNAME and if reverse lookup
444 * fail, return ai anyway to pacify
445 * calling application.
446 *
447 * XXX getaddrinfo() is a name->address
448 * translation function, and it looks strange
449 * that we do addr->name translation here.
450 */
451 get_name(pton, &gai_afdl[i], &top, pton, pai, port);
452 goto good;
453 } else
454 ERR(EAI_FAMILY); /*xxx*/
455 }
456 }
457
458 if (pai->ai_flags & AI_NUMERICHOST)
459 ERR(EAI_NONAME);
460
461 /* hostname as alphabetical name */
462 error = get_addr(hostname, pai->ai_family, &top, pai, port);
463 if (error == 0) {
464 if (top) {
465 good:
466 *res = top;
467 return SUCCESS;
468 } else
469 error = EAI_FAIL;
470 }
471 free:
472 if (top)
473 freeaddrinfo(top);
474 bad:
475 *res = NULL;
476 return error;
477 }
478
479 static int
get_name(addr,gai_afd,res,numaddr,pai,port0)480 get_name(addr, gai_afd, res, numaddr, pai, port0)
481 const char *addr;
482 struct gai_afd *gai_afd;
483 struct addrinfo **res;
484 char *numaddr;
485 struct addrinfo *pai;
486 int port0;
487 {
488 u_short port = port0 & 0xffff;
489 struct hostent *hp;
490 struct addrinfo *cur;
491 int error = 0, h_error;
492
493 #if SU_HAVE_IN6
494 hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
495 #else
496 hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
497 #endif
498 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
499 GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
500 GET_CANONNAME(cur, hp->h_name);
501 } else
502 GET_AI(cur, gai_afd, numaddr, port);
503
504 #if SU_HAVE_IN6
505 if (hp)
506 freehostent(hp);
507 #endif
508 *res = cur;
509 return SUCCESS;
510 free:
511 if (cur)
512 freeaddrinfo(cur);
513 #if SU_HAVE_IN6
514 if (hp)
515 freehostent(hp);
516 #endif
517 /* bad: */
518 *res = NULL;
519 return error;
520 }
521
522 static int
get_addr(hostname,af,res,pai,port0)523 get_addr(hostname, af, res, pai, port0)
524 const char *hostname;
525 int af;
526 struct addrinfo **res;
527 struct addrinfo *pai;
528 int port0;
529 {
530 u_short port = port0 & 0xffff;
531 struct addrinfo sentinel;
532 struct hostent *hp;
533 struct addrinfo *top, *cur;
534 struct gai_afd *gai_afd;
535 int i, error = 0, h_error;
536 char *ap;
537
538 top = NULL;
539 sentinel.ai_next = NULL;
540 cur = &sentinel;
541 #if SU_HAVE_IN6
542 if (af == AF_UNSPEC) {
543 hp = getipnodebyname(hostname, AF_INET6,
544 AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
545 } else
546 hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
547 #else
548 hp = gethostbyname(hostname);
549 h_error = h_errno;
550 #endif
551 if (hp == NULL) {
552 switch (h_error) {
553 case HOST_NOT_FOUND:
554 case NO_DATA:
555 error = EAI_NODATA;
556 break;
557 case TRY_AGAIN:
558 error = EAI_AGAIN;
559 break;
560 case NO_RECOVERY:
561 default:
562 error = EAI_FAIL;
563 break;
564 }
565 goto bad;
566 }
567
568 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
569 (hp->h_addr_list[0] == NULL))
570 ERR(EAI_FAIL);
571
572 for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
573 switch (af) {
574 #if SU_HAVE_IN6
575 case AF_INET6:
576 gai_afd = &gai_afdl[N_INET6];
577 break;
578 #endif
579 #ifndef INET6
580 default: /* AF_UNSPEC */
581 #endif
582 case AF_INET:
583 gai_afd = &gai_afdl[N_INET];
584 break;
585 #if SU_HAVE_IN6
586 default: /* AF_UNSPEC */
587 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
588 ap += sizeof(struct in6_addr) -
589 sizeof(struct in_addr);
590 gai_afd = &gai_afdl[N_INET];
591 } else
592 gai_afd = &gai_afdl[N_INET6];
593 break;
594 #endif
595 }
596 #ifdef FAITH
597 if (translate && gai_afd->a_af == AF_INET) {
598 struct in6_addr *in6;
599
600 GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);
601 in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
602 memcpy(&in6->s6_addr32[0], &faith_prefix,
603 sizeof(struct in6_addr) - sizeof(struct in_addr));
604 memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
605 } else
606 #endif /* FAITH */
607 GET_AI(cur->ai_next, gai_afd, ap, port);
608 if (cur == &sentinel) {
609 top = cur->ai_next;
610 GET_CANONNAME(top, hp->h_name);
611 }
612 cur = cur->ai_next;
613 }
614 #if SU_HAVE_IN6
615 freehostent(hp);
616 #endif
617 *res = top;
618 return SUCCESS;
619 free:
620 if (top)
621 freeaddrinfo(top);
622 #if SU_HAVE_IN6
623 if (hp)
624 freehostent(hp);
625 #endif
626 bad:
627 *res = NULL;
628 return error;
629 }
630
631 /*
632 * Issues to be discussed:
633 * - Thread safe-ness must be checked
634 * - Return values. There seems to be no standard for return value (RFC2133)
635 * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
636 */
637
638 #define SUCCESS 0
639 #define YES 1
640 #define NO 0
641
642 static struct gni_afd {
643 int a_af;
644 int a_addrlen;
645 int a_socklen;
646 int a_off;
647 } gni_afdl [] = {
648 #if SU_HAVE_IN6
649 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
650 offsetof(struct sockaddr_in6, sin6_addr)},
651 #endif
652 {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
653 offsetof(struct sockaddr_in, sin_addr)},
654 {0, 0, 0},
655 };
656
657 struct gni_sockinet {
658 u_char si_len;
659 u_char si_family;
660 u_short si_port;
661 };
662
663 #define ENI_NOSOCKET EAI_FAIL
664 #define ENI_NOSERVNAME EAI_NONAME
665 #define ENI_NOHOSTNAME EAI_NONAME
666 #define ENI_MEMORY EAI_MEMORY
667 #define ENI_SYSTEM EAI_SYSTEM
668 #define ENI_FAMILY EAI_FAMILY
669 #define ENI_SALEN EAI_MEMORY
670
671 static
672 int
getnameinfo(sa,salen,host,hostlen,serv,servlen,flags)673 getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
674 const struct sockaddr *sa;
675 size_t salen;
676 char *host;
677 size_t hostlen;
678 char *serv;
679 size_t servlen;
680 int flags;
681 {
682 struct gni_afd *gni_afd;
683 struct servent *sp;
684 struct hostent *hp;
685 u_short port;
686 int family, len, i;
687 char *addr, *p;
688 u_long v4a;
689 u_char pfx;
690 int h_error;
691 char numserv[512];
692 char numaddr[512];
693
694 if (sa == NULL)
695 return ENI_NOSOCKET;
696
697 #if SU_HAVE_SOCKADDR_SA_LEN
698 len = sa->sa_len;
699 if (len != salen) return ENI_SALEN;
700 #else
701 len = salen;
702 #endif
703
704 family = sa->sa_family;
705 for (i = 0; gni_afdl[i].a_af; i++)
706 if (gni_afdl[i].a_af == family) {
707 gni_afd = &gni_afdl[i];
708 goto found;
709 }
710 return ENI_FAMILY;
711
712 found:
713 if (len != gni_afd->a_socklen) return ENI_SALEN;
714
715 port = ((struct gni_sockinet *)sa)->si_port; /* network byte order */
716 addr = (char *)sa + gni_afd->a_off;
717
718 if (serv == NULL || servlen == 0) {
719 /* what we should do? */
720 } else if (flags & NI_NUMERICSERV) {
721 snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
722 if (strlen(numserv) > servlen)
723 return ENI_MEMORY;
724 strcpy(serv, numserv);
725 } else {
726 sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
727 if (sp) {
728 if (strlen(sp->s_name) > servlen)
729 return ENI_MEMORY;
730 strcpy(serv, sp->s_name);
731 } else
732 return ENI_NOSERVNAME;
733 }
734
735 switch (sa->sa_family) {
736 case AF_INET:
737 v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
738 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
739 flags |= NI_NUMERICHOST;
740 v4a >>= IN_CLASSA_NSHIFT;
741 if (v4a == 0 || v4a == IN_LOOPBACKNET)
742 flags |= NI_NUMERICHOST;
743 break;
744 #if SU_HAVE_IN6
745 case AF_INET6:
746 pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0];
747 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
748 flags |= NI_NUMERICHOST;
749 break;
750 #endif
751 }
752 if (host == NULL || hostlen == 0) {
753 /* what should we do? */
754 } else if (flags & NI_NUMERICHOST) {
755 if (su_inet_ntop(gni_afd->a_af, addr, numaddr, sizeof(numaddr))
756 == NULL)
757 return ENI_SYSTEM;
758 if (strlen(numaddr) > hostlen)
759 return ENI_MEMORY;
760 strcpy(host, numaddr);
761 } else {
762 #if SU_HAVE_IN6
763 hp = getipnodebyaddr(addr, gni_afd->a_addrlen, gni_afd->a_af, &h_error);
764 #else
765 hp = gethostbyaddr(addr, gni_afd->a_addrlen, gni_afd->a_af);
766 h_error = h_errno;
767 #endif
768
769 if (hp) {
770 if (flags & NI_NOFQDN) {
771 p = strchr(hp->h_name, '.');
772 if (p) *p = '\0';
773 }
774 if (strlen(hp->h_name) > hostlen) {
775 #if SU_HAVE_IN6
776 freehostent(hp);
777 #endif
778 return ENI_MEMORY;
779 }
780 strcpy(host, hp->h_name);
781 #if SU_HAVE_IN6
782 freehostent(hp);
783 #endif
784 } else {
785 if (flags & NI_NAMEREQD)
786 return ENI_NOHOSTNAME;
787 if (su_inet_ntop(gni_afd->a_af, addr,
788 numaddr, sizeof(numaddr))
789 == NULL)
790 return ENI_NOHOSTNAME;
791 if (strlen(numaddr) > hostlen)
792 return ENI_MEMORY;
793 strcpy(host, numaddr);
794 }
795 }
796 return SUCCESS;
797 }
798
799 #endif /* !HAVE_GETNAMEINFO */
800
801 #if !HAVE_FREEADDRINFO
802 static
803 void
freeaddrinfo(ai)804 freeaddrinfo(ai)
805 struct addrinfo *ai;
806 {
807 struct addrinfo *next;
808
809 if (ai == NULL)
810 return;
811
812 do {
813 next = ai->ai_next;
814 if (ai->ai_canonname)
815 free(ai->ai_canonname);
816 /* no need to free(ai->ai_addr) */
817 free(ai);
818 } while ((ai = next) != NULL);
819 }
820 #endif
821
822 #if !HAVE_GAI_STRERROR
823 static
824 char *
gai_strerror(ecode)825 gai_strerror(ecode)
826 int ecode;
827 {
828 switch (ecode) {
829 case 0:
830 return "success.";
831 #if defined(EAI_ADDRFAMILY)
832 case EAI_ADDRFAMILY:
833 return "address family for hostname not supported.";
834 #endif
835 #if defined(EAI_AGAIN)
836 case EAI_AGAIN:
837 return "temporary failure in name resolution.";
838 #endif
839 #if defined(EAI_BADFLAGS)
840 case EAI_BADFLAGS:
841 return "invalid value for ai_flags.";
842 #endif
843 #if defined(EAI_FAIL)
844 case EAI_FAIL:
845 return "non-recoverable failure in name resolution.";
846 #endif
847 #if defined(EAI_FAMILY)
848 case EAI_FAMILY:
849 return "ai_family not supported.";
850 #endif
851 #if defined(EAI_MEMORY)
852 case EAI_MEMORY:
853 return "memory allocation failure.";
854 #endif
855 #if defined(EAI_NODATA)
856 case EAI_NODATA:
857 return "no address associated with hostname.";
858 #endif
859 #if defined(EAI_NONAME)
860 case EAI_NONAME:
861 return "hostname nor servname provided, or not known.";
862 #endif
863 #if defined(EAI_SERVICE)
864 case EAI_SERVICE:
865 return "servname not supported for ai_socktype.";
866 #endif
867 #if defined(EAI_SOCKTYPE)
868 case EAI_SOCKTYPE:
869 return "ai_socktype not supported.";
870 #endif
871 #if defined(EAI_SYSTEM)
872 case EAI_SYSTEM:
873 return "system error returned in errno.";
874 #endif
875 #if defined(EAI_BADHINTS)
876 case EAI_BADHINTS:
877 return "invalid value for hints.";
878 #endif
879 #if defined(EAI_PROTOCOL)
880 case EAI_PROTOCOL:
881 return "resolved protocol is unknown.";
882 #endif
883 default:
884 return "unknown error.";
885 }
886 }
887 #endif
888
889
890 /** Translate address and service.
891 *
892 * This is a getaddrinfo() supporting SCTP and other exotic protocols.
893 */
su_getaddrinfo(char const * node,char const * service,su_addrinfo_t const * hints,su_addrinfo_t ** res)894 int su_getaddrinfo(char const *node, char const *service,
895 su_addrinfo_t const *hints,
896 su_addrinfo_t **res)
897 {
898 int retval;
899 su_addrinfo_t *ai;
900 char const *realservice = service;
901
902 if (!service || service[0] == '\0')
903 service = "0";
904
905 #if HAVE_SCTP
906 if (res && hints && hints->ai_protocol == IPPROTO_SCTP) {
907 su_addrinfo_t system_hints[1];
908 int socktype;
909
910 socktype = hints->ai_socktype;
911
912 if (!(socktype == 0 ||
913 socktype == SOCK_SEQPACKET ||
914 socktype == SOCK_STREAM ||
915 socktype == SOCK_DGRAM))
916 return EAI_SOCKTYPE;
917
918 *system_hints = *hints;
919 system_hints->ai_protocol = IPPROTO_TCP;
920 system_hints->ai_socktype = SOCK_STREAM;
921
922 retval = getaddrinfo(node, service, system_hints, res);
923 if (retval)
924 return retval;
925
926 if (socktype == 0)
927 socktype = SOCK_STREAM;
928
929 for (ai = *res; ai; ai = ai->ai_next) {
930 ai->ai_protocol = IPPROTO_SCTP;
931 ai->ai_socktype = socktype;
932 }
933
934 return 0;
935 }
936 #endif
937
938 retval = getaddrinfo(node, service, hints, res);
939
940 if (service != realservice && retval == EAI_SERVICE)
941 retval = getaddrinfo(node, realservice, hints, res);
942
943 if (retval == 0) {
944 for (ai = *res; ai; ai = ai->ai_next) {
945 if (ai->ai_protocol)
946 continue;
947
948 if (hints && hints->ai_protocol) {
949 ai->ai_protocol = hints->ai_protocol;
950 continue;
951 }
952
953 if (ai->ai_family != AF_INET
954 #if SU_HAVE_IN6
955 && ai->ai_family != AF_INET6
956 #endif
957 ) continue;
958
959 if (ai->ai_socktype == SOCK_STREAM)
960 ai->ai_protocol = IPPROTO_TCP;
961 else if (ai->ai_socktype == SOCK_DGRAM)
962 ai->ai_protocol = IPPROTO_UDP;
963 }
964 }
965 return retval;
966 }
967
968 /** Free su_addrinfo_t structure allocated by su_getaddrinfo(). */
su_freeaddrinfo(su_addrinfo_t * res)969 void su_freeaddrinfo(su_addrinfo_t *res)
970 {
971 freeaddrinfo(res);
972 }
973
974 /** Return string describing address translation error. */
su_gai_strerror(int errcode)975 char const *su_gai_strerror(int errcode)
976 {
977 return (char const *)gai_strerror(errcode);
978 }
979
980 /** Resolve socket address into hostname and service name.
981 *
982 * @note
983 * This function uses now @RFC2133 prototype. The @RFC3493 redefines the
984 * prototype as well as ai_addrlen to use socklen_t instead of size_t.
985 * If your application allocates more than 2 gigabytes for resolving the
986 * hostname, you probably lose.
987 */
988 int
su_getnameinfo(const su_sockaddr_t * su,size_t sulen,char * return_host,size_t hostlen,char * return_serv,size_t servlen,int flags)989 su_getnameinfo(const su_sockaddr_t *su, size_t sulen,
990 char *return_host, size_t hostlen,
991 char *return_serv, size_t servlen,
992 int flags)
993 {
994 return getnameinfo(&su->su_sa, (socklen_t)sulen,
995 return_host, (socklen_t)hostlen,
996 return_serv, (socklen_t)servlen,
997 flags);
998 }
999