2 * These functions are defined and used only if the configure
3 * cannot detect the standard getaddrinfo(), freeaddrinfo(),
4 * gai_strerror() and getnameinfo(). This avoids sprinkling of ifdefs.
6 * FIXME: getaddrinfo() & getnameinfo() should
7 * return all IPv4 addresses provided by DNS lookup.
10 #include <freeradius-devel/ident.h>
13 #include <freeradius-devel/libradius.h>
16 #include <sys/param.h>
22 /* Thread safe DNS lookups */
24 * FIXME: There are some systems that use the same hostent
25 * structure to return for gethostbyname() & gethostbyaddr(), if
26 * that is the case then use only one mutex instead of separate
29 static int fr_hostbyname = 0;
30 static int fr_hodtbyaddr = 0;
31 static pthread_mutex_t fr_hostbyname_mutex;
32 static pthread_mutex_t fr_hodtbyaddr_mutex;
36 #undef LOCAL_GETHOSTBYNAMERSTYLE
37 #ifndef GETHOSTBYNAMERSTYLE
38 #define LOCAL_GETHOSTBYNAMERSTYLE 1
39 #elif (GETHOSTBYNAMERSTYLE != SYSVSTYLE) && (GETHOSTBYNAMERSTYLE != GNUSTYLE)
40 #define LOCAL_GETHOSTBYNAMERSTYLE 1
41 #endif /* GETHOSTBYNAMERSTYLE */
43 #undef LOCAL_GETHOSTBYADDRR
44 #ifndef GETHOSTBYADDRRSTYLE
45 #define LOCAL_GETHOSTBYADDRR 1
46 #elif (GETHOSTBYADDRRSTYLE != SYSVSTYLE) && (GETHOSTBYADDRRSTYLE != GNUSTYLE)
47 #define LOCAL_GETHOSTBYADDRR 1
48 #endif /* GETHOSTBYADDRRSTYLE */
51 * gethostbyaddr() & gethostbyname() return hostent structure
52 * To make these functions thread safe, we need to
53 * copy the data and not pointers
56 * char *h_name; * official name of host *
57 * char **h_aliases; * alias list *
58 * int h_addrtype; * host address type *
59 * int h_length; * length of address *
60 * char **h_addr_list; * list of addresses *
62 * This struct contains 3 pointers as members.
63 * The data from these pointers is copied into a buffer.
64 * The buffer is formatted as below to store the data
65 * ---------------------------------------------------------------
66 * | h_name\0alias_array\0h_aliases\0..\0addr_array\0h_addr_list\0 |
67 * ---------------------------------------------------------------
69 #if defined(LOCAL_GETHOSTBYNAMER) || defined(LOCAL_GETHOSTBYADDRR)
70 #define BUFFER_OVERFLOW 255
71 static int copy_hostent(struct hostent *from, struct hostent *to,
72 char *buffer, int buflen, int *error)
78 to->h_addrtype = from->h_addrtype;
79 to->h_length = from->h_length;
80 to->h_name = (char *)ptr;
82 /* copy hostname to buffer */
83 len=strlen(from->h_name)+1;
84 strcpy(ptr, from->h_name);
87 /* copy aliases to buffer */
88 to->h_aliases = (char**)ptr;
89 for(i = 0; from->h_aliases[i]; i++);
90 ptr += (i+1) * sizeof(char *);
92 for(i = 0; from->h_aliases[i]; i++) {
93 len = strlen(from->h_aliases[i])+1;
94 if ((ptr-buffer)+len < buflen) {
95 to->h_aliases[i] = ptr;
96 strcpy(ptr, from->h_aliases[i]);
99 *error = BUFFER_OVERFLOW;
103 to->h_aliases[i] = NULL;
105 /* copy addr_list to buffer */
106 to->h_addr_list = (char**)ptr;
107 for(i = 0; (int *)from->h_addr_list[i] != 0; i++);
108 ptr += (i+1) * sizeof(int *);
110 for(i = 0; (int *)from->h_addr_list[i] != 0; i++) {
112 if ((ptr-buffer)+len < buflen) {
113 to->h_addr_list[i] = ptr;
114 memcpy(ptr, from->h_addr_list[i], len);
117 *error = BUFFER_OVERFLOW;
121 to->h_addr_list[i] = 0;
124 #endif /* (LOCAL_GETHOSTBYNAMER == 1) || (LOCAL_GETHOSTBYADDRR == 1) */
126 #ifdef LOCAL_GETHOSTBYNAMERSTYLE
127 static struct hostent *
128 gethostbyname_r(const char *hostname, struct hostent *result,
129 char *buffer, int buflen, int *error)
133 #ifdef HAVE_PTHREAD_H
134 if (fr_hostbyname == 0) {
135 pthread_mutex_init(&fr_hostbyname_mutex, NULL);
138 pthread_mutex_lock(&fr_hostbyname_mutex);
141 hp = gethostbyname(hostname);
142 if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
146 copy_hostent(hp, result, buffer, buflen, error);
150 #ifdef HAVE_PTHREAD_H
151 pthread_mutex_unlock(&fr_hostbyname_mutex);
156 #endif /* GETHOSTBYNAMERSTYLE */
159 #ifdef LOCAL_GETHOSTBYADDRR
160 static struct hostent *
161 gethostbyaddr_r(const char *addr, int len, int type, struct hostent *result,
162 char *buffer, int buflen, int *error)
166 #ifdef HAVE_PTHREAD_H
167 if (fr_hodtbyaddr == 0) {
168 pthread_mutex_init(&fr_hodtbyaddr_mutex, NULL);
171 pthread_mutex_lock(&fr_hodtbyaddr_mutex);
174 hp = gethostbyaddr(addr, len, type);
175 if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
179 copy_hostent(hp, result, buffer, buflen, error);
183 #ifdef HAVE_PTHREAD_H
184 pthread_mutex_unlock(&fr_hodtbyaddr_mutex);
189 #endif /* GETHOSTBYADDRRSTYLE */
192 * Mar 8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
194 * Below code is based on ssh-1.2.27-IPv6-1.5 written by
195 * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
198 #ifndef HAVE_GETADDRINFO
199 static struct addrinfo *
200 malloc_ai(int port, u_long addr, int socktype, int proto)
204 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) +
205 sizeof(struct sockaddr_in));
207 memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
208 ai->ai_addr = (struct sockaddr *)(ai + 1);
209 ai->ai_addrlen = sizeof(struct sockaddr_in);
210 #ifdef HAVE_SOCKADDR_SA_LEN
211 ai->ai_addr->sa_len = sizeof(struct sockaddr_in);
213 ai->ai_addr->sa_family = ai->ai_family = AF_INET;
214 ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
215 ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
216 ai->ai_socktype = socktype;
217 ai->ai_protocol = proto;
225 gai_strerror(int ecode)
229 return "memory allocation failure.";
231 return "ai_family not supported.";
233 return "hostname nor servname provided, or not known.";
235 return "servname not supported for ai_socktype.";
237 return "unknown error.";
242 freeaddrinfo(struct addrinfo *ai)
244 struct addrinfo *next;
246 if (ai->ai_canonname)
247 free(ai->ai_canonname);
251 } while ((ai = next) != NULL);
255 getaddrinfo(const char *hostname, const char *servname,
256 const struct addrinfo *hints, struct addrinfo **res)
258 struct addrinfo *cur, *prev = NULL;
260 struct hostent result;
262 int i, port = 0, socktype, proto;
266 if (hints && hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC)
269 socktype = (hints && hints->ai_socktype) ? hints->ai_socktype
271 if (hints && hints->ai_protocol)
272 proto = hints->ai_protocol;
287 if (isdigit((int)*servname))
288 port = htons(atoi(servname));
291 const char *pe_proto;
304 if ((se = getservbyname(servname, pe_proto)) == NULL)
310 if (hints && hints->ai_flags & AI_PASSIVE)
311 *res = malloc_ai(port, htonl(0x00000000), socktype, proto);
313 *res = malloc_ai(port, htonl(0x7f000001), socktype, proto);
319 /* Numeric IP Address */
320 if (inet_aton(hostname, &in)) {
321 *res = malloc_ai(port, in.s_addr, socktype, proto);
327 if (hints && hints->ai_flags & AI_NUMERICHOST)
331 #ifdef GETHOSTBYNAMERSTYLE
332 #if GETHOSTBYNAMERSTYLE == SYSVSTYLE
333 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
334 #elif GETHOSTBYNAMERSTYLE == GNUSTYLE
335 if (gethostbyname_r(hostname, &result, buffer,
336 sizeof(buffer), &hp, &error) != 0) {
340 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
343 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
345 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
346 for (i = 0; hp->h_addr_list[i]; i++) {
347 if ((cur = malloc_ai(port,
348 ((struct in_addr *)hp->h_addr_list[i])->s_addr,
349 socktype, proto)) == NULL) {
360 if (hints && hints->ai_flags & AI_CANONNAME && *res) {
361 if (((*res)->ai_canonname = strdup(hp->h_name)) == NULL) {
370 #endif /* HAVE_GETADDRINFO */
373 #ifndef HAVE_GETNAMEINFO
375 getnameinfo(const struct sockaddr *sa, socklen_t salen,
376 char *host, size_t hostlen,
377 char *serv, size_t servlen,
380 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
382 struct hostent result;
388 snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
389 if (strlen(tmpserv) > servlen)
392 strcpy(serv, tmpserv);
395 if (flags & NI_NUMERICHOST) {
396 /* No Reverse DNS lookup */
397 if (flags & NI_NAMEREQD)
399 if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
402 strcpy(host, inet_ntoa(sin->sin_addr));
406 /* Reverse DNS lookup required */
407 #ifdef GETHOSTBYADDRRSTYLE
408 #if GETHOSTBYADDRRSTYLE == SYSVSTYLE
409 hp = gethostbyaddr_r((const char *)&sin->sin_addr,
411 &result, buffer, sizeof(buffer), &error);
412 #elif GETHOSTBYADDRRSTYLE == GNUSTYLE
413 if (gethostbyaddr_r((const char *)&sin->sin_addr,
415 &result, buffer, sizeof(buffer),
420 hp = gethostbyaddr_r((const char *)&sin->sin_addr,
422 &result, buffer, sizeof(buffer), &error);
425 hp = gethostbyaddr_r((const char *)&sin->sin_addr,
427 &result, buffer, sizeof(buffer), &error);
430 if (strlen(hp->h_name) >= hostlen)
433 strcpy(host, hp->h_name);
436 else if (flags & NI_NAMEREQD)
438 else if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
441 strcpy(host, inet_ntoa(sin->sin_addr));
448 #endif /* HAVE_GETNAMEINFO */