source: trunk/src/sh_ipvx.c@ 300

Last change on this file since 300 was 295, checked in by katerina, 14 years ago

Support for IPv6 (ticket #222).

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