source: trunk/src/sh_ipvx.c@ 319

Last change on this file since 319 was 314, checked in by katerina, 14 years ago

Fix for ticket #235 (peer=0.0.0.0).

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