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