source: trunk/src/sh_ipvx.c@ 390

Last change on this file since 390 was 380, checked in by katerina, 13 years ago

Fix for ticket #278 (With --disable-ipv6, port check always checks all interfaces).

File size: 11.6 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_family = AF_INET;
213 (ss->sin).sin_port = htons (port);
214 break;
215 case AF_INET6:
216 (ss->sin6).sin6_family = AF_INET6;
217 (ss->sin6).sin6_port = htons (port);
218 break;
219 }
220 return 0;
221#else
222 (ss->sin).sin_family = AF_INET;
223 (ss->sin).sin_port = htons (port);
224 return 0;
225#endif
226}
227
228int sh_ipvx_get_port(struct sockaddr * sa, int sa_family)
229{
230 int port = 0;
231#if defined(USE_IPVX)
232
233 switch (sa_family)
234 {
235 case AF_INET:
236 port = ntohs(((struct sockaddr_in *)sa)->sin_port);
237 break;
238 case AF_INET6:
239 port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
240 break;
241 }
242#else
243 (void) sa_family;
244 port = ntohs(((struct sockaddr_in *)sa)->sin_port);
245#endif
246 return port;
247}
248
249int sh_ipvx_aton (const char * name, struct sh_sockaddr * ss)
250{
251#if defined(USE_IPVX)
252 int ret;
253 struct addrinfo hints;
254 struct addrinfo *res;
255
256 memset(&hints, '\0', sizeof(hints));
257 hints.ai_family = PF_UNSPEC;
258 hints.ai_flags = AI_NUMERICHOST;
259 ret = getaddrinfo(name, NULL, &hints, &res);
260
261 if (ret)
262 return 0;
263
264 memset(ss, '\0', sizeof(struct sh_sockaddr));
265 switch(res->ai_family)
266 {
267 case AF_INET:
268 memcpy(&(ss->sin), res->ai_addr, sizeof(struct sockaddr_in));
269 ss->ss_family = AF_INET;
270 break;
271 case AF_INET6:
272 memcpy(&(ss->sin6), res->ai_addr, sizeof(struct sockaddr_in6));
273 ss->ss_family = AF_INET6;
274 break;
275 default:
276 return 0;
277 break;
278 }
279 return 1;
280#else
281 int ret = inet_aton(name, &((ss->sin).sin_addr));
282 ss->ss_family = AF_INET;
283 return ret;
284#endif
285}
286
287#if !defined(USE_IPVX)
288static const char * sh_ipvx_h_name (struct hostent * host_entry)
289{
290 char ** p;
291 if (strchr(host_entry->h_name, '.')) {
292 return host_entry->h_name;
293 } else {
294 for (p = host_entry->h_aliases; *p; ++p) {
295 if (strchr(*p, '.'))
296 return *p;
297 }
298 }
299 return host_entry->h_name;
300}
301#endif
302
303static char * sh_tolower (char * s)
304{
305 char * ret = s;
306 if (s)
307 {
308 for (; *s; ++s)
309 {
310 *s = tolower((unsigned char) *s);
311 }
312 }
313 return ret;
314}
315
316static void * sh_dummy_out;
317
318char * sh_ipvx_canonical(const char * hostname, char * numeric, size_t nlen)
319{
320 volatile int flag = 0;
321 char *out = NULL;
322#if defined(USE_IPVX)
323 struct addrinfo hints;
324 struct addrinfo *res;
325 struct sockaddr *sa;
326 int salen;
327 int err;
328 struct sh_sockaddr ss;
329 const char * host;
330 char hostbuf[SH_BUFSIZE];
331
332 numeric[0] = '\0';
333
334 sh_dummy_out = (void *) &out;
335
336 if (sh_ipvx_is_numeric(hostname))
337 {
338 sh_ipvx_aton (hostname, &ss);
339 if (0 == getnameinfo(sh_ipvx_sockaddr_cast(&ss), SH_SS_LEN(ss),
340 hostbuf, sizeof(hostbuf), NULL, 0, NI_NAMEREQD))
341 host = hostbuf;
342 else
343 host = hostname;
344 }
345 else
346 {
347 host = hostname;
348 }
349
350 memset(&hints, 0, sizeof(hints));
351 hints.ai_family = PF_UNSPEC;
352#if defined(AI_CANONNAME)
353 hints.ai_flags = AI_CANONNAME;
354#endif
355
356 err = getaddrinfo(host, NULL, &hints, &res);
357 if (err == 0)
358 {
359#if defined(AI_CANONNAME)
360 if (res->ai_canonname && strlen(res->ai_canonname) > 0)
361 {
362 out = sh_util_strdup(res->ai_canonname);
363 sh_tolower (out);
364 if (strchr(out, '.'))
365 flag = 1;
366 }
367#endif
368
369 sa = res->ai_addr;
370 salen = res->ai_addrlen;
371 getnameinfo(sa, salen,
372 numeric, nlen, NULL, 0, NI_NUMERICHOST);
373
374 if (!flag)
375 out = SH_ALLOC(SH_PATHBUF);
376
377 while (res && !flag)
378 {
379 sa = res->ai_addr;
380 salen = res->ai_addrlen;
381
382 getnameinfo(sa, salen,
383 out, SH_PATHBUF, NULL, 0, 0);
384 sh_tolower (out);
385 if (strchr(out, '.'))
386 flag = 1;
387
388 res = res->ai_next;
389 }
390 }
391#else
392 struct hostent *he;
393 struct sh_sockaddr ss;
394 volatile int isNum = 0;
395 struct sockaddr_in *sin;
396
397 numeric[0] = '\0';
398
399 sh_dummy_out = (void *) &out;
400
401 if (sh_ipvx_is_numeric(hostname))
402 {
403 sh_ipvx_aton (hostname, &ss);
404 isNum = 1;
405 }
406
407
408 SH_MUTEX_LOCK(mutex_resolv);
409
410 if (isNum == 0)
411 {
412 he = sh_gethostbyname(hostname);
413 }
414 else
415 {
416 sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(&ss);
417 he = sh_gethostbyaddr(&(sin->sin_addr), sizeof(sin->sin_addr), AF_INET);
418 }
419
420 if (he != NULL)
421 {
422 out = sh_util_strdup(sh_ipvx_h_name(he));
423 sh_tolower (out);
424 sl_strlcpy (numeric,
425 inet_ntoa (*(struct in_addr *) he->h_addr),
426 nlen);
427 flag = 1;
428 }
429 SH_MUTEX_UNLOCK(mutex_resolv);
430#endif
431
432 if (flag)
433 return out;
434
435 if (out)
436 SH_FREE(out);
437 if (numeric[0] == '\0')
438 sl_strlcpy (numeric, _("0.0.0.0"), nlen);
439 return NULL;
440}
441
442char * sh_ipvx_addrtoname(struct sh_sockaddr * ss)
443{
444#if defined(USE_IPVX)
445 char namebuf[SH_BUFSIZE];
446
447 if (getnameinfo(sh_ipvx_sockaddr_cast(ss), SH_SSP_LEN(ss),
448 namebuf, sizeof(namebuf), NULL, 0, NI_NAMEREQD) != 0)
449 {
450 return NULL;
451 }
452 return sh_util_strdup(namebuf);
453#else
454 struct sockaddr_in *sin;
455 struct hostent *he;
456
457 sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(ss);
458
459 he = sh_gethostbyaddr(&(sin->sin_addr), sizeof(sin->sin_addr), AF_INET);
460
461 if (he && he->h_name)
462 {
463 return sh_util_strdup(he->h_name);
464 }
465
466 return NULL;
467#endif
468}
469
470int sh_ipvx_reverse_check_ok (char * peer, int port, struct sh_sockaddr * ss)
471{
472#if defined(USE_IPVX)
473 struct addrinfo *res;
474 struct addrinfo hints;
475 char sport[32];
476 struct addrinfo *p;
477
478 sl_snprintf(sport, sizeof(sport), "%d", port);
479
480 memset(&hints, '\0', sizeof(hints));
481 hints.ai_socktype = SOCK_STREAM;
482 hints.ai_flags = AI_ADDRCONFIG;
483
484 if (getaddrinfo(peer, sport, &hints, &res) != 0)
485 {
486 return 0;
487 }
488
489 p = res;
490 while (p != NULL)
491 {
492 if (ss->ss_family == p->ai_family)
493 {
494 struct sh_sockaddr pp;
495
496 char dst1[SH_IP_BUF];
497 char dst2[SH_IP_BUF];
498
499 sh_ipvx_save(&pp, p->ai_family, p->ai_addr);
500
501 sh_ipvx_ntoa (dst1, sizeof(dst1), &pp);
502 sh_ipvx_ntoa (dst2, sizeof(dst2), ss);
503
504 if (0 == sl_strcmp(dst1, dst2))
505 {
506 return 1;
507 }
508 }
509 p = p->ai_next;
510 }
511 freeaddrinfo(res);
512#else
513 struct hostent * he;
514 char ** p;
515 struct sockaddr_in * sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(ss);
516
517 (void) port;
518
519 he = sh_gethostbyname(peer);
520 if (he != NULL)
521 {
522 for (p = he->h_addr_list; *p; ++p)
523 {
524 if (0 == memcmp (*p, &(sin->sin_addr), sizeof(in_addr_t)) )
525 return 1;
526 }
527 }
528#endif
529 return 0;
530}
Note: See TracBrowser for help on using the repository browser.