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>
18 #ifndef HAVE_GETNAMEINFO
19 #undef LOCAL_GETHOSTBYNAMERSTYLE
20 #ifndef GETHOSTBYNAMERSTYLE
21 #define LOCAL_GETHOSTBYNAMERSTYLE 1
22 #elif (GETHOSTBYNAMERSTYLE != SYSVSTYLE) && (GETHOSTBYNAMERSTYLE != GNUSTYLE)
23 #define LOCAL_GETHOSTBYNAMERSTYLE 1
24 #endif /* GETHOSTBYNAMERSTYLE */
27 #ifndef HAVE_GETADDRINFO
28 #undef LOCAL_GETHOSTBYADDRR
29 #ifndef GETHOSTBYADDRRSTYLE
30 #define LOCAL_GETHOSTBYADDRR 1
31 #elif (GETHOSTBYADDRRSTYLE != SYSVSTYLE) && (GETHOSTBYADDRRSTYLE != GNUSTYLE)
32 #define LOCAL_GETHOSTBYADDRR 1
33 #endif /* GETHOSTBYADDRRSTYLE */
39 /* Thread safe DNS lookups */
41 * FIXME: There are some systems that use the same hostent
42 * structure to return for gethostbyname() & gethostbyaddr(), if
43 * that is the case then use only one mutex instead of separate
46 #ifdef LOCAL_GETHOSTBYNAMERSTYLE
47 static int fr_hostbyname = 0;
48 static pthread_mutex_t fr_hostbyname_mutex;
51 #ifdef LOCAL_GETHOSTBYNAMERSTYLE
52 static int fr_hostbyaddr = 0;
53 static pthread_mutex_t fr_hostbyaddr_mutex;
59 * gethostbyaddr() & gethostbyname() return hostent structure
60 * To make these functions thread safe, we need to
61 * copy the data and not pointers
64 * char *h_name; * official name of host *
65 * char **h_aliases; * alias list *
66 * int h_addrtype; * host address type *
67 * int h_length; * length of address *
68 * char **h_addr_list; * list of addresses *
70 * This struct contains 3 pointers as members.
71 * The data from these pointers is copied into a buffer.
72 * The buffer is formatted as below to store the data
73 * ---------------------------------------------------------------
74 * | h_name\0alias_array\0h_aliases\0..\0addr_array\0h_addr_list\0 |
75 * ---------------------------------------------------------------
77 #if defined(LOCAL_GETHOSTBYNAMER) || defined(LOCAL_GETHOSTBYADDRR)
78 #define BUFFER_OVERFLOW 255
79 static int copy_hostent(struct hostent *from, struct hostent *to,
80 char *buffer, int buflen, int *error)
86 to->h_addrtype = from->h_addrtype;
87 to->h_length = from->h_length;
88 to->h_name = (char *)ptr;
90 /* copy hostname to buffer */
91 len=strlen(from->h_name)+1;
92 strcpy(ptr, from->h_name);
95 /* copy aliases to buffer */
96 to->h_aliases = (char**)ptr;
97 for(i = 0; from->h_aliases[i]; i++);
98 ptr += (i+1) * sizeof(char *);
100 for(i = 0; from->h_aliases[i]; i++) {
101 len = strlen(from->h_aliases[i])+1;
102 if ((ptr-buffer)+len < buflen) {
103 to->h_aliases[i] = ptr;
104 strcpy(ptr, from->h_aliases[i]);
107 *error = BUFFER_OVERFLOW;
111 to->h_aliases[i] = NULL;
113 /* copy addr_list to buffer */
114 to->h_addr_list = (char**)ptr;
115 for(i = 0; (int *)from->h_addr_list[i] != 0; i++);
116 ptr += (i+1) * sizeof(int *);
118 for(i = 0; (int *)from->h_addr_list[i] != 0; i++) {
120 if ((ptr-buffer)+len < buflen) {
121 to->h_addr_list[i] = ptr;
122 memcpy(ptr, from->h_addr_list[i], len);
125 *error = BUFFER_OVERFLOW;
129 to->h_addr_list[i] = 0;
132 #endif /* (LOCAL_GETHOSTBYNAMER == 1) || (LOCAL_GETHOSTBYADDRR == 1) */
134 #ifdef LOCAL_GETHOSTBYNAMERSTYLE
135 static struct hostent *
136 gethostbyname_r(const char *hostname, struct hostent *result,
137 char *buffer, int buflen, int *error)
141 #ifdef HAVE_PTHREAD_H
142 if (fr_hostbyname == 0) {
143 pthread_mutex_init(&fr_hostbyname_mutex, NULL);
146 pthread_mutex_lock(&fr_hostbyname_mutex);
149 hp = gethostbyname(hostname);
150 if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
154 copy_hostent(hp, result, buffer, buflen, error);
158 #ifdef HAVE_PTHREAD_H
159 pthread_mutex_unlock(&fr_hostbyname_mutex);
164 #endif /* GETHOSTBYNAMERSTYLE */
167 #ifdef LOCAL_GETHOSTBYADDRR
168 static struct hostent *
169 gethostbyaddr_r(const char *addr, int len, int type, struct hostent *result,
170 char *buffer, int buflen, int *error)
174 #ifdef HAVE_PTHREAD_H
175 if (fr_hostbyaddr == 0) {
176 pthread_mutex_init(&fr_hostbyaddr_mutex, NULL);
179 pthread_mutex_lock(&fr_hostbyaddr_mutex);
182 hp = gethostbyaddr(addr, len, type);
183 if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
187 copy_hostent(hp, result, buffer, buflen, error);
191 #ifdef HAVE_PTHREAD_H
192 pthread_mutex_unlock(&fr_hostbyaddr_mutex);
197 #endif /* GETHOSTBYADDRRSTYLE */
200 * Mar 8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
202 * Below code is based on ssh-1.2.27-IPv6-1.5 written by
203 * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
206 #ifndef HAVE_GETADDRINFO
207 static struct addrinfo *
208 malloc_ai(int port, u_long addr, int socktype, int proto)
212 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) +
213 sizeof(struct sockaddr_in));
215 memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
216 ai->ai_addr = (struct sockaddr *)(ai + 1);
217 ai->ai_addrlen = sizeof(struct sockaddr_in);
218 #ifdef HAVE_SOCKADDR_SA_LEN
219 ai->ai_addr->sa_len = sizeof(struct sockaddr_in);
221 ai->ai_addr->sa_family = ai->ai_family = AF_INET;
222 ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
223 ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
224 ai->ai_socktype = socktype;
225 ai->ai_protocol = proto;
233 gai_strerror(int ecode)
237 return "memory allocation failure.";
239 return "ai_family not supported.";
241 return "hostname nor servname provided, or not known.";
243 return "servname not supported for ai_socktype.";
245 return "unknown error.";
250 freeaddrinfo(struct addrinfo *ai)
252 struct addrinfo *next;
254 if (ai->ai_canonname)
255 free(ai->ai_canonname);
259 } while ((ai = next) != NULL);
263 getaddrinfo(const char *hostname, const char *servname,
264 const struct addrinfo *hints, struct addrinfo **res)
266 struct addrinfo *cur, *prev = NULL;
268 struct hostent result;
270 int i, port = 0, socktype, proto;
274 if (hints && hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC)
277 socktype = (hints && hints->ai_socktype) ? hints->ai_socktype
279 if (hints && hints->ai_protocol)
280 proto = hints->ai_protocol;
295 if (isdigit((int)*servname))
296 port = htons(atoi(servname));
299 const char *pe_proto;
312 if ((se = getservbyname(servname, pe_proto)) == NULL)
318 if (hints && hints->ai_flags & AI_PASSIVE)
319 *res = malloc_ai(port, htonl(0x00000000), socktype, proto);
321 *res = malloc_ai(port, htonl(0x7f000001), socktype, proto);
327 /* Numeric IP Address */
328 if (inet_aton(hostname, &in)) {
329 *res = malloc_ai(port, in.s_addr, socktype, proto);
335 if (hints && hints->ai_flags & AI_NUMERICHOST)
339 #ifdef GETHOSTBYNAMERSTYLE
340 #if GETHOSTBYNAMERSTYLE == SYSVSTYLE
341 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
342 #elif GETHOSTBYNAMERSTYLE == GNUSTYLE
343 if (gethostbyname_r(hostname, &result, buffer,
344 sizeof(buffer), &hp, &error) != 0) {
348 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
351 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
353 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
354 for (i = 0; hp->h_addr_list[i]; i++) {
355 if ((cur = malloc_ai(port,
356 ((struct in_addr *)hp->h_addr_list[i])->s_addr,
357 socktype, proto)) == NULL) {
368 if (hints && hints->ai_flags & AI_CANONNAME && *res) {
369 if (((*res)->ai_canonname = strdup(hp->h_name)) == NULL) {
378 #endif /* HAVE_GETADDRINFO */
381 #ifndef HAVE_GETNAMEINFO
383 getnameinfo(const struct sockaddr *sa, socklen_t salen,
384 char *host, size_t hostlen,
385 char *serv, size_t servlen,
388 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
390 struct hostent result;
396 snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
397 if (strlen(tmpserv) > servlen)
400 strcpy(serv, tmpserv);
403 if (flags & NI_NUMERICHOST) {
404 /* No Reverse DNS lookup */
405 if (flags & NI_NAMEREQD)
407 if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
410 strcpy(host, inet_ntoa(sin->sin_addr));
414 /* Reverse DNS lookup required */
415 #ifdef GETHOSTBYADDRRSTYLE
416 #if GETHOSTBYADDRRSTYLE == SYSVSTYLE
417 hp = gethostbyaddr_r((const char *)&sin->sin_addr,
419 &result, buffer, sizeof(buffer), &error);
420 #elif GETHOSTBYADDRRSTYLE == GNUSTYLE
421 if (gethostbyaddr_r((const char *)&sin->sin_addr,
423 &result, buffer, sizeof(buffer),
428 hp = gethostbyaddr_r((const char *)&sin->sin_addr,
430 &result, buffer, sizeof(buffer), &error);
433 hp = gethostbyaddr_r((const char *)&sin->sin_addr,
435 &result, buffer, sizeof(buffer), &error);
438 if (strlen(hp->h_name) >= hostlen)
441 strcpy(host, hp->h_name);
444 else if (flags & NI_NAMEREQD)
446 else if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
449 strcpy(host, inet_ntoa(sin->sin_addr));
456 #endif /* HAVE_GETNAMEINFO */