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 *)&in;
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 *)&in;
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