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