1 /*
2 * $Id: libnet_resolve.c,v 1.21 2004/11/09 07:05:07 mike Exp $
3 *
4 * libnet
5 * libnet_resolve.c - various name resolution type routines
6 *
7 * Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 */
32
33 #if (HAVE_CONFIG_H)
34 #include "../include/config.h"
35 #endif
36 #if (!(_WIN32) || (__CYGWIN__))
37 #include "../include/libnet.h"
38 #else
39 #include "../include/win32/libnet.h"
40 #endif
41
42 #ifndef HAVE_GETHOSTBYNAME2
43 struct hostent *
gethostbyname2(const char * name,int af)44 gethostbyname2(const char *name, int af)
45 {
46 return gethostbyname(name);
47 }
48 #endif
49
50 char *
libnet_addr2name4(uint32_t in,uint8_t use_name)51 libnet_addr2name4(uint32_t in, uint8_t use_name)
52 {
53 #define HOSTNAME_SIZE 512
54 static char hostname[HOSTNAME_SIZE+1], hostname2[HOSTNAME_SIZE+1];
55 static uint16_t which;
56 uint8_t *p;
57
58 struct hostent *host_ent = NULL;
59 struct in_addr addr;
60
61 /*
62 * Swap to the other buffer. We swap static buffers to avoid having to
63 * pass in a int8_t *. This makes the code that calls this function more
64 * intuitive, but makes this function ugly. This function is seriously
65 * non-reentrant. For threaded applications (or for signal handler code)
66 * use host_lookup_r().
67 */
68 which++;
69
70 if (use_name == LIBNET_RESOLVE)
71 {
72 addr.s_addr = in;
73 host_ent = gethostbyaddr((int8_t *)&addr, sizeof(struct in_addr), AF_INET);
74 /* if this fails, we silently ignore the error and move to plan b! */
75 }
76 if (!host_ent)
77 {
78
79 p = (uint8_t *)∈
80 snprintf(((which % 2) ? hostname : hostname2), HOSTNAME_SIZE,
81 "%d.%d.%d.%d",
82 (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
83 }
84 else if (use_name == LIBNET_RESOLVE)
85 {
86 char *ptr = ((which % 2) ? hostname : hostname2);
87 strncpy(ptr, host_ent->h_name, HOSTNAME_SIZE);
88 ptr[HOSTNAME_SIZE] = '\0';
89
90 }
91 return (which % 2) ? (hostname) : (hostname2);
92 }
93
94 void
libnet_addr2name4_r(uint32_t in,uint8_t use_name,char * hostname,int hostname_len)95 libnet_addr2name4_r(uint32_t in, uint8_t use_name, char *hostname,
96 int hostname_len)
97 {
98 uint8_t *p;
99 struct hostent *host_ent = NULL;
100 struct in_addr addr;
101
102 if (use_name == LIBNET_RESOLVE)
103 {
104 addr.s_addr = in;
105 host_ent = gethostbyaddr((int8_t *)&addr, sizeof(struct in_addr),
106 AF_INET);
107 }
108 if (!host_ent)
109 {
110 p = (uint8_t *)∈
111 snprintf(hostname, hostname_len, "%d.%d.%d.%d",
112 (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
113 }
114 else
115 {
116 strncpy(hostname, host_ent->h_name, hostname_len - 1);
117 hostname[sizeof(hostname) - 1] = '\0';
118 }
119 }
120
121 uint32_t
libnet_name2addr4(libnet_t * l,char * host_name,uint8_t use_name)122 libnet_name2addr4(libnet_t *l, char *host_name, uint8_t use_name)
123 {
124 struct in_addr addr;
125 struct hostent *host_ent;
126 uint32_t m;
127 uint val;
128 int i;
129
130 if (use_name == LIBNET_RESOLVE)
131 {
132 if ((addr.s_addr = inet_addr(host_name)) == -1)
133 {
134 if (!(host_ent = gethostbyname(host_name)))
135 {
136 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
137 "%s(): %s\n", __func__, hstrerror(h_errno));
138 /* XXX - this is actually 255.255.255.255 */
139 return (-1);
140 }
141 memcpy(&addr.s_addr, host_ent->h_addr, host_ent->h_length);
142 }
143 /* network byte order */
144 return (addr.s_addr);
145 }
146 else
147 {
148 /*
149 * We only want dots 'n decimals.
150 */
151 if (!isdigit(host_name[0]))
152 {
153 if (l)
154 {
155 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
156 "%s(): expecting dots and decimals\n", __func__);
157 }
158 /* XXX - this is actually 255.255.255.255 */
159 return (-1);
160 }
161
162 m = 0;
163 for (i = 0; i < 4; i++)
164 {
165 m <<= 8;
166 if (*host_name)
167 {
168 val = 0;
169 while (*host_name && *host_name != '.')
170 {
171 val *= 10;
172 val += *host_name - '0';
173 if (val > 255)
174 {
175 if (l)
176 {
177 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
178 "%s(): value greater than 255\n", __func__);
179 }
180 /* XXX - this is actually 255.255.255.255 */
181 return (-1);
182 }
183 host_name++;
184 }
185 m |= val;
186 if (*host_name)
187 {
188 host_name++;
189 }
190 }
191 }
192 /* host byte order */
193 return (ntohl(m));
194 }
195 }
196
197 void
libnet_addr2name6_r(struct libnet_in6_addr addr,uint8_t use_name,char * host_name,int host_name_len)198 libnet_addr2name6_r(struct libnet_in6_addr addr, uint8_t use_name,
199 char *host_name, int host_name_len)
200 {
201 struct hostent *host_ent = NULL;
202
203 if (use_name == LIBNET_RESOLVE)
204 {
205 #ifdef HAVE_SOLARIS
206 #ifdef HAVE_SOLARIS_IPV6
207 host_ent = getipnodebyaddr((int8_t *)&addr, sizeof(struct in_addr),
208 AF_INET6, NULL);
209 #else
210 /* XXX - Gah! Can't report error! */
211 host_ent = NULL;
212 #endif
213 #else
214 host_ent = gethostbyaddr((int8_t *)&addr, sizeof(struct in_addr),
215 AF_INET6);
216 #endif
217 }
218 if (!host_ent)
219 {
220 #if !defined(__WIN32__) /* Silence Win32 warning */
221 inet_ntop(AF_INET6, &addr, host_name, host_name_len);
222 #endif
223 }
224 else
225 {
226 strncpy(host_name, host_ent->h_name, host_name_len -1);
227 host_name[sizeof(host_name) - 1] = '\0';
228 }
229 }
230
231 const struct libnet_in6_addr in6addr_error = IN6ADDR_ERROR_INIT;
232
233 int
libnet_in6_is_error(struct libnet_in6_addr addr)234 libnet_in6_is_error(struct libnet_in6_addr addr)
235 {
236 return 0 == memcmp(&addr, &in6addr_error, sizeof(addr));
237 }
238
239 struct libnet_in6_addr
libnet_name2addr6(libnet_t * l,const char * host_name,uint8_t use_name)240 libnet_name2addr6(libnet_t *l, const char *host_name, uint8_t use_name)
241 {
242 #if !defined (__WIN32__)
243 struct libnet_in6_addr addr;
244 struct hostent *host_ent;
245 #endif
246
247 if (use_name == LIBNET_RESOLVE)
248 {
249 #ifdef __WIN32__
250 /* XXX - we don't support this yet */
251 if (l)
252 {
253 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
254 "%s(): can't resolve IPv6 addresses\n", __func__);
255 }
256 return (in6addr_error);
257 #else
258 #ifdef HAVE_SOLARIS
259 #ifdef HAVE_SOLARIS_IPV6
260 if (!(host_ent = getipnodebyname((int8_t *)&addr,
261 sizeof(struct in_addr), AF_INET6, NULL)))
262 #else
263 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
264 "%s(): %s\n", __func__, strerror(errno));
265 return (in6addr_error);
266 #endif
267 #else
268 if (!(host_ent = gethostbyname2(host_name, AF_INET6)))
269 #endif
270 {
271 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
272 "%s(): %s", __func__, strerror(errno));
273 return (in6addr_error);
274 }
275 memcpy(&addr, host_ent->h_addr, host_ent->h_length);
276 return (addr);
277 #endif /* !__WIN32__ */
278 }
279 else
280 {
281 #if defined(__WIN32__) /* Silence Win32 warning */
282 if (l)
283 {
284 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
285 "%s(): can't resolve IPv6 addresses.\n", __func__);
286 }
287 return (in6addr_error);
288 #else
289 if(!inet_pton(AF_INET6, host_name, &addr))
290 {
291 if (l)
292 {
293 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
294 "%s(): invalid IPv6 address\n", __func__);
295 }
296 return (in6addr_error);
297 }
298 return (addr);
299 #endif
300 }
301 }
302
303 #ifdef HAVE_GETIFADDRS
304
305 #include <ifaddrs.h>
306
307 struct libnet_in6_addr
libnet_get_ipaddr6(libnet_t * l)308 libnet_get_ipaddr6(libnet_t *l)
309 {
310 struct ifaddrs *ifaddr, *p;
311 struct libnet_in6_addr addr;
312
313 if (l == NULL)
314 {
315 return (in6addr_error);
316 }
317
318 if (getifaddrs(&ifaddr) != 0)
319 {
320 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
321 "%s(): getifaddrs(): %s\n", __func__, strerror(errno));
322 return (in6addr_error);
323 }
324
325 if (l->device == NULL)
326 {
327 if (libnet_select_device(l) == -1)
328 {
329 /* error msg set in libnet_select_device() */
330 return (in6addr_error);
331 }
332 }
333
334 for (p = ifaddr; p != NULL; p = p->ifa_next)
335 {
336 if ((strcmp(p->ifa_name, l->device) == 0) && (p->ifa_addr != NULL) &&
337 (p->ifa_addr->sa_family == AF_INET6))
338 {
339 memcpy(&addr.__u6_addr,
340 ((struct sockaddr_in6*)p->ifa_addr)->sin6_addr.s6_addr, 16);
341 freeifaddrs(ifaddr);
342 return (addr);
343 }
344 }
345
346 freeifaddrs(ifaddr);
347 return (in6addr_error);
348 }
349 #else
350 struct libnet_in6_addr
libnet_get_ipaddr6(libnet_t * l)351 libnet_get_ipaddr6(libnet_t *l)
352 {
353 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
354 "%s(): not yet Implemented\n", __func__);
355 return (in6addr_error);
356 }
357 #endif /* WIN32 */
358
359 #if !defined(__WIN32__)
360 uint32_t
libnet_get_ipaddr4(libnet_t * l)361 libnet_get_ipaddr4(libnet_t *l)
362 {
363 struct ifreq ifr;
364 register struct sockaddr_in *sin;
365 int fd;
366
367 if (l == NULL)
368 {
369 return (-1);
370 }
371
372 /* create dummy socket to perform an ioctl upon */
373 fd = socket(PF_INET, SOCK_DGRAM, 0);
374 if (fd == -1)
375 {
376 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
377 "%s(): socket(): %s\n", __func__, strerror(errno));
378 return (-1);
379 }
380
381 sin = (struct sockaddr_in *)&ifr.ifr_addr;
382
383 if (l->device == NULL)
384 {
385 if (libnet_select_device(l) == -1)
386 {
387 /* error msg set in libnet_select_device() */
388 close(fd);
389 return (-1);
390 }
391 }
392 strncpy(ifr.ifr_name, l->device, sizeof(ifr.ifr_name) -1);
393 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
394
395 ifr.ifr_addr.sa_family = AF_INET;
396
397 if (ioctl(fd, SIOCGIFADDR, (int8_t*) &ifr) < 0)
398 {
399 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
400 "%s(): ioctl(): %s\n", __func__, strerror(errno));
401 close(fd);
402 return (-1);
403 }
404 close(fd);
405 return (sin->sin_addr.s_addr);
406 }
407 #else
408 #include <Packet32.h>
409 uint32_t
libnet_get_ipaddr4(libnet_t * l)410 libnet_get_ipaddr4(libnet_t *l)
411 {
412 long npflen = 0;
413 struct sockaddr_in sin;
414 struct npf_if_addr ipbuff;
415
416 memset(&sin,0,sizeof(sin));
417 memset(&ipbuff,0,sizeof(ipbuff));
418
419 npflen = sizeof(ipbuff);
420 if (PacketGetNetInfoEx(l->device, &ipbuff, &npflen))
421 {
422 sin = *(struct sockaddr_in *)&ipbuff.IPAddress;
423 }
424 return (sin.sin_addr.s_addr);
425 }
426 #endif /* WIN32 */
427
428 uint8_t *
libnet_hex_aton(const char * s,int * len)429 libnet_hex_aton(const char *s, int *len)
430 {
431 uint8_t *buf;
432 int i;
433 int32_t l;
434 char *pp;
435
436 while (isspace(*s))
437 {
438 s++;
439 }
440 for (i = 0, *len = 0; s[i]; i++)
441 {
442 if (s[i] == ':')
443 {
444 (*len)++;
445 }
446 }
447 buf = malloc(*len + 1);
448 if (buf == NULL)
449 {
450 return (NULL);
451 }
452 /* expect len hex octets separated by ':' */
453 for (i = 0; i < *len + 1; i++)
454 {
455 l = strtol(s, &pp, 16);
456 if (pp == s || l > 0xff || l < 0)
457 {
458 *len = 0;
459 free(buf);
460 return (NULL);
461 }
462 if (!(*pp == ':' || (i == *len && (isspace(*pp) || *pp == '\0'))))
463 {
464 *len = 0;
465 free(buf);
466 return (NULL);
467 }
468 buf[i] = (uint8_t)l;
469 s = pp + 1;
470 }
471 /* return int8_tacter after the octets ala strtol(3) */
472 (*len)++;
473 return (buf);
474 }
475
476 /* EOF */
477