1 /* 2 * Copyright (C) 2001,2002,2003,2004 by the Massachusetts Institute of Technology, 3 * Cambridge, MA, USA. All Rights Reserved. 4 * 5 * This software is being provided to you, the LICENSEE, by the 6 * Massachusetts Institute of Technology (M.I.T.) under the following 7 * license. By obtaining, using and/or copying this software, you agree 8 * that you have read, understood, and will comply with these terms and 9 * conditions: 10 * 11 * Export of this software from the United States of America may 12 * require a specific license from the United States Government. 13 * It is the responsibility of any person or organization contemplating 14 * export to obtain such a license before exporting. 15 * 16 * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute 17 * this software and its documentation for any purpose and without fee or 18 * royalty is hereby granted, provided that you agree to comply with the 19 * following copyright notice and statements, including the disclaimer, and 20 * that the same appear on ALL copies of the software and documentation, 21 * including modifications that you make for internal use or for 22 * distribution: 23 * 24 * THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS 25 * OR WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not 26 * limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF 27 * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF 28 * THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 29 * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. 30 * 31 * The name of the Massachusetts Institute of Technology or M.I.T. may NOT 32 * be used in advertising or publicity pertaining to distribution of the 33 * software. Title to copyright in this software and any associated 34 * documentation shall at all times remain with M.I.T., and USER agrees to 35 * preserve same. 36 * 37 * Furthermore if you modify this software you must label 38 * your software as modified software and not distribute it in such a 39 * fashion that it might be confused with the original M.I.T. software. 40 */ 41 42 /* Approach overview: 43 44 If a system version is available but buggy, save handles to it (via 45 inline functions), redefine the names to refer to static functions 46 defined here, and in those functions, call the system versions and 47 fix up the returned data. Use the native data structures and flag 48 values. 49 50 If no system version exists, use gethostby* and fake it. Define 51 the data structures and flag values locally. 52 53 54 On Mac OS X, getaddrinfo results aren't cached (though 55 gethostbyname results are), so we need to build a cache here. Now 56 things are getting really messy. Because the cache is in use, we 57 use getservbyname, and throw away thread safety. (Not that the 58 cache is thread safe, but when we get locking support, that'll be 59 dealt with.) This code needs tearing down and rebuilding, soon. 60 61 62 Note that recent Windows developers' code has an interesting hack: 63 When you include the right header files, with the right set of 64 macros indicating system versions, you'll get an inline function 65 that looks for getaddrinfo (or whatever) in the system library, and 66 calls it if it's there. If it's not there, it fakes it with 67 gethostby* calls. 68 69 We're taking a simpler approach: A system provides these routines or 70 it does not. 71 72 Someday, we may want to take into account different versions (say, 73 different revs of GNU libc) where some are broken in one way, and 74 some work or are broken in another way. Cross that bridge when we 75 come to it. */ 76 77 /* To do, maybe: 78 79 + For AIX 4.3.3, using the RFC 2133 definition: Implement 80 AI_NUMERICHOST. It's not defined in the header file. 81 82 For certain (old?) versions of GNU libc, AI_NUMERICHOST is 83 defined but not implemented. 84 85 + Use gethostbyname2, inet_aton and other IPv6 or thread-safe 86 functions if available. But, see 87 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=135182 for one 88 gethostbyname2 problem on Linux. And besides, if a platform is 89 supporting IPv6 at all, they really should be doing getaddrinfo 90 by now. 91 92 + inet_ntop, inet_pton 93 94 + Conditionally export/import the function definitions, so a 95 library can have a single copy instead of multiple. 96 97 + Upgrade host requirements to include working implementations of 98 these functions, and throw all this away. Pleeease? :-) */ 99 100 #ifndef FAI_DEFINED 101 #define FAI_DEFINED 102 103 #pragma ident "%Z%%M% %I% %E% SMI" 104 105 #include "port-sockets.h" 106 #include "socket-utils.h" 107 #include "k5-platform.h" 108 #include "k5-thread.h" 109 110 #include <stdio.h> /* for sprintf */ 111 #include <errno.h> 112 113 #ifdef S_SPLINT_S 114 /*@-incondefs@*/ 115 extern int 116 getaddrinfo (/*@in@*/ /*@null@*/ const char *, 117 /*@in@*/ /*@null@*/ const char *, 118 /*@in@*/ /*@null@*/ const struct addrinfo *, 119 /*@out@*/ struct addrinfo **) 120 ; 121 extern void 122 freeaddrinfo (/*@only@*/ /*@out@*/ struct addrinfo *) 123 ; 124 extern int 125 getnameinfo (const struct sockaddr *addr, socklen_t addrsz, 126 /*@out@*/ /*@null@*/ char *h, socklen_t hsz, 127 /*@out@*/ /*@null@*/ char *s, socklen_t ssz, 128 int flags) 129 /*@requires (maxSet(h)+1) >= hsz /\ (maxSet(s)+1) >= ssz @*/ 130 /* too hard: maxRead(addr) >= (addrsz-1) */ 131 /*@modifies *h, *s@*/; 132 extern /*@dependent@*/ char *gai_strerror (int code) /*@*/; 133 /*@=incondefs@*/ 134 #endif 135 136 137 #if defined (__APPLE__) && defined (__MACH__) 138 #define FAI_CACHE 139 #endif 140 141 #if (defined (__linux__) && defined(HAVE_GETADDRINFO)) || defined (_AIX) 142 /* See comments below. */ 143 # define WRAP_GETADDRINFO 144 #endif 145 146 #if defined (__linux__) && defined(HAVE_GETADDRINFO) 147 # define COPY_FIRST_CANONNAME 148 #endif 149 150 #ifdef _AIX 151 # define NUMERIC_SERVICE_BROKEN 152 # define COPY_FIRST_CANONNAME 153 #endif 154 155 156 #ifdef COPY_FIRST_CANONNAME 157 # include <string.h> 158 #endif 159 160 #ifdef NUMERIC_SERVICE_BROKEN 161 # include <ctype.h> /* isdigit */ 162 # include <stdlib.h> /* strtoul */ 163 #endif 164 165 #ifdef _WIN32 166 #define HAVE_GETADDRINFO 1 167 #define HAVE_GETNAMEINFO 1 168 #endif 169 170 171 /* Do we actually have *any* systems we care about that don't provide 172 either getaddrinfo or one of these two flavors of 173 gethostbyname_r? */ 174 #if !defined(HAVE_GETHOSTBYNAME_R) || defined(THREADSAFE_GETHOSTBYNAME) 175 #define GET_HOST_BY_NAME(NAME, HP, ERR) \ 176 { (HP) = gethostbyname (NAME); (ERR) = h_errno; } 177 #define GET_HOST_BY_ADDR(ADDR, ADDRLEN, FAMILY, HP, ERR) \ 178 { (HP) = gethostbyaddr ((ADDR), (ADDRLEN), (FAMILY)); (ERR) = h_errno; } 179 #else 180 #ifdef _AIX /* XXX should have a feature test! */ 181 #define GET_HOST_BY_NAME(NAME, HP, ERR) \ 182 { \ 183 struct hostent my_h_ent; \ 184 struct hostent_data my_h_ent_data; \ 185 (HP) = (gethostbyname_r((NAME), &my_h_ent, &my_h_ent_data) \ 186 ? 0 \ 187 : &my_h_ent); \ 188 (ERR) = h_errno; \ 189 } 190 /* 191 #define GET_HOST_BY_ADDR(ADDR, ADDRLEN, FAMILY, HP, ERR) \ 192 { \ 193 struct hostent my_h_ent; \ 194 struct hostent_data my_h_ent_data; \ 195 (HP) = (gethostbyaddr_r((ADDR), (ADDRLEN), (FAMILY), &my_h_ent, \ 196 &my_h_ent_data) \ 197 ? 0 \ 198 : &my_h_ent); \ 199 (ERR) = my_h_err; \ 200 } 201 */ 202 #else 203 #ifdef GETHOSTBYNAME_R_RETURNS_INT 204 #define GET_HOST_BY_NAME(NAME, HP, ERR) \ 205 { \ 206 struct hostent my_h_ent, *my_hp; \ 207 int my_h_err; \ 208 char my_h_buf[8192]; \ 209 (HP) = (gethostbyname_r((NAME), &my_h_ent, \ 210 my_h_buf, sizeof (my_h_buf), &my_hp, \ 211 &my_h_err) \ 212 ? 0 \ 213 : &my_h_ent); \ 214 (ERR) = my_h_err; \ 215 } 216 #define GET_HOST_BY_ADDR(ADDR, ADDRLEN, FAMILY, HP, ERR) \ 217 { \ 218 struct hostent my_h_ent, *my_hp; \ 219 int my_h_err; \ 220 char my_h_buf[8192]; \ 221 (HP) = (gethostbyaddr_r((ADDR), (ADDRLEN), (FAMILY), &my_h_ent, \ 222 my_h_buf, sizeof (my_h_buf), &my_hp, \ 223 &my_h_err) \ 224 ? 0 \ 225 : &my_h_ent); \ 226 (ERR) = my_h_err; \ 227 } 228 #else 229 #define GET_HOST_BY_NAME(NAME, HP, ERR) \ 230 { \ 231 struct hostent my_h_ent; \ 232 int my_h_err; \ 233 char my_h_buf[8192]; \ 234 (HP) = gethostbyname_r((NAME), &my_h_ent, \ 235 my_h_buf, sizeof (my_h_buf), &my_h_err); \ 236 (ERR) = my_h_err; \ 237 } 238 #define GET_HOST_BY_ADDR(ADDR, ADDRLEN, FAMILY, HP, ERR) \ 239 { \ 240 struct hostent my_h_ent; \ 241 int my_h_err; \ 242 char my_h_buf[8192]; \ 243 (HP) = gethostbyaddr_r((ADDR), (ADDRLEN), (FAMILY), &my_h_ent, \ 244 my_h_buf, sizeof (my_h_buf), &my_h_err); \ 245 (ERR) = my_h_err; \ 246 } 247 #endif /* returns int? */ 248 #endif /* _AIX */ 249 #endif 250 251 /* Now do the same for getservby* functions. */ 252 #ifndef HAVE_GETSERVBYNAME_R 253 #define GET_SERV_BY_NAME(NAME, PROTO, SP, ERR) \ 254 ((SP) = getservbyname (NAME, PROTO), (ERR) = (SP) ? 0 : -1) 255 #define GET_SERV_BY_PORT(PORT, PROTO, SP, ERR) \ 256 ((SP) = getservbyport (PORT, PROTO), (ERR) = (SP) ? 0 : -1) 257 #else 258 #ifdef GETSERVBYNAME_R_RETURNS_INT 259 #define GET_SERV_BY_NAME(NAME, PROTO, SP, ERR) \ 260 { \ 261 struct servent my_s_ent, *my_sp; \ 262 int my_s_err; \ 263 char my_s_buf[8192]; \ 264 (SP) = (getservbyname_r((NAME), (PROTO), &my_s_ent, \ 265 my_s_buf, sizeof (my_s_buf), &my_sp, \ 266 &my_s_err) \ 267 ? 0 \ 268 : &my_s_ent); \ 269 (ERR) = my_s_err; \ 270 } 271 #define GET_SERV_BY_PORT(PORT, PROTO, SP, ERR) \ 272 { \ 273 struct servent my_s_ent, *my_sp; \ 274 int my_s_err; \ 275 char my_s_buf[8192]; \ 276 (SP) = (getservbyport_r((PORT), (PROTO), &my_s_ent, \ 277 my_s_buf, sizeof (my_s_buf), &my_sp, \ 278 &my_s_err) \ 279 ? 0 \ 280 : &my_s_ent); \ 281 (ERR) = my_s_err; \ 282 } 283 #else 284 /* returns ptr -- IRIX? */ 285 #define GET_SERV_BY_NAME(NAME, PROTO, SP, ERR) \ 286 { \ 287 struct servent my_s_ent; \ 288 char my_s_buf[8192]; \ 289 (SP) = getservbyname_r((NAME), (PROTO), &my_s_ent, \ 290 my_s_buf, sizeof (my_s_buf)); \ 291 (ERR) = (SP) == NULL; \ 292 } 293 294 #define GET_SERV_BY_PORT(PORT, PROTO, SP, ERR) \ 295 { \ 296 struct servent my_s_ent, *my_sp; \ 297 char my_s_buf[8192]; \ 298 my_sp = getservbyport_r((PORT), (PROTO), &my_s_ent, \ 299 my_s_buf, sizeof (my_s_buf)); \ 300 (SP) = my_sp; \ 301 (ERR) = my_sp == 0; \ 302 (ERR) = (ERR); /* avoid "unused" warning */ \ 303 } 304 #endif 305 #endif 306 307 #if defined(WRAP_GETADDRINFO) || defined(FAI_CACHE) 308 static inline int 309 system_getaddrinfo (const char *name, const char *serv, 310 const struct addrinfo *hint, 311 struct addrinfo **res) 312 { 313 return getaddrinfo(name, serv, hint, res); 314 } 315 316 static inline void 317 system_freeaddrinfo (struct addrinfo *ai) 318 { 319 freeaddrinfo(ai); 320 } 321 322 /* Note: Implementations written to RFC 2133 use size_t, while RFC 323 2553 implementations use socklen_t, for the second parameter. 324 325 Mac OS X (10.2) and AIX 4.3.3 appear to be in the RFC 2133 camp, 326 but we don't have an autoconf test for that right now. */ 327 static inline int 328 system_getnameinfo (const struct sockaddr *sa, socklen_t salen, 329 char *host, size_t hostlen, char *serv, size_t servlen, 330 int flags) 331 { 332 return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); 333 } 334 #endif 335 336 #if !defined (HAVE_GETADDRINFO) || defined(WRAP_GETADDRINFO) || defined(FAI_CACHE) 337 338 #undef getaddrinfo 339 #define getaddrinfo my_fake_getaddrinfo 340 #undef freeaddrinfo 341 #define freeaddrinfo my_fake_freeaddrinfo 342 343 #endif 344 345 #if !defined (HAVE_GETADDRINFO) 346 347 #undef gai_strerror 348 #define gai_strerror my_fake_gai_strerror 349 #undef addrinfo 350 #define addrinfo my_fake_addrinfo 351 352 struct addrinfo { 353 int ai_family; /* PF_foo */ 354 int ai_socktype; /* SOCK_foo */ 355 int ai_protocol; /* 0, IPPROTO_foo */ 356 int ai_flags; /* AI_PASSIVE etc */ 357 size_t ai_addrlen; /* real length of socket address */ 358 char *ai_canonname; /* canonical name of host */ 359 struct sockaddr *ai_addr; /* pointer to variable-size address */ 360 struct addrinfo *ai_next; /* next in linked list */ 361 }; 362 363 #undef AI_PASSIVE 364 #define AI_PASSIVE 0x01 365 #undef AI_CANONNAME 366 #define AI_CANONNAME 0x02 367 #undef AI_NUMERICHOST 368 #define AI_NUMERICHOST 0x04 369 /* RFC 2553 says these are part of the interface for getipnodebyname, 370 not for getaddrinfo. RFC 3493 says they're part of the interface 371 for getaddrinfo, and getipnodeby* are deprecated. Our fake 372 getaddrinfo implementation here does IPv4 only anyways. */ 373 #undef AI_V4MAPPED 374 #define AI_V4MAPPED 0 375 #undef AI_ADDRCONFIG 376 #define AI_ADDRCONFIG 0 377 #undef AI_ALL 378 #define AI_ALL 0 379 #undef AI_DEFAULT 380 #define AI_DEFAULT (AI_V4MAPPED|AI_ADDRCONFIG) 381 382 #ifndef NI_MAXHOST 383 #define NI_MAXHOST 1025 384 #endif 385 #ifndef NI_MAXSERV 386 #define NI_MAXSERV 32 387 #endif 388 389 #undef NI_NUMERICHOST 390 #define NI_NUMERICHOST 0x01 391 #undef NI_NUMERICSERV 392 #define NI_NUMERICSERV 0x02 393 #undef NI_NAMEREQD 394 #define NI_NAMEREQD 0x04 395 #undef NI_DGRAM 396 #define NI_DGRAM 0x08 397 #undef NI_NOFQDN 398 #define NI_NOFQDN 0x10 399 400 401 #undef EAI_ADDRFAMILY 402 #define EAI_ADDRFAMILY 1 403 #undef EAI_AGAIN 404 #define EAI_AGAIN 2 405 #undef EAI_BADFLAGS 406 #define EAI_BADFLAGS 3 407 #undef EAI_FAIL 408 #define EAI_FAIL 4 409 #undef EAI_FAMILY 410 #define EAI_FAMILY 5 411 #undef EAI_MEMORY 412 #define EAI_MEMORY 6 413 #undef EAI_NODATA 414 #define EAI_NODATA 7 415 #undef EAI_NONAME 416 #define EAI_NONAME 8 417 #undef EAI_SERVICE 418 #define EAI_SERVICE 9 419 #undef EAI_SOCKTYPE 420 #define EAI_SOCKTYPE 10 421 #undef EAI_SYSTEM 422 #define EAI_SYSTEM 11 423 424 #endif /* ! HAVE_GETADDRINFO */ 425 426 #if (!defined (HAVE_GETADDRINFO) || defined (WRAP_GETADDRINFO)) && defined(DEBUG_ADDRINFO) 427 /* Some debug routines. */ 428 429 static const char *protoname (int p, char *buf) { 430 #define X(N) if (p == IPPROTO_ ## N) return #N 431 432 X(TCP); 433 X(UDP); 434 X(ICMP); 435 X(IPV6); 436 #ifdef IPPROTO_GRE 437 X(GRE); 438 #endif 439 X(NONE); 440 X(RAW); 441 #ifdef IPPROTO_COMP 442 X(COMP); 443 #endif 444 445 sprintf(buf, " %-2d", p); 446 return buf; 447 } 448 449 static const char *socktypename (int t, char *buf) { 450 switch (t) { 451 case SOCK_DGRAM: return "DGRAM"; 452 case SOCK_STREAM: return "STREAM"; 453 case SOCK_RAW: return "RAW"; 454 case SOCK_RDM: return "RDM"; 455 case SOCK_SEQPACKET: return "SEQPACKET"; 456 } 457 sprintf(buf, " %-2d", t); 458 return buf; 459 } 460 461 static const char *familyname (int f, char *buf) { 462 switch (f) { 463 default: 464 sprintf(buf, "AF %d", f); 465 return buf; 466 case AF_INET: return "AF_INET"; 467 case AF_INET6: return "AF_INET6"; 468 #ifdef AF_UNIX 469 case AF_UNIX: return "AF_UNIX"; 470 #endif 471 } 472 } 473 474 static void debug_dump_getaddrinfo_args (const char *name, const char *serv, 475 const struct addrinfo *hint) 476 { 477 const char *sep; 478 fprintf(stderr, 479 "getaddrinfo(hostname %s, service %s,\n" 480 " hints { ", 481 name ? name : "(null)", serv ? serv : "(null)"); 482 if (hint) { 483 char buf[30]; 484 sep = ""; 485 #define Z(FLAG) if (hint->ai_flags & AI_##FLAG) fprintf(stderr, "%s%s", sep, #FLAG), sep = "|" 486 Z(CANONNAME); 487 Z(PASSIVE); 488 #ifdef AI_NUMERICHOST 489 Z(NUMERICHOST); 490 #endif 491 if (sep[0] == 0) 492 fprintf(stderr, "no-flags"); 493 if (hint->ai_family) 494 fprintf(stderr, " %s", familyname(hint->ai_family, buf)); 495 if (hint->ai_socktype) 496 fprintf(stderr, " SOCK_%s", socktypename(hint->ai_socktype, buf)); 497 if (hint->ai_protocol) 498 fprintf(stderr, " IPPROTO_%s", protoname(hint->ai_protocol, buf)); 499 } else 500 fprintf(stderr, "(null)"); 501 fprintf(stderr, " }):\n"); 502 } 503 504 static void debug_dump_error (int err) 505 { 506 fprintf(stderr, "error %d: %s\n", err, gai_strerror(err)); 507 } 508 509 static void debug_dump_addrinfos (const struct addrinfo *ai) 510 { 511 int count = 0; 512 fprintf(stderr, "addrinfos returned:\n"); 513 while (ai) { 514 fprintf(stderr, "%p...", ai); 515 fprintf(stderr, " socktype=%s", socktypename(ai->ai_socktype)); 516 fprintf(stderr, " ai_family=%s", familyname(ai->ai_family)); 517 if (ai->ai_family != ai->ai_addr->sa_family) 518 fprintf(stderr, " sa_family=%s", 519 familyname(ai->ai_addr->sa_family)); 520 fprintf(stderr, "\n"); 521 ai = ai->ai_next; 522 count++; 523 } 524 fprintf(stderr, "end addrinfos returned (%d)\n"); 525 } 526 527 #endif 528 529 #if !defined (HAVE_GETADDRINFO) || defined (WRAP_GETADDRINFO) 530 531 static 532 int getaddrinfo (const char *name, const char *serv, 533 const struct addrinfo *hint, struct addrinfo **result); 534 535 static 536 void freeaddrinfo (struct addrinfo *ai); 537 538 #endif 539 540 #if !defined (HAVE_GETADDRINFO) 541 542 #define HAVE_FAKE_GETADDRINFO /* was not originally HAVE_GETADDRINFO */ 543 #define HAVE_GETADDRINFO 544 #define NEED_FAKE_GETNAMEINFO 545 #undef HAVE_GETNAMEINFO 546 #define HAVE_GETNAMEINFO 1 547 548 #undef getnameinfo 549 #define getnameinfo my_fake_getnameinfo 550 551 static 552 char *gai_strerror (int code); 553 554 #endif 555 556 #if !defined (HAVE_GETADDRINFO) 557 static 558 int getnameinfo (const struct sockaddr *addr, socklen_t len, 559 char *host, socklen_t hostlen, 560 char *service, socklen_t servicelen, 561 int flags); 562 #endif 563 564 /* Fudge things on older gai implementations. */ 565 /* AIX 4.3.3 is based on RFC 2133; no AI_NUMERICHOST. */ 566 #ifndef AI_NUMERICHOST 567 # define AI_NUMERICHOST 0 568 #endif 569 /* Partial RFC 2553 implementations may not have AI_ADDRCONFIG and 570 friends, which RFC 3493 says are now part of the getaddrinfo 571 interface, and we'll want to use. */ 572 #ifndef AI_ADDRCONFIG 573 # define AI_ADDRCONFIG 0 574 #endif 575 #ifndef AI_V4MAPPED 576 # define AI_V4MAPPED 0 577 #endif 578 #ifndef AI_ALL 579 # define AI_ALL 0 580 #endif 581 #ifndef AI_DEFAULT 582 # define AI_DEFAULT (AI_ADDRCONFIG|AI_V4MAPPED) 583 #endif 584 585 #if defined(HAVE_FAKE_GETADDRINFO) || defined(FAI_CACHE) 586 #define NEED_FAKE_GETADDRINFO 587 #endif 588 589 #if defined(NEED_FAKE_GETADDRINFO) || defined(WRAP_GETADDRINFO) 590 #include <stdlib.h> 591 #endif 592 593 struct face { 594 struct in_addr *addrs4; 595 struct in6_addr *addrs6; 596 unsigned int naddrs4, naddrs6; 597 time_t expiration; 598 char *canonname, *name; 599 struct face *next; 600 }; 601 602 /* fake addrinfo cache */ 603 struct fac { 604 k5_mutex_t lock; 605 struct face *data; 606 }; 607 extern struct fac krb5int_fac; 608 609 #ifdef NEED_FAKE_GETADDRINFO 610 #include <string.h> /* for strspn */ 611 612 static inline int translate_h_errno (int h); 613 614 static inline int fai_add_entry (struct addrinfo **result, void *addr, 615 int port, const struct addrinfo *template) 616 { 617 struct addrinfo *n = malloc (sizeof (struct addrinfo)); 618 if (n == 0) 619 return EAI_MEMORY; 620 if (template->ai_family != AF_INET 621 #ifdef KRB5_USE_INET6 622 && template->ai_family != AF_INET6 623 #endif 624 ) 625 return EAI_FAMILY; 626 *n = *template; 627 if (template->ai_family == AF_INET) { 628 struct sockaddr_in *sin4; 629 sin4 = malloc (sizeof (struct sockaddr_in)); 630 if (sin4 == 0) 631 return EAI_MEMORY; 632 n->ai_addr = (struct sockaddr *) sin4; 633 sin4->sin_family = AF_INET; 634 sin4->sin_addr = *(struct in_addr *)addr; 635 sin4->sin_port = port; 636 #ifdef HAVE_SA_LEN 637 sin4->sin_len = sizeof (struct sockaddr_in); 638 #endif 639 } 640 #ifdef KRB5_USE_INET6 641 if (template->ai_family == AF_INET6) { 642 struct sockaddr_in6 *sin6; 643 sin6 = malloc (sizeof (struct sockaddr_in6)); 644 if (sin6 == 0) 645 return EAI_MEMORY; 646 n->ai_addr = (struct sockaddr *) sin6; 647 sin6->sin6_family = AF_INET6; 648 sin6->sin6_addr = *(struct in6_addr *)addr; 649 sin6->sin6_port = port; 650 #ifdef HAVE_SA_LEN 651 sin6->sin6_len = sizeof (struct sockaddr_in6); 652 #endif 653 } 654 #endif 655 n->ai_next = *result; 656 *result = n; 657 return 0; 658 } 659 660 #ifdef FAI_CACHE 661 /* fake addrinfo cache entries */ 662 #define CACHE_ENTRY_LIFETIME 15 /* seconds */ 663 664 static void plant_face (const char *name, struct face *entry) 665 { 666 entry->name = strdup(name); 667 if (entry->name == NULL) 668 /* @@ Wastes memory. */ 669 return; 670 k5_mutex_assert_locked(&krb5int_fac.lock); 671 entry->next = krb5int_fac.data; 672 entry->expiration = time(0) + CACHE_ENTRY_LIFETIME; 673 krb5int_fac.data = entry; 674 #ifdef DEBUG_ADDRINFO 675 printf("added cache entry '%s' at %p: %d ipv4, %d ipv6; expire %d\n", 676 name, entry, entry->naddrs4, entry->naddrs6, entry->expiration); 677 #endif 678 } 679 680 static int find_face (const char *name, struct face **entry) 681 { 682 struct face *fp, **fpp; 683 time_t now = time(0); 684 685 /* First, scan for expired entries and free them. 686 (Future improvement: Integrate these two loops.) */ 687 #ifdef DEBUG_ADDRINFO 688 printf("scanning cache at %d for '%s'...\n", now, name); 689 #endif 690 k5_mutex_assert_locked(&krb5int_fac.lock); 691 for (fpp = &krb5int_fac.data; *fpp; ) { 692 fp = *fpp; 693 #ifdef DEBUG_ADDRINFO 694 printf(" checking expiration time of @%p: %d\n", 695 fp, fp->expiration); 696 #endif 697 if (fp->expiration < now) { 698 #ifdef DEBUG_ADDRINFO 699 printf("\texpiring cache entry\n"); 700 #endif 701 free(fp->name); 702 free(fp->canonname); 703 free(fp->addrs4); 704 free(fp->addrs6); 705 *fpp = fp->next; 706 free(fp); 707 /* Stay at this point in the list, and check again. */ 708 } else 709 /* Move forward. */ 710 fpp = &(*fpp)->next; 711 } 712 713 for (fp = krb5int_fac.data; fp; fp = fp->next) { 714 #ifdef DEBUG_ADDRINFO 715 printf(" comparing entry @%p\n", fp); 716 #endif 717 if (!strcasecmp(fp->name, name)) { 718 #ifdef DEBUG_ADDRINFO 719 printf("\tMATCH!\n"); 720 #endif 721 *entry = fp; 722 return 1; 723 } 724 } 725 return 0; 726 } 727 728 #endif 729 730 extern int krb5int_lock_fac(void), krb5int_unlock_fac(void); 731 732 static inline int fai_add_hosts_by_name (const char *name, 733 struct addrinfo *template, 734 int portnum, int flags, 735 struct addrinfo **result) 736 { 737 #ifdef FAI_CACHE 738 739 struct face *ce; 740 int i, r, err; 741 742 err = krb5int_lock_fac(); 743 if (err) { 744 errno = err; 745 return EAI_SYSTEM; 746 } 747 if (!find_face(name, &ce)) { 748 struct addrinfo myhints = { 0 }, *ai, *ai2; 749 int i4, i6, aierr; 750 751 #ifdef DEBUG_ADDRINFO 752 printf("looking up new data for '%s'...\n", name); 753 #endif 754 myhints.ai_socktype = SOCK_STREAM; 755 myhints.ai_flags = AI_CANONNAME; 756 /* Don't set ai_family -- we want to cache all address types, 757 because the next lookup may not use the same constraints as 758 the current one. We *could* cache them separately, so that 759 we never have to look up an IPv6 address if we are always 760 asked for IPv4 only, but let's deal with that later, if we 761 have to. */ 762 aierr = system_getaddrinfo(name, "telnet", &myhints, &ai); 763 if (aierr) { 764 krb5int_unlock_fac(); 765 return aierr; 766 } 767 ce = malloc(sizeof(struct face)); 768 memset(ce, 0, sizeof(*ce)); 769 ce->expiration = time(0) + 30; 770 for (ai2 = ai; ai2; ai2 = ai2->ai_next) { 771 #ifdef DEBUG_ADDRINFO 772 printf(" found an address in family %d...\n", ai2->ai_family); 773 #endif 774 switch (ai2->ai_family) { 775 case AF_INET: 776 ce->naddrs4++; 777 break; 778 case AF_INET6: 779 ce->naddrs6++; 780 break; 781 default: 782 break; 783 } 784 } 785 ce->addrs4 = calloc(ce->naddrs4, sizeof(*ce->addrs4)); 786 if (ce->addrs4 == NULL && ce->naddrs4 != 0) { 787 krb5int_unlock_fac(); 788 system_freeaddrinfo(ai); 789 return EAI_MEMORY; 790 } 791 ce->addrs6 = calloc(ce->naddrs6, sizeof(*ce->addrs6)); 792 if (ce->addrs6 == NULL && ce->naddrs6 != 0) { 793 krb5int_unlock_fac(); 794 free(ce->addrs4); 795 system_freeaddrinfo(ai); 796 return EAI_MEMORY; 797 } 798 for (ai2 = ai, i4 = i6 = 0; ai2; ai2 = ai2->ai_next) { 799 switch (ai2->ai_family) { 800 case AF_INET: 801 ce->addrs4[i4++] = ((struct sockaddr_in *)ai2->ai_addr)->sin_addr; 802 break; 803 case AF_INET6: 804 ce->addrs6[i6++] = ((struct sockaddr_in6 *)ai2->ai_addr)->sin6_addr; 805 break; 806 default: 807 break; 808 } 809 } 810 ce->canonname = ai->ai_canonname ? strdup(ai->ai_canonname) : 0; 811 system_freeaddrinfo(ai); 812 plant_face(name, ce); 813 } 814 template->ai_family = AF_INET6; 815 template->ai_addrlen = sizeof(struct sockaddr_in6); 816 for (i = 0; i < ce->naddrs6; i++) { 817 r = fai_add_entry (result, &ce->addrs6[i], portnum, template); 818 if (r) { 819 krb5int_unlock_fac(); 820 return r; 821 } 822 } 823 template->ai_family = AF_INET; 824 template->ai_addrlen = sizeof(struct sockaddr_in); 825 for (i = 0; i < ce->naddrs4; i++) { 826 r = fai_add_entry (result, &ce->addrs4[i], portnum, template); 827 if (r) { 828 krb5int_unlock_fac(); 829 return r; 830 } 831 } 832 if (*result && (flags & AI_CANONNAME)) 833 (*result)->ai_canonname = (ce->canonname 834 ? strdup(ce->canonname) 835 : NULL); 836 krb5int_unlock_fac(); 837 return 0; 838 839 #else 840 841 struct hostent *hp; 842 int i, r; 843 int herr; 844 845 GET_HOST_BY_NAME (name, hp, herr); 846 if (hp == 0) 847 return translate_h_errno (herr); 848 for (i = 0; hp->h_addr_list[i]; i++) { 849 r = fai_add_entry (result, hp->h_addr_list[i], portnum, template); 850 if (r) 851 return r; 852 } 853 if (*result && (flags & AI_CANONNAME)) 854 (*result)->ai_canonname = strdup (hp->h_name); 855 return 0; 856 857 #endif 858 } 859 860 static inline void 861 fake_freeaddrinfo (struct addrinfo *ai) 862 { 863 struct addrinfo *next; 864 while (ai) { 865 next = ai->ai_next; 866 if (ai->ai_canonname) 867 free (ai->ai_canonname); 868 if (ai->ai_addr) 869 free (ai->ai_addr); 870 free (ai); 871 ai = next; 872 } 873 } 874 875 static inline int 876 fake_getaddrinfo (const char *name, const char *serv, 877 const struct addrinfo *hint, struct addrinfo **result) 878 { 879 struct addrinfo *res = 0; 880 int ret; 881 int port = 0, socktype; 882 int flags; 883 struct addrinfo template; 884 885 #ifdef DEBUG_ADDRINFO 886 debug_dump_getaddrinfo_args(name, serv, hint); 887 #endif 888 889 if (hint != 0) { 890 if (hint->ai_family != 0 && hint->ai_family != AF_INET) 891 return EAI_NODATA; 892 socktype = hint->ai_socktype; 893 flags = hint->ai_flags; 894 } else { 895 socktype = 0; 896 flags = 0; 897 } 898 899 if (serv) { 900 size_t numlen = strspn (serv, "0123456789"); 901 if (serv[numlen] == '\0') { 902 /* pure numeric */ 903 unsigned long p = strtoul (serv, 0, 10); 904 if (p == 0 || p > 65535) 905 return EAI_NONAME; 906 port = htons (p); 907 } else { 908 struct servent *sp; 909 int try_dgram_too = 0, s_err; 910 911 if (socktype == 0) { 912 try_dgram_too = 1; 913 socktype = SOCK_STREAM; 914 } 915 try_service_lookup: 916 GET_SERV_BY_NAME(serv, socktype == SOCK_STREAM ? "tcp" : "udp", 917 sp, s_err); 918 if (sp == 0) { 919 if (try_dgram_too) { 920 socktype = SOCK_DGRAM; 921 goto try_service_lookup; 922 } 923 return EAI_SERVICE; 924 } 925 port = sp->s_port; 926 } 927 } 928 929 if (name == 0) { 930 name = (flags & AI_PASSIVE) ? "0.0.0.0" : "127.0.0.1"; 931 flags |= AI_NUMERICHOST; 932 } 933 934 template.ai_family = AF_INET; 935 template.ai_addrlen = sizeof (struct sockaddr_in); 936 template.ai_socktype = socktype; 937 template.ai_protocol = 0; 938 template.ai_flags = 0; 939 template.ai_canonname = 0; 940 template.ai_next = 0; 941 template.ai_addr = 0; 942 943 /* If NUMERICHOST is set, parse a numeric address. 944 If it's not set, don't accept such names. */ 945 if (flags & AI_NUMERICHOST) { 946 struct in_addr addr4; 947 #if 0 948 ret = inet_aton (name, &addr4); 949 if (ret) 950 return EAI_NONAME; 951 #else 952 addr4.s_addr = inet_addr (name); 953 if (addr4.s_addr == 0xffffffff || addr4.s_addr == -1) 954 /* 255.255.255.255 or parse error, both bad */ 955 return EAI_NONAME; 956 #endif 957 ret = fai_add_entry (&res, &addr4, port, &template); 958 } else { 959 ret = fai_add_hosts_by_name (name, &template, port, flags, 960 &res); 961 } 962 963 if (ret && ret != NO_ADDRESS) { 964 fake_freeaddrinfo (res); 965 return ret; 966 } 967 if (res == 0) 968 return NO_ADDRESS; 969 *result = res; 970 return 0; 971 } 972 973 #ifdef NEED_FAKE_GETNAMEINFO 974 static inline int 975 fake_getnameinfo (const struct sockaddr *sa, socklen_t len, 976 char *host, socklen_t hostlen, 977 char *service, socklen_t servicelen, 978 int flags) 979 { 980 struct hostent *hp; 981 const struct sockaddr_in *sinp; 982 struct servent *sp; 983 size_t hlen, slen; 984 985 if (sa->sa_family != AF_INET) { 986 return EAI_FAMILY; 987 } 988 sinp = (const struct sockaddr_in *) sa; 989 990 hlen = hostlen; 991 if (hostlen < 0 || hlen != hostlen) { 992 errno = EINVAL; 993 return EAI_SYSTEM; 994 } 995 slen = servicelen; 996 if (servicelen < 0 || slen != servicelen) { 997 errno = EINVAL; 998 return EAI_SYSTEM; 999 } 1000 1001 if (host) { 1002 if (flags & NI_NUMERICHOST) { 1003 #if (defined(__GNUC__) && defined(__mips__)) || 1 /* thread safety always */ 1004 /* The inet_ntoa call, passing a struct, fails on IRIX 6.5 1005 using gcc 2.95; we get back "0.0.0.0". Since this in a 1006 configuration still important at Athena, here's the 1007 workaround, which also happens to be thread-safe.... */ 1008 const unsigned char *uc; 1009 char tmpbuf[20]; 1010 numeric_host: 1011 uc = (const unsigned char *) &sinp->sin_addr; 1012 sprintf(tmpbuf, "%d.%d.%d.%d", uc[0], uc[1], uc[2], uc[3]); 1013 strncpy(host, tmpbuf, hlen); 1014 #else 1015 char *p; 1016 numeric_host: 1017 p = inet_ntoa (sinp->sin_addr); 1018 strncpy (host, p, hlen); 1019 #endif 1020 } else { 1021 int herr; 1022 GET_HOST_BY_ADDR((const char *) &sinp->sin_addr, 1023 sizeof (struct in_addr), 1024 sa->sa_family, hp, herr); 1025 if (hp == 0) { 1026 if (herr == NO_ADDRESS && !(flags & NI_NAMEREQD)) /* ??? */ 1027 goto numeric_host; 1028 return translate_h_errno (herr); 1029 } 1030 /* According to the Open Group spec, getnameinfo can 1031 silently truncate, but must still return a 1032 null-terminated string. */ 1033 strncpy (host, hp->h_name, hlen); 1034 } 1035 host[hostlen-1] = 0; 1036 } 1037 1038 if (service) { 1039 if (flags & NI_NUMERICSERV) { 1040 char numbuf[10]; 1041 int port; 1042 numeric_service: 1043 port = ntohs (sinp->sin_port); 1044 if (port < 0 || port > 65535) 1045 return EAI_FAIL; 1046 sprintf (numbuf, "%d", port); 1047 strncpy (service, numbuf, slen); 1048 } else { 1049 int serr; 1050 GET_SERV_BY_PORT(sinp->sin_port, 1051 (flags & NI_DGRAM) ? "udp" : "tcp", 1052 sp, serr); 1053 if (sp == 0) 1054 goto numeric_service; 1055 strncpy (service, sp->s_name, slen); 1056 } 1057 service[servicelen-1] = 0; 1058 } 1059 1060 return 0; 1061 } 1062 #endif 1063 1064 #if defined(HAVE_FAKE_GETADDRINFO) || defined(NEED_FAKE_GETNAMEINFO) 1065 1066 static inline 1067 char *gai_strerror (int code) 1068 { 1069 switch (code) { 1070 case EAI_ADDRFAMILY: return "address family for nodename not supported"; 1071 case EAI_AGAIN: return "temporary failure in name resolution"; 1072 case EAI_BADFLAGS: return "bad flags to getaddrinfo/getnameinfo"; 1073 case EAI_FAIL: return "non-recoverable failure in name resolution"; 1074 case EAI_FAMILY: return "ai_family not supported"; 1075 case EAI_MEMORY: return "out of memory"; 1076 case EAI_NODATA: return "no address associated with hostname"; 1077 case EAI_NONAME: return "name does not exist"; 1078 case EAI_SERVICE: return "service name not supported for specified socket type"; 1079 case EAI_SOCKTYPE: return "ai_socktype not supported"; 1080 case EAI_SYSTEM: return strerror (errno); 1081 default: return "bogus getaddrinfo error?"; 1082 } 1083 } 1084 #endif 1085 1086 static inline int translate_h_errno (int h) 1087 { 1088 switch (h) { 1089 case 0: 1090 return 0; 1091 #ifdef NETDB_INTERNAL 1092 case NETDB_INTERNAL: 1093 if (errno == ENOMEM) 1094 return EAI_MEMORY; 1095 return EAI_SYSTEM; 1096 #endif 1097 case HOST_NOT_FOUND: 1098 return EAI_NONAME; 1099 case TRY_AGAIN: 1100 return EAI_AGAIN; 1101 case NO_RECOVERY: 1102 return EAI_FAIL; 1103 case NO_DATA: 1104 #if NO_DATA != NO_ADDRESS 1105 case NO_ADDRESS: 1106 #endif 1107 return EAI_NODATA; 1108 default: 1109 return EAI_SYSTEM; 1110 } 1111 } 1112 1113 #if defined(HAVE_FAKE_GETADDRINFO) || defined(FAI_CACHE) 1114 static inline 1115 int getaddrinfo (const char *name, const char *serv, 1116 const struct addrinfo *hint, struct addrinfo **result) 1117 { 1118 return fake_getaddrinfo(name, serv, hint, result); 1119 } 1120 1121 static inline 1122 void freeaddrinfo (struct addrinfo *ai) 1123 { 1124 fake_freeaddrinfo(ai); 1125 } 1126 1127 #ifdef NEED_FAKE_GETNAMEINFO 1128 static inline 1129 int getnameinfo (const struct sockaddr *sa, socklen_t len, 1130 char *host, socklen_t hostlen, 1131 char *service, socklen_t servicelen, 1132 int flags) 1133 { 1134 return fake_getnameinfo(sa, len, host, hostlen, service, servicelen, 1135 flags); 1136 } 1137 #endif /* NEED_FAKE_GETNAMEINFO */ 1138 #endif /* HAVE_FAKE_GETADDRINFO */ 1139 #endif /* NEED_FAKE_GETADDRINFO */ 1140 1141 1142 #ifdef WRAP_GETADDRINFO 1143 1144 static inline 1145 int 1146 getaddrinfo (const char *name, const char *serv, const struct addrinfo *hint, 1147 struct addrinfo **result) 1148 { 1149 int aierr; 1150 #if defined(_AIX) || defined(COPY_FIRST_CANONNAME) 1151 struct addrinfo *ai; 1152 #endif 1153 #ifdef NUMERIC_SERVICE_BROKEN 1154 int service_is_numeric = 0; 1155 int service_port = 0; 1156 int socket_type = 0; 1157 #endif 1158 1159 #ifdef DEBUG_ADDRINFO 1160 debug_dump_getaddrinfo_args(name, serv, hint); 1161 #endif 1162 1163 #ifdef NUMERIC_SERVICE_BROKEN 1164 /* AIX 4.3.3 is broken. (Or perhaps out of date?) 1165 1166 If a numeric service is provided, and it doesn't correspond to 1167 a known service name for tcp or udp (as appropriate), an error 1168 code (for "host not found") is returned. If the port maps to a 1169 known service for both udp and tcp, all is well. */ 1170 if (serv && serv[0] && isdigit(serv[0])) { 1171 unsigned long lport; 1172 char *end; 1173 lport = strtoul(serv, &end, 10); 1174 if (!*end) { 1175 if (lport > 65535) 1176 return EAI_SOCKTYPE; 1177 service_is_numeric = 1; 1178 service_port = htons(lport); 1179 serv = "discard"; /* defined for both udp and tcp */ 1180 if (hint) 1181 socket_type = hint->ai_socktype; 1182 } 1183 } 1184 #endif 1185 1186 aierr = system_getaddrinfo (name, serv, hint, result); 1187 if (aierr || *result == 0) { 1188 #ifdef DEBUG_ADDRINFO 1189 debug_dump_error(aierr); 1190 #endif 1191 return aierr; 1192 } 1193 1194 /* Linux libc version 6 (libc-2.2.4.so on Debian) is broken. 1195 1196 RFC 2553 says that when AI_CANONNAME is set, the ai_canonname 1197 flag of the first returned structure has the canonical name of 1198 the host. Instead, GNU libc sets ai_canonname in each returned 1199 structure to the name that the corresponding address maps to, 1200 if any, or a printable numeric form. 1201 1202 RFC 2553 bis and the new Open Group spec say that field will be 1203 the canonical name if it can be determined, otherwise, the 1204 provided hostname or a copy of it. 1205 1206 IMNSHO, "canonical name" means CNAME processing and not PTR 1207 processing, but I can see arguing it. Using the numeric form 1208 when that's not the form provided is just wrong. So, let's fix 1209 it. 1210 1211 The glibc 2.2.5 sources indicate that the canonical name is 1212 *not* allocated separately, it's just some extra storage tacked 1213 on the end of the addrinfo structure. So, let's try this 1214 approach: If getaddrinfo sets ai_canonname, we'll replace the 1215 *first* one with allocated storage, and free up that pointer in 1216 freeaddrinfo if it's set; the other ai_canonname fields will be 1217 left untouched. And we'll just pray that the application code 1218 won't mess around with the list structure; if we start doing 1219 that, we'll have to start replacing and freeing all of the 1220 ai_canonname fields. 1221 1222 Ref: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=133668 . 1223 1224 Since it's dependent on the target hostname, it's hard to check 1225 for at configure time. Always do it on Linux for now. When 1226 they get around to fixing it, add a compile-time or run-time 1227 check for the glibc version in use. 1228 1229 Some Windows documentation says that even when AI_CANONNAME is 1230 set, the returned ai_canonname field can be null. The NetBSD 1231 1.5 implementation also does this, if the input hostname is a 1232 numeric host address string. That case isn't handled well at 1233 the moment. 1234 1235 Libc version 5 didn't have getaddrinfo at all. */ 1236 1237 #ifdef COPY_FIRST_CANONNAME 1238 /* 1239 * This code must *always* return an error, return a null 1240 * ai_canonname, or return an ai_canonname allocated here using 1241 * malloc, so that freeaddrinfo can always free a non-null 1242 * ai_canonname. Note that it really doesn't matter if the 1243 * AI_CANONNAME flag was set. 1244 */ 1245 ai = *result; 1246 if (ai->ai_canonname) { 1247 struct hostent *hp; 1248 const char *name2 = 0; 1249 int i, herr; 1250 1251 /* 1252 * Current versions of GET_HOST_BY_NAME will fail if the 1253 * target hostname has IPv6 addresses only. Make sure it 1254 * fails fairly cleanly. 1255 */ 1256 GET_HOST_BY_NAME (name, hp, herr); 1257 if (hp == 0) { 1258 /* 1259 * This case probably means it's an IPv6-only name. If 1260 * ai_canonname is a numeric address, get rid of it. 1261 */ 1262 if (ai->ai_canonname && strchr(ai->ai_canonname, ':')) 1263 ai->ai_canonname = 0; 1264 name2 = ai->ai_canonname ? ai->ai_canonname : name; 1265 } else { 1266 /* Sometimes gethostbyname will be directed to /etc/hosts 1267 first, and sometimes that file will have entries with 1268 the unqualified name first. So take the first entry 1269 that looks like it could be a FQDN. */ 1270 for (i = 0; hp->h_aliases[i]; i++) { 1271 if (strchr(hp->h_aliases[i], '.') != 0) { 1272 name2 = hp->h_aliases[i]; 1273 break; 1274 } 1275 } 1276 /* Give up, just use the first name (h_name == 1277 h_aliases[0] on all systems I've seen). */ 1278 if (hp->h_aliases[i] == 0) 1279 name2 = hp->h_name; 1280 } 1281 1282 ai->ai_canonname = strdup(name2); 1283 if (name2 != 0 && ai->ai_canonname == 0) { 1284 system_freeaddrinfo(ai); 1285 *result = 0; 1286 #ifdef DEBUG_ADDRINFO 1287 debug_dump_error(EAI_MEMORY); 1288 #endif 1289 return EAI_MEMORY; 1290 } 1291 /* Zap the remaining ai_canonname fields glibc fills in, in 1292 case the application messes around with the list 1293 structure. */ 1294 while ((ai = ai->ai_next) != NULL) 1295 ai->ai_canonname = 0; 1296 } 1297 #endif 1298 1299 #ifdef NUMERIC_SERVICE_BROKEN 1300 if (service_port != 0) { 1301 for (ai = *result; ai; ai = ai->ai_next) { 1302 if (socket_type != 0 && ai->ai_socktype == 0) 1303 /* Is this check actually needed? */ 1304 ai->ai_socktype = socket_type; 1305 switch (ai->ai_family) { 1306 case AF_INET: 1307 ((struct sockaddr_in *)ai->ai_addr)->sin_port = service_port; 1308 break; 1309 case AF_INET6: 1310 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = service_port; 1311 break; 1312 } 1313 } 1314 } 1315 #endif 1316 1317 #ifdef _AIX 1318 for (ai = *result; ai; ai = ai->ai_next) { 1319 /* AIX 4.3.3 libc is broken. It doesn't set the family or len 1320 fields of the sockaddr structures. Usually, sa_family is 1321 zero, but I've seen it set to 1 in some cases also (maybe 1322 just leftover from previous contents of the memory 1323 block?). So, always override what libc returned. */ 1324 ai->ai_addr->sa_family = ai->ai_family; 1325 #ifdef HAVE_SA_LEN /* always true on AIX, actually */ 1326 ai->ai_addr->sa_len = ai->ai_addrlen; 1327 #endif 1328 } 1329 #endif 1330 1331 /* Not dealt with currently: 1332 1333 - Some versions of GNU libc can lose some IPv4 addresses in 1334 certain cases when multiple IPv4 and IPv6 addresses are 1335 available. */ 1336 1337 #ifdef DEBUG_ADDRINFO 1338 debug_dump_addrinfos(*result); 1339 #endif 1340 1341 return 0; 1342 } 1343 1344 static inline 1345 void freeaddrinfo (struct addrinfo *ai) 1346 { 1347 #ifdef COPY_FIRST_CANONNAME 1348 if (ai) { 1349 free(ai->ai_canonname); 1350 ai->ai_canonname = 0; 1351 system_freeaddrinfo(ai); 1352 } 1353 #else 1354 system_freeaddrinfo(ai); 1355 #endif 1356 } 1357 #endif /* WRAP_GETADDRINFO */ 1358 1359 #if defined(KRB5_USE_INET6) && defined(NEED_INSIXADDR_ANY) 1360 /* If compiling with IPv6 support and C library does not define in6addr_any */ 1361 #undef in6addr_any 1362 #define in6addr_any krb5int_in6addr_any 1363 static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 1364 #endif 1365 1366 #ifdef ADDRINFO_UNDEF_INLINE 1367 # undef inline 1368 # undef ADDRINFO_UNDEF_INLINE 1369 #endif 1370 1371 #endif /* FAI_DEFINED */ 1372