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/autoconf.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
24 #include <sys/param.h>
26 #include <freeradius-devel/missing.h>
31 /* Thread safe DNS lookups */
32 /* TODO There are some systems that use the same hostent structure
33 to return for gethostbyname() & gethostbyaddr(), if that is the
34 case then use only one mutex instead of seperate mutexes
36 static int lrad_hostbyname = 0;
37 static int lrad_hodtbyaddr = 0;
38 static pthread_mutex_t lrad_hostbyname_mutex;
39 static pthread_mutex_t lrad_hodtbyaddr_mutex;
42 #ifndef GETHOSTBYNAMERSTYLE
43 #define LOCAL_GETHOSTBYNAMERSTYLE 1
44 #elif (GETHOSTBYNAMERSTYLE != SYSVSTYLE) && (GETHOSTBYNAMERSTYLE != GNUSTYLE)
45 #define LOCAL_GETHOSTBYNAMERSTYLE 1
46 #endif /* GETHOSTBYNAMERSTYLE */
48 #ifndef GETHOSTBYADDRRSTYLE
49 #define LOCAL_GETHOSTBYADDRR 1
50 #elif (GETHOSTBYADDRRSTYLE != SYSVSTYLE) && (GETHOSTBYADDRRSTYLE != GNUSTYLE)
51 #define LOCAL_GETHOSTBYADDRR 1
52 #endif /* GETHOSTBYADDRRSTYLE */
55 * gethostbyaddr() & gethostbyname() return hostent structure
56 * To make these functions thread safe, we need to
57 * copy the data and not pointers
60 * char *h_name; * official name of host *
61 * char **h_aliases; * alias list *
62 * int h_addrtype; * host address type *
63 * int h_length; * length of address *
64 * char **h_addr_list; * list of addresses *
66 * This struct contains 3 pointers as members.
67 * The data from these pointers is copied into a buffer.
68 * The buffer is formatted as below to store the data
69 * ---------------------------------------------------------------
70 * | h_name\0alias_array\0h_aliases\0..\0addr_array\0h_addr_list\0 |
71 * ---------------------------------------------------------------
73 #if (LOCAL_GETHOSTBYNAMER == 1) || (LOCAL_GETHOSTBYADDRR == 1)
74 #define BUFFER_OVERFLOW 255
75 int copy_hostent(struct hostent *from, struct hostent *to,
76 char *buffer, int buflen, int *error)
82 to->h_addrtype = from->h_addrtype;
83 to->h_length = from->h_length;
84 to->h_name = (char *)ptr;
86 /* copy hostname to buffer */
87 len=strlen(from->h_name)+1;
88 strcpy(ptr, from->h_name);
91 /* copy aliases to buffer */
92 to->h_aliases = (char**)ptr;
93 for(i = 0; from->h_aliases[i]; i++);
94 ptr += (i+1) * sizeof(char *);
96 for(i = 0; from->h_aliases[i]; i++) {
97 len = strlen(from->h_aliases[i])+1;
98 if ((ptr-buffer)+len < buflen) {
99 to->h_aliases[i] = ptr;
100 strcpy(ptr, from->h_aliases[i]);
103 *error = BUFFER_OVERFLOW;
107 to->h_aliases[i] = NULL;
109 /* copy addr_list to buffer */
110 to->h_addr_list = (char**)ptr;
111 for(i = 0; (int *)from->h_addr_list[i] != 0; i++);
112 ptr += (i+1) * sizeof(int *);
114 for(i = 0; (int *)from->h_addr_list[i] != 0; i++) {
116 if ((ptr-buffer)+len < buflen) {
117 to->h_addr_list[i] = ptr;
118 memcpy(ptr, from->h_addr_list[i], len);
121 *error = BUFFER_OVERFLOW;
125 to->h_addr_list[i] = 0;
128 #endif /* (LOCAL_GETHOSTBYNAMER == 1) || (LOCAL_GETHOSTBYADDRR == 1) */
130 #ifdef LOCAL_GETHOSTBYNAMERSTYLE
131 static struct hostent *
132 gethostbyname_r(const char *hostname, struct hostent *result,
133 char *buffer, int buflen, int *error)
137 #ifdef HAVE_PTHREAD_H
138 if (lrad_hostbyname == 0) {
139 pthread_mutex_init(&lrad_hostbyname_mutex, NULL);
142 pthread_mutex_lock(&lrad_hostbyname_mutex);
145 hp = gethostbyname(name);
146 if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
150 copy_hostent(hp, result, buffer, buflen, error);
154 #ifdef HAVE_PTHREAD_H
155 pthread_mutex_unlock(&lrad_hostbyname_mutex);
160 #endif /* GETHOSTBYNAMERSTYLE */
163 #ifdef LOCAL_GETHOSTBYADDRRSTYLE
164 static struct hostent *
165 gethostbyaddr_r(const char *addr, int len, int type, struct hostent *result,
166 char *buffer, int buflen, int *error)
170 #ifdef HAVE_PTHREAD_H
171 if (lrad_hodtbyaddr == 0) {
172 pthread_mutex_init(&lrad_hodtbyaddr_mutex, NULL);
175 pthread_mutex_lock(&lrad_hodtbyaddr_mutex);
178 hp = gethostbyaddr(addr, len, type);
179 if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
183 copy_hostent(hp, result, buffer, buflen, error);
187 #ifdef HAVE_PTHREAD_H
188 pthread_mutex_unlock(&lrad_hodtbyaddr_mutex);
193 #endif /* GETHOSTBYADDRRSTYLE */
196 * Mar 8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
198 * Below code is based on ssh-1.2.27-IPv6-1.5 written by
199 * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
202 #ifndef HAVE_GETADDRINFO
203 static struct addrinfo *
204 malloc_ai(int port, u_long addr, int socktype, int proto)
208 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) +
209 sizeof(struct sockaddr_in));
211 memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
212 ai->ai_addr = (struct sockaddr *)(ai + 1);
213 ai->ai_addrlen = sizeof(struct sockaddr_in);
214 #ifdef HAVE_SOCKADDR_SA_LEN
215 ai->ai_addr->sa_len = sizeof(struct sockaddr_in);
217 ai->ai_addr->sa_family = ai->ai_family = AF_INET;
218 ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
219 ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
220 ai->ai_socktype = socktype;
221 ai->ai_protocol = proto;
229 gai_strerror(int ecode)
233 return "memory allocation failure.";
235 return "ai_family not supported.";
237 return "hostname nor servname provided, or not known.";
239 return "servname not supported for ai_socktype.";
241 return "unknown error.";
246 freeaddrinfo(struct addrinfo *ai)
248 struct addrinfo *next;
250 if (ai->ai_canonname)
251 free(ai->ai_canonname);
255 } while ((ai = next) != NULL);
259 getaddrinfo(const char *hostname, const char *servname,
260 const struct addrinfo *hints, struct addrinfo **res)
262 struct addrinfo *cur, *prev = NULL;
264 struct hostent result;
266 int i, port = 0, socktype, proto;
270 if (hints && hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC)
273 socktype = (hints && hints->ai_socktype) ? hints->ai_socktype
275 if (hints && hints->ai_protocol)
276 proto = hints->ai_protocol;
291 if (isdigit((int)*servname))
292 port = htons(atoi(servname));
308 if ((se = getservbyname(servname, pe_proto)) == NULL)
314 if (hints && hints->ai_flags & AI_PASSIVE)
315 *res = malloc_ai(port, htonl(0x00000000), socktype, proto);
317 *res = malloc_ai(port, htonl(0x7f000001), socktype, proto);
323 /* Numeric IP Address */
324 if (inet_aton(hostname, &in)) {
325 *res = malloc_ai(port, in.s_addr, socktype, proto);
331 if (hints && hints->ai_flags & AI_NUMERICHOST)
335 #ifdef GETHOSTBYNAMERSTYLE
336 #if GETHOSTBYNAMERSTYLE == SYSVSTYLE
337 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
338 #elif GETHOSTBYNAMERSTYLE == GNUSTYLE
339 if (gethostbyname_r(hostname, &result, buffer,
340 sizeof(buffer), &hp, &error) != 0) {
344 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
347 hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
349 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
350 for (i = 0; hp->h_addr_list[i]; i++) {
351 if ((cur = malloc_ai(port,
352 ((struct in_addr *)hp->h_addr_list[i])->s_addr,
353 socktype, proto)) == NULL) {
364 if (hints && hints->ai_flags & AI_CANONNAME && *res) {
365 if (((*res)->ai_canonname = strdup(hp->h_name)) == NULL) {
374 #endif /* HAVE_GETADDRINFO */
377 #ifndef HAVE_GETNAMEINFO
379 getnameinfo(const struct sockaddr *sa, socklen_t salen,
380 char *host, size_t hostlen,
381 char *serv, size_t servlen,
384 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
386 struct hostent result;
392 snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
393 if (strlen(tmpserv) > servlen)
396 strcpy(serv, tmpserv);
399 if (flags & NI_NUMERICHOST) {
400 /* No Reverse DNS lookup */
401 if (flags & NI_NAMEREQD)
403 if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
406 strcpy(host, inet_ntoa(sin->sin_addr));
410 /* Reverse DNS lookup required */
411 #ifdef GETHOSTBYADDRRSTYLE
412 #if GETHOSTBYADDRRSTYLE == SYSVSTYLE
413 hp = gethostbyaddr_r((char *)&sin->sin_addr,
414 sizeof(struct in_addr), AF_INET,
415 &result, buffer, sizeof(buffer), &error);
416 #elif GETHOSTBYADDRRSTYLE == GNUSTYLE
417 if (gethostbyaddr_r((char *)&sin->sin_addr,
418 sizeof(struct in_addr), AF_INET,
419 &result, buffer, sizeof(buffer),
424 hp = gethostbyaddr_r((char *)&sin->sin_addr,
425 sizeof(struct in_addr), AF_INET,
426 &result, buffer, sizeof(buffer), &error);
429 hp = gethostbyaddr_r((char *)&sin->sin_addr,
430 sizeof(struct in_addr), AF_INET,
431 &result, buffer, sizeof(buffer), &error);
434 if (strlen(hp->h_name) >= hostlen)
437 strcpy(host, hp->h_name);
440 else if (flags & NI_NAMEREQD)
442 else if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen)
445 strcpy(host, inet_ntoa(sin->sin_addr));
452 #endif /* HAVE_GETNAMEINFO */