source: trunk/src/sh_ipvx.c@ 448

Last change on this file since 448 was 448, checked in by katerina, 11 years ago

Fic for ticket #350 (numeric hostnames).

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