source: trunk/src/sh_ipvx.c@ 328

Last change on this file since 328 was 321, checked in by katerina, 14 years ago

Fix for ticket #240: The samhain_kmem kernel module should be loaded earlier

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