summaryrefslogtreecommitdiffstats
path: root/lib/getaddrinfo.c
diff options
context:
space:
mode:
authorJeremy T. Bouse <undrgrid@users.sourceforge.net>2003-03-15 01:25:35 (GMT)
committerJeremy T. Bouse <undrgrid@users.sourceforge.net>2003-03-15 01:25:35 (GMT)
commit11b35b92e3195d230bef359f6a0679ae4414716b (patch)
treef4911e5804c1f3037dcf63bbbf0b823c5ac19e5f /lib/getaddrinfo.c
parent6cf5fc3c74c0bdfef6c4cc1b627578378ad3a407 (diff)
downloadmonitoring-plugins-11b35b92e3195d230bef359f6a0679ae4414716b.tar.gz
Spent the day working on backwards compatability using getaddrinfo()
Moved getaddrinfo.? and gethostbyname.? from lib/ to plugins/ due to problems with compiling into the libnagiosplug.a as it required linking against socket libraries which are unneeded except for network based plugins. This code should hopefully happily work for all systems and has been tested prior to commit on Debian GNU/Linux, SPARC Solaris 7 and SPARC Solaris 9. git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@424 f882894a-f735-0410-b71e-b25c423dba1c
Diffstat (limited to 'lib/getaddrinfo.c')
-rw-r--r--lib/getaddrinfo.c312
1 files changed, 0 insertions, 312 deletions
diff --git a/lib/getaddrinfo.c b/lib/getaddrinfo.c
deleted file mode 100644
index c958da6..0000000
--- a/lib/getaddrinfo.c
+++ /dev/null
@@ -1,312 +0,0 @@
1/*
2 * This file is part of libESMTP, a library for submission of RFC 2822
3 * formatted electronic mail messages using the SMTP protocol described
4 * in RFC 2821.
5 *
6 * Copyright (C) 2001,2002 Brian Stafford <brian@stafford.uklinux.net>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23/* An emulation of the RFC 2553 / Posix getaddrinfo resolver interface.
24 */
25
26#ifdef HAVE_CONFIG_H
27#include <config.h>
28#endif
29
30/* Need to turn off Posix features in glibc to build this */
31#undef _POSIX_C_SOURCE
32#undef _XOPEN_SOURCE
33
34#include <stdlib.h>
35#include <string.h>
36#include <ctype.h>
37#include <errno.h>
38
39#include <sys/socket.h>
40#include <netinet/in.h>
41#include <arpa/inet.h>
42
43#include <netdb.h>
44
45#include "gethostbyname.h"
46#include "getaddrinfo.h"
47
48static struct addrinfo *
49dup_addrinfo (struct addrinfo *info, void *addr, size_t addrlen)
50{
51 struct addrinfo *ret;
52
53 ret = malloc (sizeof (struct addrinfo));
54 if (ret == NULL)
55 return NULL;
56 memcpy (ret, info, sizeof (struct addrinfo));
57 ret->ai_addr = malloc (addrlen);
58 if (ret->ai_addr == NULL)
59 {
60 free (ret);
61 return NULL;
62 }
63 memcpy (ret->ai_addr, addr, addrlen);
64 ret->ai_addrlen = addrlen;
65 return ret;
66}
67
68int
69getaddrinfo (const char *nodename, const char *servname,
70 const struct addrinfo *hints, struct addrinfo **res)
71{
72 struct hostent *hp;
73 struct servent *servent;
74 const char *socktype;
75 int port;
76 struct addrinfo hint, result;
77 struct addrinfo *ai, *sai, *eai;
78 struct ghbnctx ghbnctx;
79 char **addrs;
80 int code;
81
82 memset (&result, 0, sizeof result);
83
84 /* default for hints */
85 if (hints == NULL)
86 {
87 memset (&hint, 0, sizeof hint);
88 hint.ai_family = PF_UNSPEC;
89 hints = &hint;
90 }
91
92 /* servname must not be NULL in this implementation */
93 if (servname == NULL)
94 return EAI_NONAME;
95
96 /* check for tcp or udp sockets only */
97 if (hints->ai_socktype == SOCK_STREAM)
98 socktype = "tcp";
99 else if (hints->ai_socktype == SOCK_DGRAM)
100 socktype = "udp";
101 else
102 return EAI_SERVICE;
103 result.ai_socktype = hints->ai_socktype;
104
105 /* Note: maintain port in host byte order to make debugging easier */
106 if (isdigit (*servname))
107 port = strtol (servname, NULL, 10);
108 else if ((servent = getservbyname (servname, socktype)) != NULL)
109 port = ntohs (servent->s_port);
110 else
111 return EAI_NONAME;
112
113 /* if nodename == NULL refer to the local host for a client or any
114 for a server */
115 if (nodename == NULL)
116 {
117 struct sockaddr_in sin;
118
119 /* check protocol family is PF_UNSPEC or PF_INET - could try harder
120 for IPv6 but that's more code than I'm prepared to write */
121 if (hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET)
122 result.ai_family = AF_INET;
123 else
124 return EAI_FAMILY;
125
126 sin.sin_family = result.ai_family;
127 sin.sin_port = htons (port);
128 if (hints->ai_flags & AI_PASSIVE)
129 sin.sin_addr.s_addr = htonl (INADDR_ANY);
130 else
131 sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
132 /* Duplicate result and addr and return */
133 *res = dup_addrinfo (&result, &sin, sizeof sin);
134 return (*res == NULL) ? EAI_MEMORY : 0;
135 }
136
137 /* If AI_NUMERIC is specified, use inet_addr to translate numbers and
138 dots notation. */
139 if (hints->ai_flags & AI_NUMERICHOST)
140 {
141 struct sockaddr_in sin;
142
143 /* check protocol family is PF_UNSPEC or PF_INET */
144 if (hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET)
145 result.ai_family = AF_INET;
146 else
147 return EAI_FAMILY;
148
149 sin.sin_family = result.ai_family;
150 sin.sin_port = htons (port);
151 sin.sin_addr.s_addr = inet_addr (nodename);
152 /* Duplicate result and addr and return */
153 *res = dup_addrinfo (&result, &sin, sizeof sin);
154 return (*res == NULL) ? EAI_MEMORY : 0;
155 }
156
157 errno = 0;
158 hp = gethostbyname_ctx (nodename, &ghbnctx);
159 if (hp == NULL)
160 {
161 if (errno != 0)
162 {
163 free_ghbnctx (&ghbnctx);
164 return EAI_SYSTEM;
165 }
166 code = h_error_ctx (&ghbnctx);
167 switch (code)
168 {
169 case HOST_NOT_FOUND: code = EAI_NODATA; break;
170 case NO_DATA: code = EAI_NODATA; break;
171#if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA
172 case NO_ADDRESS: code = EAI_NODATA; break;
173#endif
174 case NO_RECOVERY: code = EAI_FAIL; break;
175 case TRY_AGAIN: code = EAI_AGAIN; break;
176 default: code = EAI_FAIL; break;
177 }
178 free_ghbnctx (&ghbnctx);
179 return code;
180 }
181
182 /* Check that the address family is acceptable.
183 */
184 switch (hp->h_addrtype)
185 {
186 case AF_INET:
187 if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET))
188 goto eai_family;
189 break;
190#ifdef USE_IPV6
191 case AF_INET6:
192 if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET6))
193 goto eai_family;
194 break;
195#endif
196 default:
197 eai_family:
198 free_ghbnctx (&ghbnctx);
199 return EAI_FAMILY;
200 }
201
202 /* For each element pointed to by hp, create an element in the
203 result linked list. */
204 sai = eai = NULL;
205 for (addrs = hp->h_addr_list; *addrs != NULL; addrs++)
206 {
207 struct sockaddr sa;
208 size_t addrlen;
209
210 sa.sa_family = hp->h_addrtype;
211 switch (hp->h_addrtype)
212 {
213 case AF_INET:
214 ((struct sockaddr_in *) &sa)->sin_port = htons (port);
215 memcpy (&((struct sockaddr_in *) &sa)->sin_addr,
216 *addrs, hp->h_length);
217 addrlen = sizeof (struct sockaddr_in);
218 break;
219#ifdef USE_IPV6
220 case AF_INET6:
221# if SIN6_LEN
222 ((struct sockaddr_in6 *) &sa)->sin6_len = hp->h_length;
223# endif
224 ((struct sockaddr_in6 *) &sa)->sin6_port = htons (port);
225 memcpy (&((struct sockaddr_in6 *) &sa)->sin6_addr,
226 *addrs, hp->h_length);
227 addrlen = sizeof (struct sockaddr_in6);
228 break;
229#endif
230 default:
231 continue;
232 }
233
234 result.ai_family = hp->h_addrtype;
235 ai = dup_addrinfo (&result, &sa, addrlen);
236 if (ai == NULL)
237 {
238 free_ghbnctx (&ghbnctx);
239 freeaddrinfo (sai);
240 return EAI_MEMORY;
241 }
242 if (sai == NULL)
243 sai = ai;
244 else
245 eai->ai_next = ai;
246 eai = ai;
247 }
248
249 if (sai == NULL)
250 {
251 free_ghbnctx (&ghbnctx);
252 return EAI_NODATA;
253 }
254
255 if (hints->ai_flags & AI_CANONNAME)
256 {
257 sai->ai_canonname = malloc (strlen (hp->h_name) + 1);
258 if (sai->ai_canonname == NULL)
259 {
260 free_ghbnctx (&ghbnctx);
261 freeaddrinfo (sai);
262 return EAI_MEMORY;
263 }
264 strcpy (sai->ai_canonname, hp->h_name);
265 }
266
267 free_ghbnctx (&ghbnctx);
268 *res = sai;
269 return 0;
270}
271
272void
273freeaddrinfo (struct addrinfo *ai)
274{
275 struct addrinfo *next;
276
277 while (ai != NULL)
278 {
279 next = ai->ai_next;
280 if (ai->ai_canonname != NULL)
281 free (ai->ai_canonname);
282 if (ai->ai_addr != NULL)
283 free (ai->ai_addr);
284 free (ai);
285 ai = next;
286 }
287}
288
289const char *
290gai_strerror (int ecode)
291{
292 static const char *eai_descr[] =
293 {
294 "no error",
295 "address family for nodename not supported", /* EAI_ADDRFAMILY */
296 "temporary failure in name resolution", /* EAI_AGAIN */
297 "invalid value for ai_flags", /* EAI_BADFLAGS */
298 "non-recoverable failure in name resolution", /* EAI_FAIL */
299 "ai_family not supported", /* EAI_FAMILY */
300 "memory allocation failure", /* EAI_MEMORY */
301 "no address associated with nodename", /* EAI_NODATA */
302 "nodename nor servname provided, or not known", /* EAI_NONAME */
303 "servname not supported for ai_socktype", /* EAI_SERVICE */
304 "ai_socktype not supported", /* EAI_SOCKTYPE */
305 "system error returned in errno", /* EAI_SYSTEM */
306 };
307
308 if (ecode < 0 || ecode > (int) (sizeof eai_descr/ sizeof eai_descr[0]))
309 return "unknown error";
310 return eai_descr[ecode];
311}
312