source: trunk/src/sh_ipvx.c@ 526

Last change on this file since 526 was 526, checked in by katerina, 7 years ago

Fix for ticket #421 (spurious port detections) and ticket #422 (PortCheckSkip bug).

File size: 12.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;
[448]43 int count = 0;
[295]44 int len = sl_strlen(addr);
[448]45 unsigned int a, b, c, d;
[295]46
[448]47 if (len > 15) /* 3*4 + 3 dots */
48 return (1 == 0);
49
50 for (j = 0; j < len; ++j) {
[295]51 if ( (addr[j] < '0' || addr[j] > '9') && addr[j] != '.')
52 return (1 == 0);
[448]53 if (addr[j] == '.') ++count;
54 }
55
56 if (count != 3)
57 return (1 == 0);
58
59 if (sscanf(addr, "%3u.%3u.%3u.%3u", &a, &b, &c, &d) != 4)
60 return( 1 == 0 );
61
62 if ((a|b|c|d) > 255)
63 return( 1 == 0 );
64
[295]65 return (1 == 1);
66}
67
68#if defined(USE_IPVX)
69static int sh_ipvx_is_ipv6 (const char * addr)
70{
[321]71 int j, k = 0;
[295]72 char c;
73 int len = sl_strlen(addr);
74
75 for (j = 0; j < len; ++j) {
76 c = addr[j];
77 if (( c < '0' || c > '9' ) &&
78 ( c < 'a' || c > 'f' ) &&
79 ( c < 'A' || c > 'F' ) &&
[314]80 ( c != ':') && ( c != '.'))
[295]81 return (1 == 0);
[321]82 else if (c == ':')
83 ++k;
[449]84 else if (c == '.' && k < 2)
[321]85 return (1 == 0); /* ::ffff:ipv4 */
[295]86 }
[449]87 if (k < 2 || k > 7)
88 return (1 == 0);
89
[295]90 return (1 == 1);
91}
92#endif
93
94
95int sh_ipvx_is_numeric (const char * addr)
96{
97#if defined(USE_IPVX)
98 if (!sh_ipvx_is_ipv4(addr))
99 return sh_ipvx_is_ipv6(addr);
100 else
101 return (1 == 1);
102#else
103 return sh_ipvx_is_ipv4(addr);
104#endif
105}
106
107int sh_ipvx_isany (struct sh_sockaddr * a)
108{
[422]109#if defined(HOST_IS_CYGWIN)
110 /*
111 * Cygwin implementation gives 'missing braces around initializer'
112 * warning, thus replace it with correct version.
113 */
114#undef IN6ADDR_ANY_INIT
115#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
116#endif
117
[295]118#if defined(USE_IPVX)
119 struct in6_addr anyaddr = IN6ADDR_ANY_INIT;
120#endif
121
122 switch (a->ss_family)
123 {
124 case AF_INET:
125 if ((a->sin).sin_addr.s_addr == INADDR_ANY)
126 return 1;
127 break;
128#if defined(USE_IPVX)
129 case AF_INET6:
130 if (0 == memcmp(&((a->sin6).sin6_addr.s6_addr), &anyaddr, 16))
131 return 1;
132 break;
133#endif
134 }
135 return 0;
136}
137
138int sh_ipvx_cmp (struct sh_sockaddr * a, struct sh_sockaddr * b)
139{
140 if (a->ss_family != b->ss_family)
141 return 1;
142
143 switch (a->ss_family)
144 {
145 case AF_INET:
146 return memcmp(&((a->sin).sin_addr.s_addr), &((b->sin).sin_addr.s_addr), 4);
147 break;
148#if defined(USE_IPVX)
149 case AF_INET6:
150 return memcmp(&((a->sin6).sin6_addr.s6_addr), &((b->sin6).sin6_addr.s6_addr), 16);
151 break;
152#endif
153 }
154 return 1;
155}
156
157int sh_ipvx_ntoa (char * name, size_t name_size, struct sh_sockaddr * ss)
158{
159#if defined(USE_IPVX)
160 int len = (ss->ss_family == AF_INET) ?
161 sizeof(struct sockaddr_in) :
162 sizeof(struct sockaddr_in6);
163
164 int ret = getnameinfo(sh_ipvx_sockaddr_cast(ss), len,
165 name, name_size, NULL, 0, NI_NUMERICHOST);
166
[314]167 if (ret != 0 && name_size > 0)
[295]168 {
[314]169 name[name_size-1] = '\0';
170
171 if (!sh_ipvx_is_numeric(name))
172 {
173 if (name_size > 7) {
174 name[0] = '0'; name[1] = '.'; name[2] = '0'; name[3] = '.';
175 name[4] = '0'; name[5] = '.'; name[6] = '0'; name[7] = '\0';
176 } else {
177 name[0] = '\0';
178 }
179 }
[295]180 }
181 return ret;
182#else
183 char * p = inet_ntoa((ss->sin).sin_addr);
184 sl_strlcpy(name, p, name_size);
185 return 0;
186#endif
187}
188
189struct sockaddr * sh_ipvx_sockaddr_cast (struct sh_sockaddr * ss)
190{
191#if defined(USE_IPVX)
192 if (ss->ss_family == AF_INET6)
193 return (struct sockaddr *) &(ss->sin6);
194#endif
195 return (struct sockaddr *) &(ss->sin);
196}
197
[314]198char * sh_ipvx_print_sockaddr (struct sockaddr * sa, int sa_family)
199{
200 struct sh_sockaddr ss;
201 static char ipbuf[SH_IP_BUF];
202
203 sh_ipvx_save(&ss, sa_family, sa);
204 sh_ipvx_ntoa (ipbuf, sizeof(ipbuf), &ss);
205 return ipbuf;
206}
207
[295]208void sh_ipvx_save(struct sh_sockaddr * ss, int sa_family, struct sockaddr * sa)
209{
210 /* memset(ss, '\0', sizeof(struct sh_sockaddr)); */
211
212 switch (sa_family)
213 {
214 case AF_INET:
215 ss->ss_family = AF_INET;
[314]216 memcpy(&(ss->sin), (struct sockaddr_in*) sa, sizeof(struct sockaddr_in));
[295]217 break;
218#if defined(USE_IPVX)
219 case AF_INET6:
220 ss->ss_family = AF_INET6;
[314]221 memcpy(&(ss->sin6), (struct sockaddr_in6*) sa, sizeof(struct sockaddr_in6));
[295]222 break;
223#endif
224 default:
225 break;
226 }
227 return;
228}
229
230int sh_ipvx_set_port(struct sh_sockaddr * ss, int port)
231{
232#if defined(USE_IPVX)
233
234 switch (ss->ss_family)
235 {
236 case AF_INET:
[380]237 (ss->sin).sin_family = AF_INET;
[295]238 (ss->sin).sin_port = htons (port);
239 break;
240 case AF_INET6:
[380]241 (ss->sin6).sin6_family = AF_INET6;
[295]242 (ss->sin6).sin6_port = htons (port);
243 break;
244 }
245 return 0;
246#else
[380]247 (ss->sin).sin_family = AF_INET;
[295]248 (ss->sin).sin_port = htons (port);
249 return 0;
250#endif
251}
252
[526]253int sh_ipvx_get_port(struct sh_sockaddr * sa)
[314]254{
255 int port = 0;
256#if defined(USE_IPVX)
257
[526]258 switch (sa->ss_family)
[314]259 {
260 case AF_INET:
[526]261 port = ntohs((sa->sin).sin_port);
[314]262 break;
263 case AF_INET6:
[526]264 port = ntohs((sa->sin6).sin6_port);
[314]265 break;
266 }
267#else
[526]268 port = ntohs((sa->sin).sin_port);
[314]269#endif
270 return port;
271}
272
[295]273int sh_ipvx_aton (const char * name, struct sh_sockaddr * ss)
274{
275#if defined(USE_IPVX)
276 int ret;
277 struct addrinfo hints;
278 struct addrinfo *res;
279
280 memset(&hints, '\0', sizeof(hints));
281 hints.ai_family = PF_UNSPEC;
282 hints.ai_flags = AI_NUMERICHOST;
283 ret = getaddrinfo(name, NULL, &hints, &res);
284
285 if (ret)
286 return 0;
287
288 memset(ss, '\0', sizeof(struct sh_sockaddr));
289 switch(res->ai_family)
290 {
291 case AF_INET:
292 memcpy(&(ss->sin), res->ai_addr, sizeof(struct sockaddr_in));
293 ss->ss_family = AF_INET;
294 break;
295 case AF_INET6:
296 memcpy(&(ss->sin6), res->ai_addr, sizeof(struct sockaddr_in6));
297 ss->ss_family = AF_INET6;
298 break;
299 default:
300 return 0;
301 break;
302 }
[509]303 freeaddrinfo(res);
[295]304 return 1;
305#else
306 int ret = inet_aton(name, &((ss->sin).sin_addr));
307 ss->ss_family = AF_INET;
308 return ret;
309#endif
310}
311
312#if !defined(USE_IPVX)
313static const char * sh_ipvx_h_name (struct hostent * host_entry)
314{
315 char ** p;
316 if (strchr(host_entry->h_name, '.')) {
317 return host_entry->h_name;
318 } else {
319 for (p = host_entry->h_aliases; *p; ++p) {
320 if (strchr(*p, '.'))
321 return *p;
322 }
323 }
324 return host_entry->h_name;
325}
326#endif
327
328static char * sh_tolower (char * s)
329{
330 char * ret = s;
331 if (s)
332 {
333 for (; *s; ++s)
334 {
335 *s = tolower((unsigned char) *s);
336 }
337 }
338 return ret;
339}
340
[481]341void * sh_dummy_341_out;
[295]342
343char * sh_ipvx_canonical(const char * hostname, char * numeric, size_t nlen)
344{
345 volatile int flag = 0;
346 char *out = NULL;
347#if defined(USE_IPVX)
348 struct addrinfo hints;
349 struct addrinfo *res;
350 struct sockaddr *sa;
351 int salen;
352 int err;
353 struct sh_sockaddr ss;
354 const char * host;
355 char hostbuf[SH_BUFSIZE];
356
357 numeric[0] = '\0';
358
[481]359 sh_dummy_341_out = (void *) &out;
[295]360
361 if (sh_ipvx_is_numeric(hostname))
362 {
363 sh_ipvx_aton (hostname, &ss);
364 if (0 == getnameinfo(sh_ipvx_sockaddr_cast(&ss), SH_SS_LEN(ss),
365 hostbuf, sizeof(hostbuf), NULL, 0, NI_NAMEREQD))
366 host = hostbuf;
367 else
368 host = hostname;
369 }
370 else
371 {
372 host = hostname;
373 }
374
375 memset(&hints, 0, sizeof(hints));
376 hints.ai_family = PF_UNSPEC;
377#if defined(AI_CANONNAME)
378 hints.ai_flags = AI_CANONNAME;
379#endif
380
381 err = getaddrinfo(host, NULL, &hints, &res);
382 if (err == 0)
383 {
[509]384 struct addrinfo * res_orig = res;
385
[295]386#if defined(AI_CANONNAME)
387 if (res->ai_canonname && strlen(res->ai_canonname) > 0)
388 {
389 out = sh_util_strdup(res->ai_canonname);
390 sh_tolower (out);
391 if (strchr(out, '.'))
392 flag = 1;
393 }
394#endif
395
396 sa = res->ai_addr;
397 salen = res->ai_addrlen;
398 getnameinfo(sa, salen,
399 numeric, nlen, NULL, 0, NI_NUMERICHOST);
400
401 if (!flag)
402 out = SH_ALLOC(SH_PATHBUF);
403
404 while (res && !flag)
405 {
406 sa = res->ai_addr;
407 salen = res->ai_addrlen;
408
409 getnameinfo(sa, salen,
410 out, SH_PATHBUF, NULL, 0, 0);
411 sh_tolower (out);
412 if (strchr(out, '.'))
413 flag = 1;
414
415 res = res->ai_next;
416 }
[509]417
418 freeaddrinfo(res_orig);
[295]419 }
420#else
421 struct hostent *he;
422 struct sh_sockaddr ss;
423 volatile int isNum = 0;
424 struct sockaddr_in *sin;
425
426 numeric[0] = '\0';
427
[481]428 sh_dummy_341_out = (void *) &out;
[295]429
430 if (sh_ipvx_is_numeric(hostname))
431 {
432 sh_ipvx_aton (hostname, &ss);
433 isNum = 1;
434 }
435
436
437 SH_MUTEX_LOCK(mutex_resolv);
438
439 if (isNum == 0)
440 {
441 he = sh_gethostbyname(hostname);
442 }
443 else
444 {
445 sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(&ss);
446 he = sh_gethostbyaddr(&(sin->sin_addr), sizeof(sin->sin_addr), AF_INET);
447 }
448
449 if (he != NULL)
450 {
451 out = sh_util_strdup(sh_ipvx_h_name(he));
452 sh_tolower (out);
453 sl_strlcpy (numeric,
454 inet_ntoa (*(struct in_addr *) he->h_addr),
455 nlen);
456 flag = 1;
457 }
458 SH_MUTEX_UNLOCK(mutex_resolv);
459#endif
460
461 if (flag)
462 return out;
463
464 if (out)
465 SH_FREE(out);
466 if (numeric[0] == '\0')
467 sl_strlcpy (numeric, _("0.0.0.0"), nlen);
468 return NULL;
469}
470
471char * sh_ipvx_addrtoname(struct sh_sockaddr * ss)
472{
473#if defined(USE_IPVX)
474 char namebuf[SH_BUFSIZE];
475
476 if (getnameinfo(sh_ipvx_sockaddr_cast(ss), SH_SSP_LEN(ss),
477 namebuf, sizeof(namebuf), NULL, 0, NI_NAMEREQD) != 0)
478 {
479 return NULL;
480 }
481 return sh_util_strdup(namebuf);
482#else
483 struct sockaddr_in *sin;
484 struct hostent *he;
485
486 sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(ss);
487
488 he = sh_gethostbyaddr(&(sin->sin_addr), sizeof(sin->sin_addr), AF_INET);
489
490 if (he && he->h_name)
491 {
492 return sh_util_strdup(he->h_name);
493 }
494
495 return NULL;
496#endif
497}
498
499int sh_ipvx_reverse_check_ok (char * peer, int port, struct sh_sockaddr * ss)
500{
501#if defined(USE_IPVX)
502 struct addrinfo *res;
503 struct addrinfo hints;
504 char sport[32];
505 struct addrinfo *p;
506
507 sl_snprintf(sport, sizeof(sport), "%d", port);
508
509 memset(&hints, '\0', sizeof(hints));
510 hints.ai_socktype = SOCK_STREAM;
511 hints.ai_flags = AI_ADDRCONFIG;
512
513 if (getaddrinfo(peer, sport, &hints, &res) != 0)
514 {
515 return 0;
516 }
517
518 p = res;
519 while (p != NULL)
520 {
521 if (ss->ss_family == p->ai_family)
522 {
523 struct sh_sockaddr pp;
524
525 char dst1[SH_IP_BUF];
526 char dst2[SH_IP_BUF];
527
528 sh_ipvx_save(&pp, p->ai_family, p->ai_addr);
529
530 sh_ipvx_ntoa (dst1, sizeof(dst1), &pp);
531 sh_ipvx_ntoa (dst2, sizeof(dst2), ss);
532
533 if (0 == sl_strcmp(dst1, dst2))
534 {
535 return 1;
536 }
537 }
538 p = p->ai_next;
539 }
540 freeaddrinfo(res);
541#else
542 struct hostent * he;
543 char ** p;
544 struct sockaddr_in * sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(ss);
545
546 (void) port;
547
548 he = sh_gethostbyname(peer);
549 if (he != NULL)
550 {
551 for (p = he->h_addr_list; *p; ++p)
552 {
553 if (0 == memcmp (*p, &(sin->sin_addr), sizeof(in_addr_t)) )
554 return 1;
555 }
556 }
557#endif
558 return 0;
559}
[448]560
561#ifdef SH_CUTEST
562#include <stdlib.h>
563#include "CuTest.h"
564
565void Test_ipvx (CuTest *tc) {
566
567 int result;
568
569 result = sh_ipvx_is_ipv4("123456789");
570 CuAssertTrue(tc, result == FALSE);
571
572 result = sh_ipvx_is_ipv4("123456789123...");
573 CuAssertTrue(tc, result == FALSE);
574
575 result = sh_ipvx_is_ipv4("123.456.789.123");
576 CuAssertTrue(tc, result == FALSE);
577
578 result = sh_ipvx_is_ipv4("123.156.189.254");
579 CuAssertTrue(tc, result == TRUE);
580
581 result = sh_ipvx_is_ipv4("255.255.255.255");
582 CuAssertTrue(tc, result == TRUE);
583
584 result = sh_ipvx_is_ipv4("0.0.0.0");
585 CuAssertTrue(tc, result == TRUE);
586
587 result = sh_ipvx_is_ipv4("0022.156.189.254");
588 CuAssertTrue(tc, result == FALSE);
589
590 result = sh_ipvx_is_ipv4("999999999.1.1.2");
591 CuAssertTrue(tc, result == FALSE);
592
593}
594#endif
595
Note: See TracBrowser for help on using the repository browser.