Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | /* |
2 | * $Id: libnet_resolve.c,v 1.21 2005/11/29 21:49:08 carlosc 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 | char * | |
43 | libnet_addr2name4(u_int32_t in, u_int8_t use_name) | |
44 | { | |
45 | #define HOSTNAME_SIZE 512 | |
46 | static char hostname[HOSTNAME_SIZE+1], hostname2[HOSTNAME_SIZE+1]; | |
47 | static u_int16_t which; | |
48 | u_int8_t *p; | |
49 | ||
50 | struct hostent *host_ent = NULL; | |
51 | struct in_addr addr; | |
52 | ||
53 | /* | |
54 | * Swap to the other buffer. We swap static buffers to avoid having to | |
55 | * pass in a int8_t *. This makes the code that calls this function more | |
56 | * intuitive, but makes this function ugly. This function is seriously | |
57 | * non-reentrant. For threaded applications (or for signal handler code) | |
58 | * use host_lookup_r(). | |
59 | */ | |
60 | which++; | |
61 | ||
62 | if (use_name == LIBNET_RESOLVE) | |
63 | { | |
64 | addr.s_addr = in; | |
65 | host_ent = gethostbyaddr((int8_t *)&addr, sizeof(struct in_addr), AF_INET); | |
66 | /* if this fails, we silently ignore the error and move to plan b! */ | |
67 | } | |
68 | if (!host_ent) | |
69 | { | |
70 | ||
71 | p = (u_int8_t *)∈ | |
72 | snprintf(((which % 2) ? hostname : hostname2), HOSTNAME_SIZE, | |
73 | "%d.%d.%d.%d", | |
74 | (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255)); | |
75 | } | |
76 | else if (use_name == LIBNET_RESOLVE) | |
77 | { | |
78 | char *ptr = ((which % 2) ? hostname : hostname2); | |
79 | strncpy(ptr, host_ent->h_name, HOSTNAME_SIZE); | |
80 | ptr[HOSTNAME_SIZE] = '\0'; | |
81 | ||
82 | } | |
83 | return (which % 2) ? (hostname) : (hostname2); | |
84 | } | |
85 | ||
86 | void | |
87 | libnet_addr2name4_r(u_int32_t in, u_int8_t use_name, char *hostname, | |
88 | int hostname_len) | |
89 | { | |
90 | u_int8_t *p; | |
91 | struct hostent *host_ent = NULL; | |
92 | struct in_addr addr; | |
93 | ||
94 | if (use_name == LIBNET_RESOLVE) | |
95 | { | |
96 | addr.s_addr = in; | |
97 | host_ent = gethostbyaddr((int8_t *)&addr, sizeof(struct in_addr), | |
98 | AF_INET); | |
99 | } | |
100 | if (!host_ent) | |
101 | { | |
102 | p = (u_int8_t *)∈ | |
103 | snprintf(hostname, hostname_len, "%d.%d.%d.%d", | |
104 | (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255)); | |
105 | } | |
106 | else | |
107 | { | |
108 | strncpy(hostname, host_ent->h_name, hostname_len - 1); | |
109 | hostname[sizeof(hostname) - 1] = '\0'; | |
110 | } | |
111 | } | |
112 | ||
113 | u_int32_t | |
114 | libnet_name2addr4(libnet_t *l, char *host_name, u_int8_t use_name) | |
115 | { | |
116 | struct in_addr addr; | |
117 | struct hostent *host_ent; | |
118 | u_int32_t m; | |
119 | u_int val; | |
120 | int i; | |
121 | ||
122 | if (use_name == LIBNET_RESOLVE) | |
123 | { | |
124 | if ((addr.s_addr = inet_addr(host_name)) == -1) | |
125 | { | |
126 | if (!(host_ent = gethostbyname(host_name))) | |
127 | { | |
128 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
129 | "%s(): %s\n", __func__, strerror(errno)); | |
130 | /* XXX - this is actually 255.255.255.255 */ | |
131 | return (-1); | |
132 | } | |
133 | memcpy(&addr.s_addr, host_ent->h_addr, host_ent->h_length); | |
134 | } | |
135 | /* network byte order */ | |
136 | return (addr.s_addr); | |
137 | } | |
138 | else | |
139 | { | |
140 | /* | |
141 | * We only want dots 'n decimals. | |
142 | */ | |
143 | if (!isdigit(host_name[0])) | |
144 | { | |
145 | if (l) | |
146 | { | |
147 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
148 | "%s(): expecting dots and decimals\n", __func__); | |
149 | } | |
150 | /* XXX - this is actually 255.255.255.255 */ | |
151 | return (-1); | |
152 | } | |
153 | ||
154 | m = 0; | |
155 | for (i = 0; i < 4; i++) | |
156 | { | |
157 | m <<= 8; | |
158 | if (*host_name) | |
159 | { | |
160 | val = 0; | |
161 | while (*host_name && *host_name != '.') | |
162 | { | |
163 | val *= 10; | |
164 | val += *host_name - '0'; | |
165 | if (val > 255) | |
166 | { | |
167 | if (l) | |
168 | { | |
169 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
170 | "%s(): value greater than 255\n", __func__); | |
171 | } | |
172 | /* XXX - this is actually 255.255.255.255 */ | |
173 | return (-1); | |
174 | } | |
175 | host_name++; | |
176 | } | |
177 | m |= val; | |
178 | if (*host_name) | |
179 | { | |
180 | host_name++; | |
181 | } | |
182 | } | |
183 | } | |
184 | /* host byte order */ | |
185 | return (ntohl(m)); | |
186 | } | |
187 | } | |
188 | ||
189 | void | |
190 | libnet_addr2name6_r(struct libnet_in6_addr addr, u_int8_t use_name, | |
191 | char *host_name, int host_name_len) | |
192 | { | |
193 | struct hostent *host_ent = NULL; | |
194 | ||
195 | if (use_name == LIBNET_RESOLVE) | |
196 | { | |
197 | #ifdef HAVE_SOLARIS | |
198 | #ifdef HAVE_SOLARIS_IPV6 | |
199 | host_ent = getipnodebyaddr((int8_t *)&addr, sizeof(struct in_addr), | |
200 | AF_INET6, NULL); | |
201 | #else | |
202 | /* XXX - Gah! Can't report error! */ | |
203 | host_ent = NULL; | |
204 | #endif | |
205 | #else | |
206 | host_ent = gethostbyaddr((int8_t *)&addr, sizeof(struct in_addr), | |
207 | AF_INET6); | |
208 | #endif | |
209 | } | |
210 | if (!host_ent) | |
211 | { | |
212 | #if !defined(__WIN32__) /* Silence Win32 warning */ | |
213 | inet_ntop(AF_INET6, &addr, host_name, host_name_len); | |
214 | #endif | |
215 | } | |
216 | else | |
217 | { | |
218 | strncpy(host_name, host_ent->h_name, host_name_len -1); | |
219 | host_name[sizeof(host_name) - 1] = '\0'; | |
220 | } | |
221 | } | |
222 | ||
223 | const struct libnet_in6_addr in6addr_error = IN6ADDR_ERROR_INIT; | |
224 | ||
225 | struct libnet_in6_addr | |
226 | libnet_name2addr6(libnet_t *l, char *host_name, u_int8_t use_name) | |
227 | { | |
228 | #if !defined (__WIN32__) | |
229 | struct libnet_in6_addr addr; | |
230 | struct hostent *host_ent; | |
231 | #endif | |
232 | ||
233 | if (use_name == LIBNET_RESOLVE) | |
234 | { | |
235 | #ifdef __WIN32__ | |
236 | /* XXX - we don't support this yet */ | |
237 | if (l) | |
238 | { | |
239 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
240 | "%s(): can't resolve IPv6 addresses\n", __func__); | |
241 | } | |
242 | return (in6addr_error); | |
243 | #else | |
244 | #ifdef HAVE_SOLARIS | |
245 | #ifdef HAVE_SOLARIS_IPV6 | |
246 | if (!(host_ent = getipnodebyname((int8_t *)&addr, | |
247 | sizeof(struct in_addr), AF_INET6, NULL))) | |
248 | #else | |
249 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
250 | "%s(): %s\n", __func__, strerror(errno)); | |
251 | return (in6addr_error); | |
252 | #endif | |
253 | #else | |
254 | if (!(host_ent = gethostbyname2(host_name, AF_INET6))) | |
255 | #endif | |
256 | { | |
257 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
258 | "%s(): %s", __func__, strerror(errno)); | |
259 | return (in6addr_error); | |
260 | } | |
261 | memcpy(&addr, host_ent->h_addr, host_ent->h_length); | |
262 | return (addr); | |
263 | #endif /* !__WIN32__ */ | |
264 | } | |
265 | else | |
266 | { | |
267 | #if defined(__WIN32__) /* Silence Win32 warning */ | |
268 | if (l) | |
269 | { | |
270 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
271 | "%s(): can't resolve IPv6 addresses.\n", __func__); | |
272 | } | |
273 | return (in6addr_error); | |
274 | #else | |
275 | if(!inet_pton(AF_INET6, host_name, &addr)) | |
276 | { | |
277 | if (l) | |
278 | { | |
279 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
280 | "%s(): invalid IPv6 address\n", __func__); | |
281 | } | |
282 | return (in6addr_error); | |
283 | } | |
284 | return (addr); | |
285 | #endif | |
286 | } | |
287 | } | |
288 | ||
289 | struct libnet_in6_addr | |
290 | libnet_get_ipaddr6(libnet_t *l) | |
291 | { | |
292 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
293 | "%s(): not yet Implemented\n", __func__); | |
294 | return (in6addr_error); | |
295 | } | |
296 | ||
297 | #if !defined(__WIN32__) | |
298 | u_int32_t | |
299 | libnet_get_ipaddr4(libnet_t *l) | |
300 | { | |
301 | struct ifreq ifr; | |
302 | register struct sockaddr_in *sin; | |
303 | int fd; | |
304 | ||
305 | if (l == NULL) | |
306 | { | |
307 | return (-1); | |
308 | } | |
309 | ||
310 | /* create dummy socket to perform an ioctl upon */ | |
311 | fd = socket(PF_INET, SOCK_DGRAM, 0); | |
312 | if (fd == -1) | |
313 | { | |
314 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
315 | "%s(): socket(): %s\n", __func__, strerror(errno)); | |
316 | return (-1); | |
317 | } | |
318 | ||
319 | sin = (struct sockaddr_in *)&ifr.ifr_addr; | |
320 | ||
321 | if (l->device == NULL) | |
322 | { | |
323 | if (libnet_select_device(l) == -1) | |
324 | { | |
325 | /* error msg set in libnet_select_device() */ | |
326 | close(fd); | |
327 | return (-1); | |
328 | } | |
329 | } | |
330 | strncpy(ifr.ifr_name, l->device, sizeof(ifr.ifr_name) -1); | |
331 | ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; | |
332 | ||
333 | ifr.ifr_addr.sa_family = AF_INET; | |
334 | ||
335 | if (ioctl(fd, SIOCGIFADDR, (int8_t*) &ifr) < 0) | |
336 | { | |
337 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
338 | "%s(): ioctl(): %s\n", __func__, strerror(errno)); | |
339 | close(fd); | |
340 | return (-1); | |
341 | } | |
342 | close(fd); | |
343 | return (sin->sin_addr.s_addr); | |
344 | } | |
345 | #else | |
346 | #include <Packet32.h> | |
347 | u_int32_t | |
348 | libnet_get_ipaddr4(libnet_t *l) | |
349 | { | |
350 | long npflen = 0; | |
351 | struct sockaddr_in sin; | |
352 | struct npf_if_addr ipbuff; | |
353 | ||
354 | memset(&sin,0,sizeof(sin)); | |
355 | memset(&ipbuff,0,sizeof(ipbuff)); | |
356 | ||
357 | npflen = sizeof(ipbuff); | |
358 | if (PacketGetNetInfoEx(l->device, &ipbuff, &npflen)) | |
359 | { | |
360 | sin = *(struct sockaddr_in *)&ipbuff.IPAddress; | |
361 | } | |
362 | return (sin.sin_addr.s_addr); | |
363 | } | |
364 | #endif /* WIN32 */ | |
365 | ||
366 | u_int8_t * | |
367 | libnet_hex_aton(int8_t *s, int *len) | |
368 | { | |
369 | u_int8_t *buf; | |
370 | int i; | |
371 | int32_t l; | |
372 | int8_t *pp; | |
373 | ||
374 | while (isspace(*s)) | |
375 | { | |
376 | s++; | |
377 | } | |
378 | for (i = 0, *len = 0; s[i]; i++) | |
379 | { | |
380 | if (s[i] == ':') | |
381 | { | |
382 | (*len)++; | |
383 | } | |
384 | } | |
385 | buf = malloc(*len + 1); | |
386 | if (buf == NULL) | |
387 | { | |
388 | return (NULL); | |
389 | } | |
390 | /* expect len hex octets separated by ':' */ | |
391 | for (i = 0; i < *len + 1; i++) | |
392 | { | |
393 | l = strtol(s, (char **)&pp, 16); | |
394 | if (pp == s || l > 0xff || l < 0) | |
395 | { | |
396 | *len = 0; | |
397 | free(buf); | |
398 | return (NULL); | |
399 | } | |
400 | if (!(*pp == ':' || (i == *len && (isspace(*pp) || *pp == '\0')))) | |
401 | { | |
402 | *len = 0; | |
403 | free(buf); | |
404 | return (NULL); | |
405 | } | |
406 | buf[i] = (u_int8_t)l; | |
407 | s = pp + 1; | |
408 | } | |
409 | /* return int8_tacter after the octets ala strtol(3) */ | |
410 | (*len)++; | |
411 | return (buf); | |
412 | } | |
413 | ||
414 | /* EOF */ |