source: trunk/src/sh_ipvx.c @ 448

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

Fic for ticket #350 (numeric hostnames).

File size: 12.9 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 < 3)
85      return (1 == 0); /* ::ffff:ipv4 */
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{
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
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
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)
169    {
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        }
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
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
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;
217      memcpy(&(ss->sin), (struct sockaddr_in*) sa, sizeof(struct sockaddr_in));
218      break;
219#if defined(USE_IPVX)
220    case AF_INET6:
221      ss->ss_family = AF_INET6;
222      memcpy(&(ss->sin6), (struct sockaddr_in6*) sa, sizeof(struct sockaddr_in6));
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:
238      (ss->sin).sin_family = AF_INET;
239      (ss->sin).sin_port = htons (port);
240      break;
241    case AF_INET6:
242      (ss->sin6).sin6_family = AF_INET6;
243      (ss->sin6).sin6_port = htons (port);
244      break;
245    }
246  return 0;
247#else
248  (ss->sin).sin_family = AF_INET;
249  (ss->sin).sin_port = htons (port);
250  return 0;
251#endif
252}
253
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
269  (void) sa_family;
270  port = ntohs(((struct sockaddr_in *)sa)->sin_port);
271#endif
272  return port;
273}
274
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}
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.