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 #undef LOCAL_GETHOSTBYNAMERSTYLE
33 #ifndef GETHOSTBYNAMERSTYLE
34 #define LOCAL_GETHOSTBYNAMERSTYLE 1
35 #elif (GETHOSTBYNAMERSTYLE != SYSVSTYLE) && (GETHOSTBYNAMERSTYLE != GNUSTYLE)
36 #define LOCAL_GETHOSTBYNAMERSTYLE 1
37 #endif /* GETHOSTBYNAMERSTYLE */
39 #undef LOCAL_GETHOSTBYADDRR
40 #ifndef GETHOSTBYADDRRSTYLE
41 #define LOCAL_GETHOSTBYADDRR 1
42 #elif (GETHOSTBYADDRRSTYLE != SYSVSTYLE) && (GETHOSTBYADDRRSTYLE != GNUSTYLE)
43 #define LOCAL_GETHOSTBYADDRR 1
44 #endif /* GETHOSTBYADDRRSTYLE */
47 * gethostbyaddr() & gethostbyname() return hostent structure
48 * To make these functions thread safe, we need to
49 * copy the data and not pointers
52 * char *h_name; * official name of host *
53 * char **h_aliases; * alias list *
54 * int h_addrtype; * host address type *
55 * int h_length; * length of address *
56 * char **h_addr_list; * list of addresses *
58 * This struct contains 3 pointers as members.
59 * The data from these pointers is copied into a buffer.
60 * The buffer is formatted as below to store the data
61 * ---------------------------------------------------------------
62 * | h_name\0alias_array\0h_aliases\0..\0addr_array\0h_addr_list\0 |
63 * ---------------------------------------------------------------
65 #if defined(LOCAL_GETHOSTBYNAMER) || defined(LOCAL_GETHOSTBYADDRR)
66 #define BUFFER_OVERFLOW 255
67 int copy_hostent(struct hostent *from, struct hostent *to,
68 char *buffer, int buflen, int *error)
74 to->h_addrtype = from->h_addrtype;
75 to->h_length = from->h_length;
76 to->h_name = (char *)ptr;
78 /* copy hostname to buffer */
79 len=strlen(from->h_name)+1;
80 strcpy(ptr, from->h_name);
83 /* copy aliases to buffer */
84 to->h_aliases = (char**)ptr;
85 for(i = 0; from->h_aliases[i]; i++);
86 ptr += (i+1) * sizeof(char *);
88 for(i = 0; from->h_aliases[i]; i++) {
89 len = strlen(from->h_aliases[i])+1;
90 if ((ptr-buffer)+len < buflen) {
91 to->h_aliases[i] = ptr;
92 strcpy(ptr, from->h_aliases[i]);
95 *error = BUFFER_OVERFLOW;
99 to->h_aliases[i] = NULL;
101 /* copy addr_list to buffer */
102 to->h_addr_list = (char**)ptr;
103 for(i = 0; (int *)from->h_addr_list[i] != 0; i++);
104 ptr += (i+1) * sizeof(int *);
106 for(i = 0; (int *)from->h_addr_list[i] != 0; i++) {
108 if ((ptr-buffer)+len < buflen) {
109 to->h_addr_list[i] = ptr;
110 memcpy(ptr, from->h_addr_list[i], len);
113 *error = BUFFER_OVERFLOW;
117 to->h_addr_list[i] = 0;
120 #endif /* (LOCAL_GETHOSTBYNAMER == 1) || (LOCAL_GETHOSTBYADDRR == 1) */
122 #ifdef LOCAL_GETHOSTBYNAMERSTYLE
123 static struct hostent *
124 gethostbyname_r(const char *hostname, struct hostent *result,
125 char *buffer, int buflen, int *error)
129 #ifdef HAVE_PTHREAD_H
130 if (lrad_hostbyname == 0) {
131 pthread_mutex_init(&lrad_hostbyname_mutex, NULL);
134 pthread_mutex_lock(&lrad_hostbyname_mutex);
137 hp = gethostbyname(hostname);
138 if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
142 copy_hostent(hp, result, buffer, buflen, error);
146 #ifdef HAVE_PTHREAD_H
147 pthread_mutex_unlock(&lrad_hostbyname_mutex);
152 #endif /* GETHOSTBYNAMERSTYLE */
155 #ifdef LOCAL_GETHOSTBYADDRR
156 static struct hostent *
157 gethostbyaddr_r(const char *addr, int len, int type, struct hostent *result,
158 char *buffer, int buflen, int *error)
162 #ifdef HAVE_PTHREAD_H
163 if (lrad_hodtbyaddr == 0) {
164 pthread_mutex_init(&lrad_hodtbyaddr_mutex, NULL);
167 pthread_mutex_lock(&lrad_hodtbyaddr_mutex);
170 hp = gethostbyaddr(addr, len, type);
171 if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
175 copy_hostent(hp, result, buffer, buflen, error);
179 #ifdef HAVE_PTHREAD_H
180 pthread_mutex_unlock(&lrad_hodtbyaddr_mutex);
185 #endif /* GETHOSTBYADDRRSTYLE */
188 * Mar 8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
190 * Below code is based on ssh-1.2.27-IPv6-1.5 written by
191 * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
194 #ifndef HAVE_GETADDRINFO
195 static struct addrinfo *
196 malloc_ai(int port, u_long addr, int socktype, int proto)
200 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) +
201 sizeof(struct sockaddr_in));
203 memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
204 ai->ai_addr = (struct sockaddr *)(ai + 1);
205 ai->ai_addrlen = sizeof(struct sockaddr_in);
206 #ifdef HAVE_SOCKADDR_SA_LEN
207 ai->ai_addr->sa_len = sizeof(struct sockaddr_in);
209 ai->ai_addr->sa_family = ai->ai_family = AF_INET;
210 ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
211 ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
212 ai->ai_socktype = socktype;
213 ai->ai_protocol = proto;
221 gai_strerror(int ecode)
225 return "memory allocation failure.";
227 return "ai_family not supported.";
229 return "hostname nor servname provided, or not known.";
231 return "servname not supported for ai_socktype.";
233 return "unknown error.";
238 freeaddrinfo(struct addrinfo *ai)
240 struct addrinfo *next;
242 if (ai->ai_canonname)
243 free(ai->ai_canonname);
247 } while ((ai = next) != NULL);
251 getaddrinfo(const char *hostname, const char *servname,
252 const struct addrinfo *hints, struct addrinfo **res)
254 struct addrinfo *cur, *prev = NULL;
256 struct hostent result;
258 int i, port = 0, socktype, proto;
262 if (hints && hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC)
265 socktype = (hints && hints->ai_socktype) ? hints->ai_socktype
267 if (hints && hints->ai_protocol)
268 proto = hints->ai_protocol;
283 if (isdigit((int)*servname))
284 port = htons(atoi(servname));
300 if ((se = getservbyname(servname, pe_proto)) == NULL)
306 if (hints && hints->ai_flags & AI_PASSIVE)
307 *res = malloc_ai(port, htonl(0x00000000), socktype, proto);
309 *res = malloc_ai(port, htonl(0x7f000001), socktype, proto);
315 /* Numeric IP Address */
316 if (inet_aton(hostname, &in)) {
317 *res = malloc_ai(port, in.s_addr, socktype, proto);
323 if (hints && hints->ai_flags & AI_NUMERICHOST)
327 #ifdef GETHOSTBYNAMERSTYLE
328 #if GETHOSTBYNAMERSTYLE == SYSVSTYLE
329 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
330 #elif GETHOSTBYNAMERSTYLE == GNUSTYLE
331 if (gethostbyname_r(hostname, &result, buffer,
332 sizeof(buffer), &hp, &error) != 0) {
336 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
339 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
341 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
342 for (i = 0; hp->h_addr_list[i]; i++) {
343 if ((cur = malloc_ai(port,
344 ((struct in_addr *)hp->h_addr_list[i])->s_addr,
345 socktype, proto)) == NULL) {
356 if (hints && hints->ai_flags & AI_CANONNAME && *res) {
357 if (((*res)->ai_canonname = strdup(hp->h_name)) == NULL) {
366 #endif /* HAVE_GETADDRINFO */
369 #ifndef HAVE_GETNAMEINFO
371 getnameinfo(const struct sockaddr *sa, socklen_t salen,
372 char *host, size_t hostlen,
373 char *serv, size_t servlen,
376 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
378 struct hostent result;
384 snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
385 if (strlen(tmpserv) > servlen)
388 strcpy(serv, tmpserv);
391 if (flags & NI_NUMERICHOST) {
392 /* No Reverse DNS lookup */
393 if (flags & NI_NAMEREQD)
395 if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
398 strcpy(host, inet_ntoa(sin->sin_addr));
402 /* Reverse DNS lookup required */
403 #ifdef GETHOSTBYADDRRSTYLE
404 #if GETHOSTBYADDRRSTYLE == SYSVSTYLE
405 hp = gethostbyaddr_r((char *)&sin->sin_addr,
406 sizeof(struct in_addr), AF_INET,
407 &result, buffer, sizeof(buffer), &error);
408 #elif GETHOSTBYADDRRSTYLE == GNUSTYLE
409 if (gethostbyaddr_r((char *)&sin->sin_addr,
410 sizeof(struct in_addr), AF_INET,
411 &result, buffer, sizeof(buffer),
416 hp = gethostbyaddr_r((char *)&sin->sin_addr,
417 sizeof(struct in_addr), AF_INET,
418 &result, buffer, sizeof(buffer), &error);
421 hp = gethostbyaddr_r((char *)&sin->sin_addr,
422 sizeof(struct in_addr), AF_INET,
423 &result, buffer, sizeof(buffer), &error);
426 if (strlen(hp->h_name) >= hostlen)
429 strcpy(host, hp->h_name);
432 else if (flags & NI_NAMEREQD)
434 else if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
437 strcpy(host, inet_ntoa(sin->sin_addr));
444 #endif /* HAVE_GETNAMEINFO */