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>
21 /* Thread safe DNS lookups */
22 /* TODO There are some systems that use the same hostent structure
23 to return for gethostbyname() & gethostbyaddr(), if that is the
24 case then use only one mutex instead of seperate mutexes
26 static int lrad_hostbyname = 0;
27 static int lrad_hodtbyaddr = 0;
28 static pthread_mutex_t lrad_hostbyname_mutex;
29 static pthread_mutex_t lrad_hodtbyaddr_mutex;
32 #ifndef GETHOSTBYNAMERSTYLE
33 #define LOCAL_GETHOSTBYNAMERSTYLE 1
34 #elif (GETHOSTBYNAMERSTYLE != SYSVSTYLE) && (GETHOSTBYNAMERSTYLE != GNUSTYLE)
35 #define LOCAL_GETHOSTBYNAMERSTYLE 1
36 #endif /* GETHOSTBYNAMERSTYLE */
38 #ifndef GETHOSTBYADDRRSTYLE
39 #define LOCAL_GETHOSTBYADDRR 1
40 #elif (GETHOSTBYADDRRSTYLE != SYSVSTYLE) && (GETHOSTBYADDRRSTYLE != GNUSTYLE)
41 #define LOCAL_GETHOSTBYADDRR 1
42 #endif /* GETHOSTBYADDRRSTYLE */
45 * gethostbyaddr() & gethostbyname() return hostent structure
46 * To make these functions thread safe, we need to
47 * copy the data and not pointers
50 * char *h_name; * official name of host *
51 * char **h_aliases; * alias list *
52 * int h_addrtype; * host address type *
53 * int h_length; * length of address *
54 * char **h_addr_list; * list of addresses *
56 * This struct contains 3 pointers as members.
57 * The data from these pointers is copied into a buffer.
58 * The buffer is formatted as below to store the data
59 * ---------------------------------------------------------------
60 * | h_name\0alias_array\0h_aliases\0..\0addr_array\0h_addr_list\0 |
61 * ---------------------------------------------------------------
63 #if (LOCAL_GETHOSTBYNAMER == 1) || (LOCAL_GETHOSTBYADDRR == 1)
64 #define BUFFER_OVERFLOW 255
65 int copy_hostent(struct hostent *from, struct hostent *to,
66 char *buffer, int buflen, int *error)
72 to->h_addrtype = from->h_addrtype;
73 to->h_length = from->h_length;
74 to->h_name = (char *)ptr;
76 /* copy hostname to buffer */
77 len=strlen(from->h_name)+1;
78 strcpy(ptr, from->h_name);
81 /* copy aliases to buffer */
82 to->h_aliases = (char**)ptr;
83 for(i = 0; from->h_aliases[i]; i++);
84 ptr += (i+1) * sizeof(char *);
86 for(i = 0; from->h_aliases[i]; i++) {
87 len = strlen(from->h_aliases[i])+1;
88 if ((ptr-buffer)+len < buflen) {
89 to->h_aliases[i] = ptr;
90 strcpy(ptr, from->h_aliases[i]);
93 *error = BUFFER_OVERFLOW;
97 to->h_aliases[i] = NULL;
99 /* copy addr_list to buffer */
100 to->h_addr_list = (char**)ptr;
101 for(i = 0; (int *)from->h_addr_list[i] != 0; i++);
102 ptr += (i+1) * sizeof(int *);
104 for(i = 0; (int *)from->h_addr_list[i] != 0; i++) {
106 if ((ptr-buffer)+len < buflen) {
107 to->h_addr_list[i] = ptr;
108 memcpy(ptr, from->h_addr_list[i], len);
111 *error = BUFFER_OVERFLOW;
115 to->h_addr_list[i] = 0;
118 #endif /* (LOCAL_GETHOSTBYNAMER == 1) || (LOCAL_GETHOSTBYADDRR == 1) */
120 #ifdef LOCAL_GETHOSTBYNAMERSTYLE
121 static struct hostent *
122 gethostbyname_r(const char *hostname, struct hostent *result,
123 char *buffer, int buflen, int *error)
127 #ifdef HAVE_PTHREAD_H
128 if (lrad_hostbyname == 0) {
129 pthread_mutex_init(&lrad_hostbyname_mutex, NULL);
132 pthread_mutex_lock(&lrad_hostbyname_mutex);
135 hp = gethostbyname(name);
136 if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
140 copy_hostent(hp, result, buffer, buflen, error);
144 #ifdef HAVE_PTHREAD_H
145 pthread_mutex_unlock(&lrad_hostbyname_mutex);
150 #endif /* GETHOSTBYNAMERSTYLE */
153 #ifdef LOCAL_GETHOSTBYADDRRSTYLE
154 static struct hostent *
155 gethostbyaddr_r(const char *addr, int len, int type, struct hostent *result,
156 char *buffer, int buflen, int *error)
160 #ifdef HAVE_PTHREAD_H
161 if (lrad_hodtbyaddr == 0) {
162 pthread_mutex_init(&lrad_hodtbyaddr_mutex, NULL);
165 pthread_mutex_lock(&lrad_hodtbyaddr_mutex);
168 hp = gethostbyaddr(addr, len, type);
169 if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
173 copy_hostent(hp, result, buffer, buflen, error);
177 #ifdef HAVE_PTHREAD_H
178 pthread_mutex_unlock(&lrad_hodtbyaddr_mutex);
183 #endif /* GETHOSTBYADDRRSTYLE */
186 * Mar 8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
188 * Below code is based on ssh-1.2.27-IPv6-1.5 written by
189 * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
192 #ifndef HAVE_GETADDRINFO
193 static struct addrinfo *
194 malloc_ai(int port, u_long addr, int socktype, int proto)
198 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) +
199 sizeof(struct sockaddr_in));
201 memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
202 ai->ai_addr = (struct sockaddr *)(ai + 1);
203 ai->ai_addrlen = sizeof(struct sockaddr_in);
204 #ifdef HAVE_SOCKADDR_SA_LEN
205 ai->ai_addr->sa_len = sizeof(struct sockaddr_in);
207 ai->ai_addr->sa_family = ai->ai_family = AF_INET;
208 ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
209 ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
210 ai->ai_socktype = socktype;
211 ai->ai_protocol = proto;
219 gai_strerror(int ecode)
223 return "memory allocation failure.";
225 return "ai_family not supported.";
227 return "hostname nor servname provided, or not known.";
229 return "servname not supported for ai_socktype.";
231 return "unknown error.";
236 freeaddrinfo(struct addrinfo *ai)
238 struct addrinfo *next;
240 if (ai->ai_canonname)
241 free(ai->ai_canonname);
245 } while ((ai = next) != NULL);
249 getaddrinfo(const char *hostname, const char *servname,
250 const struct addrinfo *hints, struct addrinfo **res)
252 struct addrinfo *cur, *prev = NULL;
254 struct hostent result;
256 int i, port = 0, socktype, proto;
260 if (hints && hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC)
263 socktype = (hints && hints->ai_socktype) ? hints->ai_socktype
265 if (hints && hints->ai_protocol)
266 proto = hints->ai_protocol;
281 if (isdigit((int)*servname))
282 port = htons(atoi(servname));
298 if ((se = getservbyname(servname, pe_proto)) == NULL)
304 if (hints && hints->ai_flags & AI_PASSIVE)
305 *res = malloc_ai(port, htonl(0x00000000), socktype, proto);
307 *res = malloc_ai(port, htonl(0x7f000001), socktype, proto);
313 /* Numeric IP Address */
314 if (inet_aton(hostname, &in)) {
315 *res = malloc_ai(port, in.s_addr, socktype, proto);
321 if (hints && hints->ai_flags & AI_NUMERICHOST)
325 #ifdef GETHOSTBYNAMERSTYLE
326 #if GETHOSTBYNAMERSTYLE == SYSVSTYLE
327 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
328 #elif GETHOSTBYNAMERSTYLE == GNUSTYLE
329 if (gethostbyname_r(hostname, &result, buffer,
330 sizeof(buffer), &hp, &error) != 0) {
334 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
337 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
339 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
340 for (i = 0; hp->h_addr_list[i]; i++) {
341 if ((cur = malloc_ai(port,
342 ((struct in_addr *)hp->h_addr_list[i])->s_addr,
343 socktype, proto)) == NULL) {
354 if (hints && hints->ai_flags & AI_CANONNAME && *res) {
355 if (((*res)->ai_canonname = strdup(hp->h_name)) == NULL) {
364 #endif /* HAVE_GETADDRINFO */
367 #ifndef HAVE_GETNAMEINFO
369 getnameinfo(const struct sockaddr *sa, socklen_t salen,
370 char *host, size_t hostlen,
371 char *serv, size_t servlen,
374 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
376 struct hostent result;
382 snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
383 if (strlen(tmpserv) > servlen)
386 strcpy(serv, tmpserv);
389 if (flags & NI_NUMERICHOST) {
390 /* No Reverse DNS lookup */
391 if (flags & NI_NAMEREQD)
393 if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
396 strcpy(host, inet_ntoa(sin->sin_addr));
400 /* Reverse DNS lookup required */
401 #ifdef GETHOSTBYADDRRSTYLE
402 #if GETHOSTBYADDRRSTYLE == SYSVSTYLE
403 hp = gethostbyaddr_r((char *)&sin->sin_addr,
404 sizeof(struct in_addr), AF_INET,
405 &result, buffer, sizeof(buffer), &error);
406 #elif GETHOSTBYADDRRSTYLE == GNUSTYLE
407 if (gethostbyaddr_r((char *)&sin->sin_addr,
408 sizeof(struct in_addr), AF_INET,
409 &result, buffer, sizeof(buffer),
414 hp = gethostbyaddr_r((char *)&sin->sin_addr,
415 sizeof(struct in_addr), AF_INET,
416 &result, buffer, sizeof(buffer), &error);
419 hp = gethostbyaddr_r((char *)&sin->sin_addr,
420 sizeof(struct in_addr), AF_INET,
421 &result, buffer, sizeof(buffer), &error);
424 if (strlen(hp->h_name) >= hostlen)
427 strcpy(host, hp->h_name);
430 else if (flags & NI_NAMEREQD)
432 else if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
435 strcpy(host, inet_ntoa(sin->sin_addr));
442 #endif /* HAVE_GETNAMEINFO */