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/autoconf.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
21 #include <sys/param.h>
23 #include <freeradius-devel/missing.h>
28 /* Thread safe DNS lookups */
29 /* TODO There are some systems that use the same hostent structure
30 to return for gethostbyname() & gethostbyaddr(), if that is the
31 case then use only one mutex instead of seperate mutexes
33 static int lrad_hostbyname = 0;
34 static int lrad_hodtbyaddr = 0;
35 static pthread_mutex_t lrad_hostbyname_mutex;
36 static pthread_mutex_t lrad_hodtbyaddr_mutex;
39 #ifndef GETHOSTBYNAMERSTYLE
40 #define LOCAL_GETHOSTBYNAMERSTYLE 1
41 #elif (GETHOSTBYNAMERSTYLE != SYSVSTYLE) && (GETHOSTBYNAMERSTYLE != GNUSTYLE)
42 #define LOCAL_GETHOSTBYNAMERSTYLE 1
43 #endif /* GETHOSTBYNAMERSTYLE */
45 #ifndef GETHOSTBYADDRRSTYLE
46 #define LOCAL_GETHOSTBYADDRR 1
47 #elif (GETHOSTBYADDRRSTYLE != SYSVSTYLE) && (GETHOSTBYADDRRSTYLE != GNUSTYLE)
48 #define LOCAL_GETHOSTBYADDRR 1
49 #endif /* GETHOSTBYADDRRSTYLE */
52 * gethostbyaddr() & gethostbyname() return hostent structure
53 * To make these functions thread safe, we need to
54 * copy the data and not pointers
57 * char *h_name; * official name of host *
58 * char **h_aliases; * alias list *
59 * int h_addrtype; * host address type *
60 * int h_length; * length of address *
61 * char **h_addr_list; * list of addresses *
63 * This struct contains 3 pointers as members.
64 * The data from these pointers is copied into a buffer.
65 * The buffer is formatted as below to store the data
66 * ---------------------------------------------------------------
67 * | h_name\0alias_array\0h_aliases\0..\0addr_array\0h_addr_list\0 |
68 * ---------------------------------------------------------------
70 #if (LOCAL_GETHOSTBYNAMER == 1) || (LOCAL_GETHOSTBYADDRR == 1)
71 #define BUFFER_OVERFLOW 255
72 int copy_hostent(struct hostent *from, struct hostent *to,
73 char *buffer, int buflen, int *error)
79 to->h_addrtype = from->h_addrtype;
80 to->h_length = from->h_length;
81 to->h_name = (char *)ptr;
83 /* copy hostname to buffer */
84 len=strlen(from->h_name)+1;
85 strcpy(ptr, from->h_name);
88 /* copy aliases to buffer */
89 to->h_aliases = (char**)ptr;
90 for(i = 0; from->h_aliases[i]; i++);
91 ptr += (i+1) * sizeof(char *);
93 for(i = 0; from->h_aliases[i]; i++) {
94 len = strlen(from->h_aliases[i])+1;
95 if ((ptr-buffer)+len < buflen) {
96 to->h_aliases[i] = ptr;
97 strcpy(ptr, from->h_aliases[i]);
100 *error = BUFFER_OVERFLOW;
104 to->h_aliases[i] = NULL;
106 /* copy addr_list to buffer */
107 to->h_addr_list = (char**)ptr;
108 for(i = 0; (int *)from->h_addr_list[i] != 0; i++);
109 ptr += (i+1) * sizeof(int *);
111 for(i = 0; (int *)from->h_addr_list[i] != 0; i++) {
113 if ((ptr-buffer)+len < buflen) {
114 to->h_addr_list[i] = ptr;
115 memcpy(ptr, from->h_addr_list[i], len);
118 *error = BUFFER_OVERFLOW;
122 to->h_addr_list[i] = 0;
125 #endif /* (LOCAL_GETHOSTBYNAMER == 1) || (LOCAL_GETHOSTBYADDRR == 1) */
127 #ifdef LOCAL_GETHOSTBYNAMERSTYLE
128 static struct hostent *
129 gethostbyname_r(const char *hostname, struct hostent *result,
130 char *buffer, int buflen, int *error)
134 #ifdef HAVE_PTHREAD_H
135 if (lrad_hostbyname == 0) {
136 pthread_mutex_init(&lrad_hostbyname_mutex, NULL);
139 pthread_mutex_lock(&lrad_hostbyname_mutex);
142 hp = gethostbyname(name);
143 if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
147 copy_hostent(hp, result, buffer, buflen, error);
151 #ifdef HAVE_PTHREAD_H
152 pthread_mutex_unlock(&lrad_hostbyname_mutex);
157 #endif /* GETHOSTBYNAMERSTYLE */
160 #ifdef LOCAL_GETHOSTBYADDRRSTYLE
161 static struct hostent *
162 gethostbyaddr_r(const char *addr, int len, int type, struct hostent *result,
163 char *buffer, int buflen, int *error)
167 #ifdef HAVE_PTHREAD_H
168 if (lrad_hodtbyaddr == 0) {
169 pthread_mutex_init(&lrad_hodtbyaddr_mutex, NULL);
172 pthread_mutex_lock(&lrad_hodtbyaddr_mutex);
175 hp = gethostbyaddr(addr, len, type);
176 if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
180 copy_hostent(hp, result, buffer, buflen, error);
184 #ifdef HAVE_PTHREAD_H
185 pthread_mutex_unlock(&lrad_hodtbyaddr_mutex);
190 #endif /* GETHOSTBYADDRRSTYLE */
193 * Mar 8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
195 * Below code is based on ssh-1.2.27-IPv6-1.5 written by
196 * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
199 #ifndef HAVE_GETADDRINFO
200 static struct addrinfo *
201 malloc_ai(int port, u_long addr, int socktype, int proto)
205 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) +
206 sizeof(struct sockaddr_in));
208 memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
209 ai->ai_addr = (struct sockaddr *)(ai + 1);
210 ai->ai_addrlen = sizeof(struct sockaddr_in);
211 #ifdef HAVE_SOCKADDR_SA_LEN
212 ai->ai_addr->sa_len = sizeof(struct sockaddr_in);
214 ai->ai_addr->sa_family = ai->ai_family = AF_INET;
215 ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
216 ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
217 ai->ai_socktype = socktype;
218 ai->ai_protocol = proto;
226 gai_strerror(int ecode)
230 return "memory allocation failure.";
232 return "ai_family not supported.";
234 return "hostname nor servname provided, or not known.";
236 return "servname not supported for ai_socktype.";
238 return "unknown error.";
243 freeaddrinfo(struct addrinfo *ai)
245 struct addrinfo *next;
247 if (ai->ai_canonname)
248 free(ai->ai_canonname);
252 } while ((ai = next) != NULL);
256 getaddrinfo(const char *hostname, const char *servname,
257 const struct addrinfo *hints, struct addrinfo **res)
259 struct addrinfo *cur, *prev = NULL;
261 struct hostent result;
263 int i, port = 0, socktype, proto;
267 if (hints && hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC)
270 socktype = (hints && hints->ai_socktype) ? hints->ai_socktype
272 if (hints && hints->ai_protocol)
273 proto = hints->ai_protocol;
288 if (isdigit((int)*servname))
289 port = htons(atoi(servname));
305 if ((se = getservbyname(servname, pe_proto)) == NULL)
311 if (hints && hints->ai_flags & AI_PASSIVE)
312 *res = malloc_ai(port, htonl(0x00000000), socktype, proto);
314 *res = malloc_ai(port, htonl(0x7f000001), socktype, proto);
320 /* Numeric IP Address */
321 if (inet_aton(hostname, &in)) {
322 *res = malloc_ai(port, in.s_addr, socktype, proto);
328 if (hints && hints->ai_flags & AI_NUMERICHOST)
332 #ifdef GETHOSTBYNAMERSTYLE
333 #if GETHOSTBYNAMERSTYLE == SYSVSTYLE
334 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
335 #elif GETHOSTBYNAMERSTYLE == GNUSTYLE
336 if (gethostbyname_r(hostname, &result, buffer,
337 sizeof(buffer), &hp, &error) != 0) {
341 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
344 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
346 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
347 for (i = 0; hp->h_addr_list[i]; i++) {
348 if ((cur = malloc_ai(port,
349 ((struct in_addr *)hp->h_addr_list[i])->s_addr,
350 socktype, proto)) == NULL) {
361 if (hints && hints->ai_flags & AI_CANONNAME && *res) {
362 if (((*res)->ai_canonname = strdup(hp->h_name)) == NULL) {
371 #endif /* HAVE_GETADDRINFO */
374 #ifndef HAVE_GETNAMEINFO
376 getnameinfo(const struct sockaddr *sa, socklen_t salen,
377 char *host, size_t hostlen,
378 char *serv, size_t servlen,
381 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
383 struct hostent result;
389 snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
390 if (strlen(tmpserv) > servlen)
393 strcpy(serv, tmpserv);
396 if (flags & NI_NUMERICHOST) {
397 /* No Reverse DNS lookup */
398 if (flags & NI_NAMEREQD)
400 if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
403 strcpy(host, inet_ntoa(sin->sin_addr));
407 /* Reverse DNS lookup required */
408 #ifdef GETHOSTBYADDRRSTYLE
409 #if GETHOSTBYADDRRSTYLE == SYSVSTYLE
410 hp = gethostbyaddr_r((char *)&sin->sin_addr,
411 sizeof(struct in_addr), AF_INET,
412 &result, buffer, sizeof(buffer), &error);
413 #elif GETHOSTBYADDRRSTYLE == GNUSTYLE
414 if (gethostbyaddr_r((char *)&sin->sin_addr,
415 sizeof(struct in_addr), AF_INET,
416 &result, buffer, sizeof(buffer),
421 hp = gethostbyaddr_r((char *)&sin->sin_addr,
422 sizeof(struct in_addr), AF_INET,
423 &result, buffer, sizeof(buffer), &error);
426 hp = gethostbyaddr_r((char *)&sin->sin_addr,
427 sizeof(struct in_addr), AF_INET,
428 &result, buffer, sizeof(buffer), &error);
431 if (strlen(hp->h_name) >= hostlen)
434 strcpy(host, hp->h_name);
437 else if (flags & NI_NAMEREQD)
439 else if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
442 strcpy(host, inet_ntoa(sin->sin_addr));
449 #endif /* HAVE_GETNAMEINFO */