source: trunk/src/sh_ipvx.c

Last change on this file was 560, checked in by katerina, 13 months ago

Fix for ticket #449 (gcc 10 compile issues).

File size: 13.2 KB
Line 
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 count = 0;
44  int len = sl_strlen(addr);
45  unsigned int a, b, c, d;
46 
47  if (len > 15) /* 3*4 + 3 dots */
48    return (1 == 0);
49
50  for (j = 0; j < len; ++j) {
51    if ( (addr[j] < '0' || addr[j] > '9') && addr[j] != '.')
52      return (1 == 0);
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
65  return (1 == 1);
66}
67
68#if defined(USE_IPVX)
69static int sh_ipvx_is_ipv6 (const char * addr)
70{
71  int j, k = 0;
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' ) &&
80        ( c != ':') && ( c != '.'))
81      return (1 == 0);
82    else if (c == ':')
83      ++k;
84    else if (c == '.' && k < 2)
85      return (1 == 0); /* ::ffff:ipv4 */
86  }
87  if (k < 2 || k > 7)
88    return (1 == 0);
89
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{
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
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
167  if (ret != 0 && name_size > 0)
168    {
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        }
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
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  memset(&ss, 0, sizeof(struct sh_sockaddr));
204  sh_ipvx_save(&ss, sa_family, sa);
205  sh_ipvx_ntoa (ipbuf, sizeof(ipbuf), &ss);
206  return ipbuf;
207}
208
209void sh_ipvx_save(struct sh_sockaddr * ss, int sa_family, struct sockaddr * sa)
210{
211  switch (sa_family)
212    {
213    case AF_INET:
214      ss->ss_family = AF_INET;
215      memcpy(&(ss->sin), (struct sockaddr_in*) sa, sizeof(struct sockaddr_in));
216      break;
217#if defined(USE_IPVX)
218    case AF_INET6:
219      ss->ss_family = AF_INET6;
220      memcpy(&(ss->sin6), (struct sockaddr_in6*) sa, sizeof(struct sockaddr_in6));
221      break;
222#endif
223    default:
224      break;
225    }
226  return;
227}
228
229int sh_ipvx_set_port(struct sh_sockaddr * ss, int port)
230{
231#if defined(USE_IPVX)
232
233  switch (ss->ss_family)
234    {
235    case AF_INET:
236      (ss->sin).sin_family = AF_INET;
237      (ss->sin).sin_port = htons (port);
238      break;
239    case AF_INET6:
240      (ss->sin6).sin6_family = AF_INET6;
241      (ss->sin6).sin6_port = htons (port);
242      break;
243    }
244  return 0;
245#else
246  (ss->sin).sin_family = AF_INET;
247  (ss->sin).sin_port = htons (port);
248  return 0;
249#endif
250}
251
252int sh_ipvx_get_port(struct sh_sockaddr * sa)
253{
254  int port = 0;
255#if defined(USE_IPVX)
256
257  switch (sa->ss_family)
258    {
259    case AF_INET:
260      port = ntohs((sa->sin).sin_port);
261      break;
262    case AF_INET6:
263      port = ntohs((sa->sin6).sin6_port);
264      break;
265    }
266#else
267  port = ntohs((sa->sin).sin_port);
268#endif
269  return port;
270}
271
272int sh_ipvx_aton (const char * name, struct sh_sockaddr * ss)
273{
274#if defined(USE_IPVX)
275  int             ret;
276  struct addrinfo hints;
277  struct addrinfo *res;
278
279  memset(&hints, 0, sizeof(hints));
280  hints.ai_family = PF_UNSPEC;
281  hints.ai_flags  = AI_NUMERICHOST;
282  ret = getaddrinfo(name, NULL, &hints, &res);
283
284  if (ret)
285    return 0;
286
287  memset(ss, 0, sizeof(struct sh_sockaddr));
288  switch(res->ai_family)
289    {
290    case AF_INET:
291      memcpy(&(ss->sin), res->ai_addr, sizeof(struct sockaddr_in));
292      ss->ss_family = AF_INET;
293      break;
294    case AF_INET6:
295      memcpy(&(ss->sin6), res->ai_addr, sizeof(struct sockaddr_in6));
296      ss->ss_family = AF_INET6;
297      break;
298    default:
299      return 0;
300      break;
301    }
302  freeaddrinfo(res);
303  return 1;
304#else
305  int ret = inet_aton(name, &((ss->sin).sin_addr));
306  ss->ss_family = AF_INET;
307  return ret;
308#endif
309}
310
311#if !defined(USE_IPVX)
312static const char * sh_ipvx_h_name (struct hostent * host_entry)
313{
314  char ** p;
315  if (strchr(host_entry->h_name, '.')) {
316    return host_entry->h_name;
317  } else {
318    for (p = host_entry->h_aliases; *p; ++p) {
319      if (strchr(*p, '.'))
320        return *p;
321    }
322  }
323  return host_entry->h_name;
324}
325#endif
326
327static char * sh_tolower (char * s)
328{
329  char * ret = s;
330  if (s)
331    {
332      for (; *s; ++s)
333        { 
334          *s = tolower((unsigned char) *s);
335        }
336    }
337  return ret;
338}
339
340void * sh_dummy_341_out;
341
342char * sh_ipvx_canonical(const char * hostname, char * numeric, size_t nlen)
343{
344  volatile int    flag = 0;
345  char            *out = NULL;
346#if defined(USE_IPVX)
347  struct addrinfo hints;
348  struct addrinfo *res;
349  struct sockaddr *sa;
350  int             salen;
351  int             err;
352  struct sh_sockaddr  ss;
353  const char * host;
354  char hostbuf[SH_BUFSIZE];
355
356  SL_ENTER(_("sh_ipvx_canonical"));
357 
358  numeric[0] = '\0';
359
360  sh_dummy_341_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      struct addrinfo * res_orig = res;
386
387#if defined(AI_CANONNAME)
388      if (res->ai_canonname && strlen(res->ai_canonname) > 0)
389        {
390          out = sh_util_strdup(res->ai_canonname);
391          sh_tolower (out);
392          if (strchr(out, '.'))
393            flag = 1;
394        }
395#endif
396
397      sa = res->ai_addr;
398      salen = res->ai_addrlen;
399      getnameinfo(sa, salen,
400                  numeric, nlen, NULL, 0, NI_NUMERICHOST);
401
402      if (!flag)
403        out = SH_ALLOC(SH_PATHBUF);
404
405      while (res && !flag) 
406        {
407          sa = res->ai_addr;
408          salen = res->ai_addrlen;
409
410          getnameinfo(sa, salen,
411                      out, SH_PATHBUF, NULL, 0, 0);
412          sh_tolower (out);
413          if (strchr(out, '.'))
414            flag = 1;
415         
416          res = res->ai_next;
417        }
418     
419      freeaddrinfo(res_orig);
420    }
421#else
422  struct hostent     *he;
423  struct sh_sockaddr  ss;
424  volatile int        isNum = 0;
425  struct sockaddr_in *sin;
426
427  SL_ENTER(_("sh_ipvx_canonical"));
428
429  numeric[0] = '\0';
430
431  sh_dummy_341_out = (void *) &out;
432
433  if (sh_ipvx_is_numeric(hostname))
434    {
435      sh_ipvx_aton (hostname, &ss);
436      isNum = 1;
437    }
438 
439
440  SH_MUTEX_LOCK(mutex_resolv);
441
442  if (isNum == 0)
443    {
444      he = sh_gethostbyname(hostname);
445    }
446  else
447    {
448      sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(&ss);
449      he = sh_gethostbyaddr(&(sin->sin_addr), sizeof(sin->sin_addr), AF_INET);
450    }
451
452  if (he != NULL)
453    {
454      out = sh_util_strdup(sh_ipvx_h_name(he));
455      sh_tolower (out);
456      sl_strlcpy (numeric, 
457                  inet_ntoa (*(struct in_addr *) he->h_addr), 
458                  nlen);
459      flag = 1;
460    }
461  SH_MUTEX_UNLOCK(mutex_resolv);
462#endif
463
464  if (flag) {
465    SL_RETURN(out, _("sh_ipvx_canonical"));
466  }
467 
468  if (out)
469    SH_FREE(out);
470  if (numeric[0] == '\0')
471    sl_strlcpy (numeric, _("0.0.0.0"), nlen);
472  SL_RETURN(NULL, _("sh_ipvx_canonical"));
473}
474
475char * sh_ipvx_addrtoname(struct sh_sockaddr * ss)
476{
477#if defined(USE_IPVX)
478  char namebuf[SH_BUFSIZE];
479
480  if (getnameinfo(sh_ipvx_sockaddr_cast(ss), SH_SSP_LEN(ss),
481                  namebuf, sizeof(namebuf), NULL, 0, NI_NAMEREQD) != 0)
482    {
483      return NULL;
484    }
485  return sh_util_strdup(namebuf);
486#else
487  struct sockaddr_in *sin;
488  struct hostent *he;
489
490  sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(ss);
491
492  he = sh_gethostbyaddr(&(sin->sin_addr), sizeof(sin->sin_addr), AF_INET);
493
494  if (he && he->h_name)
495    {
496      return sh_util_strdup(he->h_name);
497    }
498
499  return NULL;
500#endif
501}
502
503int sh_ipvx_reverse_check_ok (char * peer, int port, struct sh_sockaddr * ss)
504{
505#if defined(USE_IPVX)
506  struct addrinfo *res;
507  struct addrinfo hints;
508  char            sport[32];
509  struct addrinfo *p;
510
511  SL_ENTER(_("sh_ipvx_reverse_check_ok"));
512
513  sl_snprintf(sport, sizeof(sport), "%d", port);
514
515  memset(&hints, 0, sizeof(hints));
516  hints.ai_socktype = SOCK_STREAM;
517  hints.ai_flags = AI_ADDRCONFIG;
518
519  if (getaddrinfo(peer, sport, &hints, &res) != 0)
520    {
521      SL_RETURN((0), _("sh_ipvx_reverse_check_ok")); 
522    }
523 
524  p = res;
525  while (p != NULL)
526    {
527      if (ss->ss_family == p->ai_family)
528        {
529          struct sh_sockaddr pp;
530
531          char dst1[SH_IP_BUF];
532          char dst2[SH_IP_BUF];
533
534          sh_ipvx_save(&pp, p->ai_family, p->ai_addr);
535
536          sh_ipvx_ntoa (dst1, sizeof(dst1), &pp);
537          sh_ipvx_ntoa (dst2, sizeof(dst2),  ss);
538
539          if (0 == sl_strcmp(dst1, dst2))
540            {
541              SL_RETURN((1), _("sh_ipvx_reverse_check_ok")); 
542            }
543        }
544      p = p->ai_next;
545    }
546  freeaddrinfo(res);
547#else
548  struct hostent * he;
549  char          ** p;
550  struct sockaddr_in * sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(ss);
551
552  (void) port;
553
554  SL_ENTER(_("sh_ipvx_reverse_check_ok"));
555
556  he = sh_gethostbyname(peer);
557  if (he != NULL)
558    {
559      for (p = he->h_addr_list; *p; ++p)
560        {
561          if (0 == memcmp (*p, &(sin->sin_addr), sizeof(in_addr_t)) ) {
562            SL_RETURN((1), _("sh_ipvx_reverse_check_ok")); }
563        }
564    }
565#endif
566  SL_RETURN((0), _("sh_ipvx_reverse_check_ok"));
567}
568
569#ifdef SH_CUTEST
570#include <stdlib.h>
571#include "CuTest.h"
572
573void Test_ipvx (CuTest *tc) {
574
575  int result;
576
577  result = sh_ipvx_is_ipv4("123456789");
578  CuAssertTrue(tc, result == FALSE);
579
580  result = sh_ipvx_is_ipv4("123456789123...");
581  CuAssertTrue(tc, result == FALSE);
582
583  result = sh_ipvx_is_ipv4("123.456.789.123");
584  CuAssertTrue(tc, result == FALSE);
585
586  result = sh_ipvx_is_ipv4("123.156.189.254");
587  CuAssertTrue(tc, result == TRUE);
588
589  result = sh_ipvx_is_ipv4("255.255.255.255");
590  CuAssertTrue(tc, result == TRUE);
591
592  result = sh_ipvx_is_ipv4("0.0.0.0");
593  CuAssertTrue(tc, result == TRUE);
594
595  result = sh_ipvx_is_ipv4("0022.156.189.254");
596  CuAssertTrue(tc, result == FALSE);
597
598  result = sh_ipvx_is_ipv4("999999999.1.1.2");
599  CuAssertTrue(tc, result == FALSE);
600
601}
602#endif
603
Note: See TracBrowser for help on using the repository browser.