1 | #define _POSIX_C_SOURCE 200112 |
1 | #if defined(__linux) |
2 | #define _XOPEN_SOURCE 600 |
2 | # define ENABLE_IPV6 1 // if you get compilation problems try to disable IPv6 |
3 | #define _LARGEFILE64_SOURCE 1 |
|
|
4 | |
|
|
5 | #ifdef __APPLE__ |
|
|
6 | # define IPV6 0 |
|
|
7 | #else |
3 | #else |
8 | # define IPV6 1 // if you get compilation problems try to disable IPv6 |
4 | # define ENABLE_IPV6 0 |
9 | #endif |
5 | #endif |
10 | |
6 | |
11 | #include "EXTERN.h" |
7 | #include "EXTERN.h" |
12 | #include "perl.h" |
8 | #include "perl.h" |
13 | #include "XSUB.h" |
9 | #include "XSUB.h" |
… | |
… | |
34 | #include <arpa/inet.h> |
30 | #include <arpa/inet.h> |
35 | |
31 | |
36 | #ifdef __linux |
32 | #ifdef __linux |
37 | # include <linux/icmp.h> |
33 | # include <linux/icmp.h> |
38 | #endif |
34 | #endif |
39 | #if IPV6 |
35 | #if ENABLE_IPV6 |
40 | # include <netinet/icmp6.h> |
36 | # include <netinet/icmp6.h> |
41 | #endif |
37 | #endif |
42 | |
38 | |
43 | #define ICMP4_ECHO 8 |
39 | #define ICMP4_ECHO 8 |
44 | #define ICMP4_ECHO_REPLY 0 |
40 | #define ICMP4_ECHO_REPLY 0 |
… | |
… | |
49 | #define MIN_INTERVAL .000001 // minimum packet send interval, in seconds |
45 | #define MIN_INTERVAL .000001 // minimum packet send interval, in seconds |
50 | |
46 | |
51 | #define HDR_SIZE_IP4 20 |
47 | #define HDR_SIZE_IP4 20 |
52 | #define HDR_SIZE_IP6 48 |
48 | #define HDR_SIZE_IP6 48 |
53 | |
49 | |
54 | //TODO: xread/xwrite for atomicity? we currently rely on the fact that the pip biffersize divides exactly by pointer sizes |
50 | //TODO: xread/xwrite for atomicity? we currently rely on the fact that the pip buffersize divides exactly by pointer sizes |
55 | |
51 | |
56 | typedef uint8_t addr_t[16]; |
52 | typedef uint8_t addr_t[16]; |
57 | |
53 | |
58 | typedef double tstamp; |
54 | typedef double tstamp; |
59 | |
55 | |
60 | tstamp |
56 | static tstamp |
61 | NOW () |
57 | NOW (void) |
62 | { |
58 | { |
63 | struct timeval tv; |
59 | struct timeval tv; |
64 | gettimeofday (&tv, 0); |
60 | gettimeofday (&tv, 0); |
65 | return tv.tv_sec + tv.tv_usec * 0.000001; |
61 | return tv.tv_sec + tv.tv_usec * 0.000001; |
66 | } |
62 | } |
… | |
… | |
166 | static void * |
162 | static void * |
167 | ping_proc (void *unused) |
163 | ping_proc (void *unused) |
168 | { |
164 | { |
169 | PKT pkt; |
165 | PKT pkt; |
170 | struct sockaddr_in sa4; |
166 | struct sockaddr_in sa4; |
171 | #if IPV6 |
167 | #if ENABLE_IPV6 |
172 | struct sockaddr_in6 sa6; |
168 | struct sockaddr_in6 sa6; |
173 | #endif |
169 | #endif |
174 | |
170 | |
175 | memset (&pkt, 0, sizeof (pkt)); |
171 | memset (&pkt, 0, sizeof (pkt)); |
176 | |
172 | |
177 | memset (&sa4, 0, sizeof (sa4)); |
173 | memset (&sa4, 0, sizeof (sa4)); |
178 | sa4.sin_family = AF_INET; |
174 | sa4.sin_family = AF_INET; |
179 | sa4.sin_port = 0; |
175 | sa4.sin_port = 0; |
180 | #if IPV6 |
176 | #if ENABLE_IPV6 |
181 | memset (&sa6, 0, sizeof (sa6)); |
177 | memset (&sa6, 0, sizeof (sa6)); |
182 | sa6.sin6_family = AF_INET6; |
178 | sa6.sin6_family = AF_INET6; |
183 | sa6.sin6_port = 0; |
179 | sa6.sin6_port = 0; |
184 | #endif |
180 | #endif |
185 | |
181 | |
… | |
… | |
260 | if (sendto (icmp4_fd, &pkt, sizeof (pkt), 0, (struct sockaddr *)&sa4, sizeof (sa4)) > 0) |
256 | if (sendto (icmp4_fd, &pkt, sizeof (pkt), 0, (struct sockaddr *)&sa4, sizeof (sa4)) > 0) |
261 | errno = 0; |
257 | errno = 0; |
262 | } |
258 | } |
263 | else |
259 | else |
264 | { |
260 | { |
265 | #if IPV6 |
261 | #if ENABLE_IPV6 |
266 | pkt.type = ICMP6_ECHO; |
262 | pkt.type = ICMP6_ECHO; |
267 | |
263 | |
268 | memcpy (&sa6.sin6_addr, |
264 | memcpy (&sa6.sin6_addr, |
269 | sizeof (addr_t) - sizeof (sa6.sin6_addr) + (char *)&range->lo, |
265 | sizeof (addr_t) - sizeof (sa6.sin6_addr) + (char *)&range->lo, |
270 | sizeof (sa6.sin6_addr)); |
266 | sizeof (sa6.sin6_addr)); |
… | |
… | |
372 | oval.data = 0xffffffff & ~(1 << ICMP4_ECHO_REPLY); |
368 | oval.data = 0xffffffff & ~(1 << ICMP4_ECHO_REPLY); |
373 | setsockopt (icmp4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval); |
369 | setsockopt (icmp4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval); |
374 | } |
370 | } |
375 | #endif |
371 | #endif |
376 | |
372 | |
377 | #if IPV6 |
373 | #if ENABLE_IPV6 |
378 | icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); |
374 | icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); |
379 | fcntl (icmp6_fd, F_SETFL, O_NONBLOCK); |
375 | fcntl (icmp6_fd, F_SETFL, O_NONBLOCK); |
380 | # ifdef ICMP6_FILTER |
376 | # ifdef ICMP6_FILTER |
381 | { |
377 | { |
382 | struct icmp6_filter oval; |
378 | struct icmp6_filter oval; |
… | |
… | |
471 | memset (&r->hi, 0, sizeof (addr_t)); |
467 | memset (&r->hi, 0, sizeof (addr_t)); |
472 | |
468 | |
473 | if (SvPOKp (lo) && SvPOKp (hi)) |
469 | if (SvPOKp (lo) && SvPOKp (hi)) |
474 | { |
470 | { |
475 | if (SvCUR (lo) != SvCUR (hi)) |
471 | if (SvCUR (lo) != SvCUR (hi)) |
476 | croak ("addresses in range must be of the same size (either 4 or 16 bytes)"); |
472 | croak ("all addresses in range must be of the same size (either 4 or 16 bytes)"); |
477 | |
473 | |
478 | if (SvCUR (lo) == 4) |
474 | if (SvCUR (lo) == 4) |
479 | { |
475 | { |
480 | r->family = AF_INET; |
476 | r->family = AF_INET; |
481 | memcpy (sizeof (addr_t) - 4 + (char *)&r->lo, SvPVX (lo), 4); |
477 | memcpy (sizeof (addr_t) - 4 + (char *)&r->lo, SvPVX (lo), 4); |
482 | memcpy (sizeof (addr_t) - 4 + (char *)&r->hi, SvPVX (hi), 4); |
478 | memcpy (sizeof (addr_t) - 4 + (char *)&r->hi, SvPVX (hi), 4); |
483 | } |
479 | } |
484 | else if (SvCUR (lo) == 16) |
480 | else if (SvCUR (lo) == 16) |
485 | { |
481 | { |
486 | #if IPV6 |
482 | #if ENABLE_IPV6 |
487 | r->family = AF_INET6; |
483 | r->family = AF_INET6; |
488 | memcpy (&r->lo, SvPVX (lo), sizeof (addr_t)); |
484 | memcpy (&r->lo, SvPVX (lo), sizeof (addr_t)); |
489 | memcpy (&r->hi, SvPVX (hi), sizeof (addr_t)); |
485 | memcpy (&r->hi, SvPVX (hi), sizeof (addr_t)); |
490 | #else |
486 | #else |
491 | croak ("IPv6 not supported in this configuration"); |
487 | croak ("IPv6 not supported in this configuration"); |
492 | #endif |
488 | #endif |
493 | } |
489 | } |
494 | else |
490 | else |
495 | croak ("addresses in range must be either 4 (IPv4) or 16 (IPV6) bytes in length"); |
491 | croak ("addresses in range must be either 4 (IPv4) or 16 (IPv6) bytes in length"); |
496 | } |
492 | } |
497 | else if (SvIOK (lo) && SvIOK (hi)) |
493 | else if (SvIOK (lo) && SvIOK (hi)) |
498 | { |
494 | { |
499 | r->family = AF_INET; |
495 | r->family = AF_INET; |
500 | |
496 | |