All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
getaddrinfo.c
Go to the documentation of this file.
1 /*
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.
5  *
6  * FIXME: getaddrinfo() & getnameinfo() should
7  * return all IPv4 addresses provided by DNS lookup.
8  */
9 
10 RCSID("$Id: 2022362d3d095e3ca25814906e625cf018fcc5e1 $")
11 
12 #include <freeradius-devel/libradius.h>
13 
14 #include <ctype.h>
15 #include <sys/param.h>
16 
17 #ifndef HAVE_GETNAMEINFO
18 # undef LOCAL_GETHOSTBYNAMERSTYLE
19 # ifndef GETHOSTBYNAMERSTYLE
20 # define LOCAL_GETHOSTBYNAMERSTYLE 1
21 #elif (GETHOSTBYNAMERSTYLE != SYSVSTYLE) && (GETHOSTBYNAMERSTYLE != GNUSTYLE)
22 # define LOCAL_GETHOSTBYNAMERSTYLE 1
23 # endif /* GETHOSTBYNAMERSTYLE */
24 #endif
25 
26 #ifndef HAVE_GETADDRINFO
27 # undef LOCAL_GETHOSTBYADDRR
28 # ifndef GETHOSTBYADDRRSTYLE
29 # define LOCAL_GETHOSTBYADDRR 1
30 # elif (GETHOSTBYADDRRSTYLE != SYSVSTYLE) && (GETHOSTBYADDRRSTYLE != GNUSTYLE)
31 # define LOCAL_GETHOSTBYADDRR 1
32 # endif /* GETHOSTBYADDRRSTYLE */
33 #endif
34 
35 #ifdef HAVE_PTHREAD_H
36 # include <pthread.h>
37 
38 /* Thread safe DNS lookups */
39 /*
40  * FIXME: There are some systems that use the same hostent
41  * structure to return for gethostbyname() & gethostbyaddr(), if
42  * that is the case then use only one mutex instead of separate
43  * mutexes
44  */
45 # ifdef LOCAL_GETHOSTBYNAMERSTYLE
46 static int fr_hostbyname = 0;
47 static pthread_mutex_t fr_hostbyname_mutex;
48 # endif
49 
50 # ifdef LOCAL_GETHOSTBYNAMERSTYLE
51 static int fr_hostbyaddr = 0;
52 static pthread_mutex_t fr_hostbyaddr_mutex;
53 # endif
54 
55 #endif
56 
57 /*
58  * gethostbyaddr() & gethostbyname() return hostent structure
59  * To make these functions thread safe, we need to
60  * copy the data and not pointers
61  *
62  * struct hostent {
63  * char *h_name; * official name of host *
64  * char **h_aliases; * alias list *
65  * int h_addrtype; * host address type *
66  * int h_length; * length of address *
67  * char **h_addr_list; * list of addresses *
68  * }
69  * This struct contains 3 pointers as members.
70  * The data from these pointers is copied into a buffer.
71  * The buffer is formatted as below to store the data
72  * ---------------------------------------------------------------
73  * | h_name\0alias_array\0h_aliases\0..\0addr_array\0h_addr_list\0 |
74  * ---------------------------------------------------------------
75  */
76 #if defined(LOCAL_GETHOSTBYNAMER) || defined(LOCAL_GETHOSTBYADDRR)
77 # define BUFFER_OVERFLOW 255
78 static int copy_hostent(struct hostent *from, struct hostent *to, char *buffer, int buflen, int *error)
79 {
80  int i, len;
81  char *ptr = buffer;
82 
83  *error = 0;
84  to->h_addrtype = from->h_addrtype;
85  to->h_length = from->h_length;
86  to->h_name = (char *)ptr;
87 
88  /* copy hostname to buffer */
89  len = strlen(from->h_name) + 1;
90  strcpy(ptr, from->h_name);
91  ptr += len;
92 
93  /* copy aliases to buffer */
94  to->h_aliases = (char**)ptr;
95  for (i = 0; from->h_aliases[i]; i++);
96  ptr += (i+1) * sizeof(char *);
97 
98  for (i = 0; from->h_aliases[i]; i++) {
99  len = strlen(from->h_aliases[i])+1;
100  if ((ptr-buffer) + len < buflen) {
101  to->h_aliases[i] = ptr;
102  strcpy(ptr, from->h_aliases[i]);
103  ptr += len;
104  } else {
105  *error = BUFFER_OVERFLOW;
106  return *error;
107  }
108  }
109  to->h_aliases[i] = NULL;
110 
111  /* copy addr_list to buffer */
112  to->h_addr_list = (char**)ptr;
113  for (i = 0; (int *)from->h_addr_list[i] != 0; i++);
114  ptr += (i + 1) * sizeof(int *);
115 
116  for (i = 0; (int *)from->h_addr_list[i] != 0; i++) {
117  len = sizeof(int);
118 
119  if ((ptr-buffer)+len < buflen) {
120  to->h_addr_list[i] = ptr;
121  memcpy(ptr, from->h_addr_list[i], len);
122  ptr += len;
123  } else {
124  *error = BUFFER_OVERFLOW;
125  return *error;
126  }
127  }
128  to->h_addr_list[i] = 0;
129  return *error;
130 }
131 #endif /* (LOCAL_GETHOSTBYNAMER == 1) || (LOCAL_GETHOSTBYADDRR == 1) */
132 
133 #ifdef LOCAL_GETHOSTBYNAMERSTYLE
134 static struct hostent *
135 gethostbyname_r(char const *hostname, struct hostent *result,
136  char *buffer, int buflen, int *error)
137 {
138  struct hostent *hp;
139 
140 # ifdef HAVE_PTHREAD_H
141  if (fr_hostbyname == 0) {
142  pthread_mutex_init(&fr_hostbyname_mutex, NULL);
143  fr_hostbyname = 1;
144  }
145  pthread_mutex_lock(&fr_hostbyname_mutex);
146 # endif
147 
148  hp = gethostbyname(hostname);
149  if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
150  *error = h_errno;
151  hp = NULL;
152  } else {
153  copy_hostent(hp, result, buffer, buflen, error);
154  hp = result;
155  }
156 
157 # ifdef HAVE_PTHREAD_H
158  pthread_mutex_unlock(&fr_hostbyname_mutex);
159 # endif
160 
161  return hp;
162 }
163 #endif /* GETHOSTBYNAMERSTYLE */
164 
165 
166 #ifdef LOCAL_GETHOSTBYADDRR
167 static struct hostent *gethostbyaddr_r(char const *addr, int len, int type, struct hostent *result,
168  char *buffer, int buflen, int *error)
169 {
170  struct hostent *hp;
171 
172 #ifdef HAVE_PTHREAD_H
173  if (fr_hostbyaddr == 0) {
174  pthread_mutex_init(&fr_hostbyaddr_mutex, NULL);
175  fr_hostbyaddr = 1;
176  }
177  pthread_mutex_lock(&fr_hostbyaddr_mutex);
178 #endif
179 
180  hp = gethostbyaddr(addr, len, type);
181  if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
182  *error = h_errno;
183  hp = NULL;
184  } else {
185  copy_hostent(hp, result, buffer, buflen, error);
186  hp = result;
187  }
188 
189 #ifdef HAVE_PTHREAD_H
190  pthread_mutex_unlock(&fr_hostbyaddr_mutex);
191 #endif
192 
193  return hp;
194 }
195 #endif /* GETHOSTBYADDRRSTYLE */
196 
197 /*
198  * Mar 8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
199  *
200  * Below code is based on ssh-1.2.27-IPv6-1.5 written by
201  * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
202  */
203 
204 #ifndef HAVE_GETADDRINFO
205 static struct addrinfo *malloc_ai(uint16_t port, u_long addr, int socktype, int proto)
206 {
207  struct addrinfo *ai;
208 
209  ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
210  if (!ai) return NULL;
211 
212  memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
213  ai->ai_addr = (struct sockaddr *)(ai + 1);
214  ai->ai_addrlen = sizeof(struct sockaddr_in);
215 # ifdef HAVE_SOCKADDR_SA_LEN
216  ai->ai_addr->sa_len = sizeof(struct sockaddr_in);
217 # endif
218  ai->ai_addr->sa_family = ai->ai_family = AF_INET;
219  ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
220  ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
221  ai->ai_socktype = socktype;
222  ai->ai_protocol = proto;
223 
224  return ai;
225 }
226 
227 char const *gai_strerror(int ecode)
228 {
229  switch (ecode) {
230  case EAI_MEMORY:
231  return "memory allocation failure";
232 
233  case EAI_FAMILY:
234  return "ai_family not supported";
235 
236  case EAI_NONAME:
237  return "hostname nor servname provided, or not known";
238 
239  case EAI_SERVICE:
240  return "servname not supported for ai_socktype";
241 
242  default:
243  return "unknown error";
244  }
245 }
246 
247 void freeaddrinfo(struct addrinfo *ai)
248 {
249  struct addrinfo *next;
250 
251  if (ai->ai_canonname) free(ai->ai_canonname);
252 
253  do {
254  next = ai->ai_next;
255  free(ai);
256  } while ((ai = next) != NULL);
257 }
258 
259 int getaddrinfo(char const *hostname, char const *servname, struct addrinfo const *hints, struct addrinfo **res)
260 {
261  struct addrinfo *cur, *prev = NULL;
262  struct hostent *hp;
263  struct hostent result;
264  struct in_addr in;
265  int i, socktype, proto;
266  uint16_t port = 0;
267  int error;
268  char buffer[2048];
269 
270  if (hints && (hints->ai_family != PF_INET) && (hints->ai_family != PF_UNSPEC)) return EAI_FAMILY;
271 
272  socktype = (hints && hints->ai_socktype) ? hints->ai_socktype : SOCK_STREAM;
273  if (hints && hints->ai_protocol) {
274  proto = hints->ai_protocol;
275  } else {
276  switch (socktype) {
277  case SOCK_DGRAM:
278  proto = IPPROTO_UDP;
279  break;
280  case SOCK_STREAM:
281  proto = IPPROTO_TCP;
282  break;
283  default:
284  proto = 0;
285  break;
286  }
287  }
288 
289  if (servname) {
290  if (isdigit((int)*servname)) {
291  port = htons(atoi(servname));
292  } else {
293  struct servent *se;
294  char const *pe_proto;
295 
296  switch (socktype) {
297  case SOCK_DGRAM:
298  pe_proto = "udp";
299  break;
300 
301  case SOCK_STREAM:
302  pe_proto = "tcp";
303  break;
304 
305  default:
306  pe_proto = NULL;
307  break;
308  }
309  if ((se = getservbyname(servname, pe_proto)) == NULL) return EAI_SERVICE;
310 
311  port = se->s_port;
312  }
313  }
314 
315  if (!hostname) {
316  if (hints && hints->ai_flags & AI_PASSIVE) {
317  *res = malloc_ai(port, htonl(0x00000000), socktype, proto);
318  } else {
319  *res = malloc_ai(port, htonl(0x7f000001), socktype, proto);
320  }
321  if (!*res) return EAI_MEMORY;
322 
323  return 0;
324  }
325 
326  /* Numeric IP Address */
327  if (inet_aton(hostname, &in)) {
328  *res = malloc_ai(port, in.s_addr, socktype, proto);
329  if (!*res) return EAI_MEMORY;
330 
331  return 0;
332  }
333 
334  if (hints && hints->ai_flags & AI_NUMERICHOST) return EAI_NONAME;
335 
336  /* DNS Lookup */
337 #ifdef GETHOSTBYNAMERSTYLE
338 # if GETHOSTBYNAMERSTYLE == SYSVSTYLE
339  hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
340 # elif GETHOSTBYNAMERSTYLE == GNUSTYLE
341  if (gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &hp, &error) != 0) hp = NULL;
342 # else
343  hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
344 # endif
345 #else
346  hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
347 #endif
348 
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, ((struct in_addr *)hp->h_addr_list[i])->s_addr,
352  socktype, proto)) == NULL) {
353  if (*res) freeaddrinfo(*res);
354  return EAI_MEMORY;
355  }
356 
357  if (prev) {
358  prev->ai_next = cur;
359  } else {
360  *res = cur;
361  }
362  prev = cur;
363  }
364 
365  if (hints && hints->ai_flags & AI_CANONNAME && *res) {
366  if (((*res)->ai_canonname = strdup(hp->h_name)) == NULL) {
367  freeaddrinfo(*res);
368  return EAI_MEMORY;
369  }
370  }
371  return 0;
372  }
373  return EAI_NONAME;
374 }
375 #endif /* HAVE_GETADDRINFO */
376 
377 
378 #ifndef HAVE_GETNAMEINFO
379 int getnameinfo(struct sockaddr const *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen,
380  unsigned int flags)
381 {
382  const struct sockaddr_in *sin = (struct sockaddr_in const *)sa;
383  struct hostent *hp;
384  struct hostent result;
385  char tmpserv[16];
386  char buffer[2048];
387  int error;
388 
389  if (serv) {
390  snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
391  if (strlen(tmpserv) > servlen) return EAI_MEMORY;
392 
393  strcpy(serv, tmpserv);
394 
395  if (host) {
396  if (flags & NI_NUMERICHOST) {
397  /* No Reverse DNS lookup */
398  if (flags & NI_NAMEREQD) return EAI_NONAME;
399  if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen) return EAI_MEMORY;
400 
401  strcpy(host, inet_ntoa(sin->sin_addr));
402  return 0;
403  } else {
404  /* Reverse DNS lookup required */
405 #ifdef GETHOSTBYADDRRSTYLE
406 # if GETHOSTBYADDRRSTYLE == SYSVSTYLE
407  hp = gethostbyaddr_r((char const *)&sin->sin_addr,
408  salen, AF_INET, &result, buffer, sizeof(buffer), &error);
409 # elif GETHOSTBYADDRRSTYLE == GNUSTYLE
410  if (gethostbyaddr_r((char const *)&sin->sin_addr, salen, AF_INET,
411  &result, buffer, sizeof(buffer), &hp, &error) != 0) {
412  hp = NULL;
413  }
414 # else
415  hp = gethostbyaddr_r((char const *)&sin->sin_addr, salen, AF_INET,
416  &result, buffer, sizeof(buffer), &error);
417 # endif
418 #else
419  hp = gethostbyaddr_r((char const *)&sin->sin_addr, salen, AF_INET,
420  &result, buffer, sizeof(buffer), &error);
421 #endif
422  if (hp) {
423  if (strlen(hp->h_name) >= hostlen) return EAI_MEMORY;
424 
425  strcpy(host, hp->h_name);
426  return 0;
427  }
428 
429  if (flags & NI_NAMEREQD) return EAI_NONAME;
430  if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen) return EAI_MEMORY;
431 
432  strcpy(host, inet_ntoa(sin->sin_addr));
433  return 0;
434  }
435  }
436  return 0;
437 }
438 #endif /* HAVE_GETNAMEINFO */
static struct hostent * gethostbyaddr_r(char const *addr, int len, int type, struct hostent *result, char *buffer, int buflen, int *error)
Definition: getaddrinfo.c:167
#define pthread_mutex_init(_x, _y)
Definition: rlm_eap.h:75
char const * gai_strerror(int ecode)
Definition: getaddrinfo.c:227
#define BUFFER_OVERFLOW
Definition: getaddrinfo.c:77
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
static char const * hostname(char *buf, size_t buflen, uint32_t ipaddr)
Definition: radwho.c:149
static int copy_hostent(struct hostent *from, struct hostent *to, char *buffer, int buflen, int *error)
Definition: getaddrinfo.c:78
static char const * proto
Definition: radclient.c:63
int inet_aton(char const *cp, struct in_addr *inp)
Definition: missing.c:86
#define pthread_mutex_unlock(_x)
Definition: rlm_eap.h:78
void freeaddrinfo(struct addrinfo *ai)
Definition: getaddrinfo.c:247
static struct addrinfo * malloc_ai(uint16_t port, u_long addr, int socktype, int proto)
Definition: getaddrinfo.c:205
int getnameinfo(struct sockaddr const *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, unsigned int flags)
Definition: getaddrinfo.c:379
static struct hostent * gethostbyname_r(char const *hostname, struct hostent *result, char *buffer, int buflen, int *error)
Definition: getaddrinfo.c:135
#define pthread_mutex_lock(_x)
Definition: rlm_eap.h:77
int getaddrinfo(char const *hostname, char const *servname, struct addrinfo const *hints, struct addrinfo **res)
Definition: getaddrinfo.c:259
#define RCSID(id)
Definition: build.h:135