source: trunk/src/sh_ipvx.c@ 423

Last change on this file since 423 was 422, checked in by katerina, 12 years ago

Fix for tickets #326, #327.

File size: 11.8 KB
RevLine 
[295]1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2010 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <netdb.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
27#include <string.h>
28#include <ctype.h>
29
30#undef FIL__
31#define FIL__ _("sh_ipvx.c")
32
33#include "samhain.h"
34#define SH_NEED_GETHOSTBYXXX
35#include "sh_static.h"
36#include "sh_pthread.h"
37#include "sh_utils.h"
38#include "sh_ipvx.h"
39
40static int sh_ipvx_is_ipv4 (const char * addr)
41{
42 int j;
43 int len = sl_strlen(addr);
44
45 for (j = 0; j < len; ++j)
46 if ( (addr[j] < '0' || addr[j] > '9') && addr[j] != '.')
47 return (1 == 0);
48 return (1 == 1);
49}
50
51#if defined(USE_IPVX)
52static int sh_ipvx_is_ipv6 (const char * addr)
53{
[321]54 int j, k = 0;
[295]55 char c;
56 int len = sl_strlen(addr);
57
58 for (j = 0; j < len; ++j) {
59 c = addr[j];
60 if (( c < '0' || c > '9' ) &&
61 ( c < 'a' || c > 'f' ) &&
62 ( c < 'A' || c > 'F' ) &&
[314]63 ( c != ':') && ( c != '.'))
[295]64 return (1 == 0);
[321]65 else if (c == ':')
66 ++k;
67 else if (c == '.' && k < 3)
68 return (1 == 0); /* ::ffff:ipv4 */
[295]69 }
70 return (1 == 1);
71}
72#endif
73
74
75int sh_ipvx_is_numeric (const char * addr)
76{
77#if defined(USE_IPVX)
78 if (!sh_ipvx_is_ipv4(addr))
79 return sh_ipvx_is_ipv6(addr);
80 else
81 return (1 == 1);
82#else
83 return sh_ipvx_is_ipv4(addr);
84#endif
85}
86
87int sh_ipvx_isany (struct sh_sockaddr * a)
88{
[422]89#if defined(HOST_IS_CYGWIN)
90 /*
91 * Cygwin implementation gives 'missing braces around initializer'
92 * warning, thus replace it with correct version.
93 */
94#undef IN6ADDR_ANY_INIT
95#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
96#endif
97
[295]98#if defined(USE_IPVX)
99 struct in6_addr anyaddr = IN6ADDR_ANY_INIT;
100#endif
101
102 switch (a->ss_family)
103 {
104 case AF_INET:
105 if ((a->sin).sin_addr.s_addr == INADDR_ANY)
106 return 1;
107 break;
108#if defined(USE_IPVX)
109 case AF_INET6:
110 if (0 == memcmp(&((a->sin6).sin6_addr.s6_addr), &anyaddr, 16))
111 return 1;
112 break;
113#endif
114 }
115 return 0;
116}
117
118int sh_ipvx_cmp (struct sh_sockaddr * a, struct sh_sockaddr * b)
119{
120 if (a->ss_family != b->ss_family)
121 return 1;
122
123 switch (a->ss_family)
124 {
125 case AF_INET:
126 return memcmp(&((a->sin).sin_addr.s_addr), &((b->sin).sin_addr.s_addr), 4);
127 break;
128#if defined(USE_IPVX)
129 case AF_INET6:
130 return memcmp(&((a->sin6).sin6_addr.s6_addr), &((b->sin6).sin6_addr.s6_addr), 16);
131 break;
132#endif
133 }
134 return 1;
135}
136
137int sh_ipvx_ntoa (char * name, size_t name_size, struct sh_sockaddr * ss)
138{
139#if defined(USE_IPVX)
140 int len = (ss->ss_family == AF_INET) ?
141 sizeof(struct sockaddr_in) :
142 sizeof(struct sockaddr_in6);
143
144 int ret = getnameinfo(sh_ipvx_sockaddr_cast(ss), len,
145 name, name_size, NULL, 0, NI_NUMERICHOST);
146
[314]147
148 /* fprintf(stderr, "FIXME: Error %s (%d), name %s (%d)\n",
149 gai_strerror(ret), ret, name, name_size); */
150
151 if (ret != 0 && name_size > 0)
[295]152 {
[314]153 name[name_size-1] = '\0';
154
155 if (!sh_ipvx_is_numeric(name))
156 {
157 if (name_size > 7) {
158 name[0] = '0'; name[1] = '.'; name[2] = '0'; name[3] = '.';
159 name[4] = '0'; name[5] = '.'; name[6] = '0'; name[7] = '\0';
160 } else {
161 name[0] = '\0';
162 }
163 }
[295]164 }
165 return ret;
166#else
167 char * p = inet_ntoa((ss->sin).sin_addr);
168 sl_strlcpy(name, p, name_size);
169 return 0;
170#endif
171}
172
173struct sockaddr * sh_ipvx_sockaddr_cast (struct sh_sockaddr * ss)
174{
175#if defined(USE_IPVX)
176 if (ss->ss_family == AF_INET6)
177 return (struct sockaddr *) &(ss->sin6);
178#endif
179 return (struct sockaddr *) &(ss->sin);
180}
181
[314]182char * sh_ipvx_print_sockaddr (struct sockaddr * sa, int sa_family)
183{
184 struct sh_sockaddr ss;
185 static char ipbuf[SH_IP_BUF];
186
187 sh_ipvx_save(&ss, sa_family, sa);
188 sh_ipvx_ntoa (ipbuf, sizeof(ipbuf), &ss);
189 return ipbuf;
190}
191
[295]192void sh_ipvx_save(struct sh_sockaddr * ss, int sa_family, struct sockaddr * sa)
193{
194 /* memset(ss, '\0', sizeof(struct sh_sockaddr)); */
195
196 switch (sa_family)
197 {
198 case AF_INET:
199 ss->ss_family = AF_INET;
[314]200 memcpy(&(ss->sin), (struct sockaddr_in*) sa, sizeof(struct sockaddr_in));
[295]201 break;
202#if defined(USE_IPVX)
203 case AF_INET6:
204 ss->ss_family = AF_INET6;
[314]205 memcpy(&(ss->sin6), (struct sockaddr_in6*) sa, sizeof(struct sockaddr_in6));
[295]206 break;
207#endif
208 default:
209 break;
210 }
211 return;
212}
213
214int sh_ipvx_set_port(struct sh_sockaddr * ss, int port)
215{
216#if defined(USE_IPVX)
217
218 switch (ss->ss_family)
219 {
220 case AF_INET:
[380]221 (ss->sin).sin_family = AF_INET;
[295]222 (ss->sin).sin_port = htons (port);
223 break;
224 case AF_INET6:
[380]225 (ss->sin6).sin6_family = AF_INET6;
[295]226 (ss->sin6).sin6_port = htons (port);
227 break;
228 }
229 return 0;
230#else
[380]231 (ss->sin).sin_family = AF_INET;
[295]232 (ss->sin).sin_port = htons (port);
233 return 0;
234#endif
235}
236
[314]237int sh_ipvx_get_port(struct sockaddr * sa, int sa_family)
238{
239 int port = 0;
240#if defined(USE_IPVX)
241
242 switch (sa_family)
243 {
244 case AF_INET:
245 port = ntohs(((struct sockaddr_in *)sa)->sin_port);
246 break;
247 case AF_INET6:
248 port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
249 break;
250 }
251#else
[321]252 (void) sa_family;
253 port = ntohs(((struct sockaddr_in *)sa)->sin_port);
[314]254#endif
255 return port;
256}
257
[295]258int sh_ipvx_aton (const char * name, struct sh_sockaddr * ss)
259{
260#if defined(USE_IPVX)
261 int ret;
262 struct addrinfo hints;
263 struct addrinfo *res;
264
265 memset(&hints, '\0', sizeof(hints));
266 hints.ai_family = PF_UNSPEC;
267 hints.ai_flags = AI_NUMERICHOST;
268 ret = getaddrinfo(name, NULL, &hints, &res);
269
270 if (ret)
271 return 0;
272
273 memset(ss, '\0', sizeof(struct sh_sockaddr));
274 switch(res->ai_family)
275 {
276 case AF_INET:
277 memcpy(&(ss->sin), res->ai_addr, sizeof(struct sockaddr_in));
278 ss->ss_family = AF_INET;
279 break;
280 case AF_INET6:
281 memcpy(&(ss->sin6), res->ai_addr, sizeof(struct sockaddr_in6));
282 ss->ss_family = AF_INET6;
283 break;
284 default:
285 return 0;
286 break;
287 }
288 return 1;
289#else
290 int ret = inet_aton(name, &((ss->sin).sin_addr));
291 ss->ss_family = AF_INET;
292 return ret;
293#endif
294}
295
296#if !defined(USE_IPVX)
297static const char * sh_ipvx_h_name (struct hostent * host_entry)
298{
299 char ** p;
300 if (strchr(host_entry->h_name, '.')) {
301 return host_entry->h_name;
302 } else {
303 for (p = host_entry->h_aliases; *p; ++p) {
304 if (strchr(*p, '.'))
305 return *p;
306 }
307 }
308 return host_entry->h_name;
309}
310#endif
311
312static char * sh_tolower (char * s)
313{
314 char * ret = s;
315 if (s)
316 {
317 for (; *s; ++s)
318 {
319 *s = tolower((unsigned char) *s);
320 }
321 }
322 return ret;
323}
324
325static void * sh_dummy_out;
326
327char * sh_ipvx_canonical(const char * hostname, char * numeric, size_t nlen)
328{
329 volatile int flag = 0;
330 char *out = NULL;
331#if defined(USE_IPVX)
332 struct addrinfo hints;
333 struct addrinfo *res;
334 struct sockaddr *sa;
335 int salen;
336 int err;
337 struct sh_sockaddr ss;
338 const char * host;
339 char hostbuf[SH_BUFSIZE];
340
341 numeric[0] = '\0';
342
343 sh_dummy_out = (void *) &out;
344
345 if (sh_ipvx_is_numeric(hostname))
346 {
347 sh_ipvx_aton (hostname, &ss);
348 if (0 == getnameinfo(sh_ipvx_sockaddr_cast(&ss), SH_SS_LEN(ss),
349 hostbuf, sizeof(hostbuf), NULL, 0, NI_NAMEREQD))
350 host = hostbuf;
351 else
352 host = hostname;
353 }
354 else
355 {
356 host = hostname;
357 }
358
359 memset(&hints, 0, sizeof(hints));
360 hints.ai_family = PF_UNSPEC;
361#if defined(AI_CANONNAME)
362 hints.ai_flags = AI_CANONNAME;
363#endif
364
365 err = getaddrinfo(host, NULL, &hints, &res);
366 if (err == 0)
367 {
368#if defined(AI_CANONNAME)
369 if (res->ai_canonname && strlen(res->ai_canonname) > 0)
370 {
371 out = sh_util_strdup(res->ai_canonname);
372 sh_tolower (out);
373 if (strchr(out, '.'))
374 flag = 1;
375 }
376#endif
377
378 sa = res->ai_addr;
379 salen = res->ai_addrlen;
380 getnameinfo(sa, salen,
381 numeric, nlen, NULL, 0, NI_NUMERICHOST);
382
383 if (!flag)
384 out = SH_ALLOC(SH_PATHBUF);
385
386 while (res && !flag)
387 {
388 sa = res->ai_addr;
389 salen = res->ai_addrlen;
390
391 getnameinfo(sa, salen,
392 out, SH_PATHBUF, NULL, 0, 0);
393 sh_tolower (out);
394 if (strchr(out, '.'))
395 flag = 1;
396
397 res = res->ai_next;
398 }
399 }
400#else
401 struct hostent *he;
402 struct sh_sockaddr ss;
403 volatile int isNum = 0;
404 struct sockaddr_in *sin;
405
406 numeric[0] = '\0';
407
408 sh_dummy_out = (void *) &out;
409
410 if (sh_ipvx_is_numeric(hostname))
411 {
412 sh_ipvx_aton (hostname, &ss);
413 isNum = 1;
414 }
415
416
417 SH_MUTEX_LOCK(mutex_resolv);
418
419 if (isNum == 0)
420 {
421 he = sh_gethostbyname(hostname);
422 }
423 else
424 {
425 sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(&ss);
426 he = sh_gethostbyaddr(&(sin->sin_addr), sizeof(sin->sin_addr), AF_INET);
427 }
428
429 if (he != NULL)
430 {
431 out = sh_util_strdup(sh_ipvx_h_name(he));
432 sh_tolower (out);
433 sl_strlcpy (numeric,
434 inet_ntoa (*(struct in_addr *) he->h_addr),
435 nlen);
436 flag = 1;
437 }
438 SH_MUTEX_UNLOCK(mutex_resolv);
439#endif
440
441 if (flag)
442 return out;
443
444 if (out)
445 SH_FREE(out);
446 if (numeric[0] == '\0')
447 sl_strlcpy (numeric, _("0.0.0.0"), nlen);
448 return NULL;
449}
450
451char * sh_ipvx_addrtoname(struct sh_sockaddr * ss)
452{
453#if defined(USE_IPVX)
454 char namebuf[SH_BUFSIZE];
455
456 if (getnameinfo(sh_ipvx_sockaddr_cast(ss), SH_SSP_LEN(ss),
457 namebuf, sizeof(namebuf), NULL, 0, NI_NAMEREQD) != 0)
458 {
459 return NULL;
460 }
461 return sh_util_strdup(namebuf);
462#else
463 struct sockaddr_in *sin;
464 struct hostent *he;
465
466 sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(ss);
467
468 he = sh_gethostbyaddr(&(sin->sin_addr), sizeof(sin->sin_addr), AF_INET);
469
470 if (he && he->h_name)
471 {
472 return sh_util_strdup(he->h_name);
473 }
474
475 return NULL;
476#endif
477}
478
479int sh_ipvx_reverse_check_ok (char * peer, int port, struct sh_sockaddr * ss)
480{
481#if defined(USE_IPVX)
482 struct addrinfo *res;
483 struct addrinfo hints;
484 char sport[32];
485 struct addrinfo *p;
486
487 sl_snprintf(sport, sizeof(sport), "%d", port);
488
489 memset(&hints, '\0', sizeof(hints));
490 hints.ai_socktype = SOCK_STREAM;
491 hints.ai_flags = AI_ADDRCONFIG;
492
493 if (getaddrinfo(peer, sport, &hints, &res) != 0)
494 {
495 return 0;
496 }
497
498 p = res;
499 while (p != NULL)
500 {
501 if (ss->ss_family == p->ai_family)
502 {
503 struct sh_sockaddr pp;
504
505 char dst1[SH_IP_BUF];
506 char dst2[SH_IP_BUF];
507
508 sh_ipvx_save(&pp, p->ai_family, p->ai_addr);
509
510 sh_ipvx_ntoa (dst1, sizeof(dst1), &pp);
511 sh_ipvx_ntoa (dst2, sizeof(dst2), ss);
512
513 if (0 == sl_strcmp(dst1, dst2))
514 {
515 return 1;
516 }
517 }
518 p = p->ai_next;
519 }
520 freeaddrinfo(res);
521#else
522 struct hostent * he;
523 char ** p;
524 struct sockaddr_in * sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(ss);
525
526 (void) port;
527
528 he = sh_gethostbyname(peer);
529 if (he != NULL)
530 {
531 for (p = he->h_addr_list; *p; ++p)
532 {
533 if (0 == memcmp (*p, &(sin->sin_addr), sizeof(in_addr_t)) )
534 return 1;
535 }
536 }
537#endif
538 return 0;
539}
Note: See TracBrowser for help on using the repository browser.