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