1 | #define _POSIX_C_SOURCE 199309 |
1 | #if defined(__linux) |
2 | #define _GNU_SOURCE 1 |
|
|
3 | |
|
|
4 | #define IPV6 1 // if you get compilation problems try to disable IPv6 |
2 | # define ENABLE_IPV6 1 // if you get compilation problems try to disable IPv6 |
|
|
3 | #else |
|
|
4 | # define ENABLE_IPV6 0 |
|
|
5 | #endif |
5 | |
6 | |
6 | #include "EXTERN.h" |
7 | #include "EXTERN.h" |
7 | #include "perl.h" |
8 | #include "perl.h" |
8 | #include "XSUB.h" |
9 | #include "XSUB.h" |
9 | |
10 | |
… | |
… | |
29 | #include <arpa/inet.h> |
30 | #include <arpa/inet.h> |
30 | |
31 | |
31 | #ifdef __linux |
32 | #ifdef __linux |
32 | # include <linux/icmp.h> |
33 | # include <linux/icmp.h> |
33 | #endif |
34 | #endif |
34 | #if IPV6 |
35 | #if ENABLE_IPV6 |
35 | # include <netinet/icmp6.h> |
36 | # include <netinet/icmp6.h> |
36 | #endif |
37 | #endif |
37 | |
38 | |
38 | #define ICMP4_ECHO 8 |
39 | #define ICMP4_ECHO 8 |
39 | #define ICMP4_ECHO_REPLY 0 |
40 | #define ICMP4_ECHO_REPLY 0 |
… | |
… | |
44 | #define MIN_INTERVAL .000001 // minimum packet send interval, in seconds |
45 | #define MIN_INTERVAL .000001 // minimum packet send interval, in seconds |
45 | |
46 | |
46 | #define HDR_SIZE_IP4 20 |
47 | #define HDR_SIZE_IP4 20 |
47 | #define HDR_SIZE_IP6 48 |
48 | #define HDR_SIZE_IP6 48 |
48 | |
49 | |
49 | //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 |
50 | |
51 | |
51 | typedef uint8_t addr_t[16]; |
52 | typedef uint8_t addr_t[16]; |
52 | |
53 | |
53 | typedef double tstamp; |
54 | typedef double tstamp; |
54 | |
55 | |
55 | tstamp |
56 | static tstamp |
56 | NOW () |
57 | NOW (void) |
57 | { |
58 | { |
58 | struct timeval tv; |
59 | struct timeval tv; |
59 | gettimeofday (&tv, 0); |
60 | gettimeofday (&tv, 0); |
60 | return tv.tv_sec + tv.tv_usec * 0.000001; |
61 | return tv.tv_sec + tv.tv_usec * 0.000001; |
61 | } |
62 | } |
… | |
… | |
161 | static void * |
162 | static void * |
162 | ping_proc (void *unused) |
163 | ping_proc (void *unused) |
163 | { |
164 | { |
164 | PKT pkt; |
165 | PKT pkt; |
165 | struct sockaddr_in sa4; |
166 | struct sockaddr_in sa4; |
166 | #if IPV6 |
167 | #if ENABLE_IPV6 |
167 | struct sockaddr_in6 sa6; |
168 | struct sockaddr_in6 sa6; |
168 | #endif |
169 | #endif |
169 | |
170 | |
170 | memset (&pkt, 0, sizeof (pkt)); |
171 | memset (&pkt, 0, sizeof (pkt)); |
171 | |
172 | |
172 | memset (&sa4, 0, sizeof (sa4)); |
173 | memset (&sa4, 0, sizeof (sa4)); |
173 | sa4.sin_family = AF_INET; |
174 | sa4.sin_family = AF_INET; |
174 | sa4.sin_port = 0; |
175 | sa4.sin_port = 0; |
175 | #if IPV6 |
176 | #if ENABLE_IPV6 |
176 | memset (&sa6, 0, sizeof (sa6)); |
177 | memset (&sa6, 0, sizeof (sa6)); |
177 | sa6.sin6_family = AF_INET6; |
178 | sa6.sin6_family = AF_INET6; |
178 | sa6.sin6_port = 0; |
179 | sa6.sin6_port = 0; |
179 | #endif |
180 | #endif |
180 | |
181 | |
… | |
… | |
255 | 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) |
256 | errno = 0; |
257 | errno = 0; |
257 | } |
258 | } |
258 | else |
259 | else |
259 | { |
260 | { |
260 | #if IPV6 |
261 | #if ENABLE_IPV6 |
261 | pkt.type = ICMP6_ECHO; |
262 | pkt.type = ICMP6_ECHO; |
262 | |
263 | |
263 | memcpy (&sa6.sin6_addr, |
264 | memcpy (&sa6.sin6_addr, |
264 | sizeof (addr_t) - sizeof (sa6.sin6_addr) + (char *)&range->lo, |
265 | sizeof (addr_t) - sizeof (sa6.sin6_addr) + (char *)&range->lo, |
265 | sizeof (sa6.sin6_addr)); |
266 | sizeof (sa6.sin6_addr)); |
… | |
… | |
358 | |
359 | |
359 | if (pipe (thr_recv) < 0) |
360 | if (pipe (thr_recv) < 0) |
360 | croak ("AnyEvent::FastPing: unable to create receive pipe"); |
361 | croak ("AnyEvent::FastPing: unable to create receive pipe"); |
361 | |
362 | |
362 | icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); |
363 | icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); |
|
|
364 | fcntl (icmp4_fd, F_SETFL, O_NONBLOCK); |
363 | #ifdef ICMP_FILTER |
365 | #ifdef ICMP_FILTER |
364 | { |
366 | { |
365 | struct icmp_filter oval; |
367 | struct icmp_filter oval; |
366 | oval.data = 0xffffffff & ~(1 << ICMP4_ECHO_REPLY); |
368 | oval.data = 0xffffffff & ~(1 << ICMP4_ECHO_REPLY); |
367 | setsockopt (icmp4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval); |
369 | setsockopt (icmp4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval); |
368 | } |
370 | } |
369 | #endif |
371 | #endif |
370 | |
372 | |
371 | #if IPV6 |
373 | #if ENABLE_IPV6 |
372 | icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); |
374 | icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); |
|
|
375 | fcntl (icmp6_fd, F_SETFL, O_NONBLOCK); |
373 | # ifdef ICMP6_FILTER |
376 | # ifdef ICMP6_FILTER |
374 | { |
377 | { |
375 | struct icmp6_filter oval; |
378 | struct icmp6_filter oval; |
376 | ICMP6_FILTER_SETBLOCKALL (&oval); |
379 | ICMP6_FILTER_SETBLOCKALL (&oval); |
377 | ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &oval); |
380 | ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &oval); |
… | |
… | |
464 | memset (&r->hi, 0, sizeof (addr_t)); |
467 | memset (&r->hi, 0, sizeof (addr_t)); |
465 | |
468 | |
466 | if (SvPOKp (lo) && SvPOKp (hi)) |
469 | if (SvPOKp (lo) && SvPOKp (hi)) |
467 | { |
470 | { |
468 | if (SvCUR (lo) != SvCUR (hi)) |
471 | if (SvCUR (lo) != SvCUR (hi)) |
469 | 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)"); |
470 | |
473 | |
471 | if (SvCUR (lo) == 4) |
474 | if (SvCUR (lo) == 4) |
472 | { |
475 | { |
473 | r->family = AF_INET; |
476 | r->family = AF_INET; |
474 | memcpy (sizeof (addr_t) - 4 + (char *)&r->lo, SvPVX (lo), 4); |
477 | memcpy (sizeof (addr_t) - 4 + (char *)&r->lo, SvPVX (lo), 4); |
475 | memcpy (sizeof (addr_t) - 4 + (char *)&r->hi, SvPVX (hi), 4); |
478 | memcpy (sizeof (addr_t) - 4 + (char *)&r->hi, SvPVX (hi), 4); |
476 | } |
479 | } |
477 | else if (SvCUR (lo) == 16) |
480 | else if (SvCUR (lo) == 16) |
478 | { |
481 | { |
479 | #if IPV6 |
482 | #if ENABLE_IPV6 |
480 | r->family = AF_INET6; |
483 | r->family = AF_INET6; |
481 | memcpy (&r->lo, SvPVX (lo), sizeof (addr_t)); |
484 | memcpy (&r->lo, SvPVX (lo), sizeof (addr_t)); |
482 | memcpy (&r->hi, SvPVX (hi), sizeof (addr_t)); |
485 | memcpy (&r->hi, SvPVX (hi), sizeof (addr_t)); |
483 | #else |
486 | #else |
484 | croak ("IPv6 not supported in this configuration"); |
487 | croak ("IPv6 not supported in this configuration"); |
485 | #endif |
488 | #endif |
486 | } |
489 | } |
487 | else |
490 | else |
488 | 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"); |
489 | } |
492 | } |
490 | else if (SvIOK (lo) && SvIOK (hi)) |
493 | else if (SvIOK (lo) && SvIOK (hi)) |
491 | { |
494 | { |
492 | r->family = AF_INET; |
495 | r->family = AF_INET; |
493 | |
496 | |
… | |
… | |
548 | AV *res_av = av_len (cbs) < 0 ? 0 : (AV *)sv_2mortal ((SV *)newAV ()); |
551 | AV *res_av = av_len (cbs) < 0 ? 0 : (AV *)sv_2mortal ((SV *)newAV ()); |
549 | tstamp now = NOW (); |
552 | tstamp now = NOW (); |
550 | |
553 | |
551 | for (;;) |
554 | for (;;) |
552 | { |
555 | { |
553 | int len = recvfrom (icmp4_fd, buf, sizeof (buf), MSG_DONTWAIT | MSG_TRUNC, &sa, &sl); |
556 | int len = recvfrom (icmp4_fd, buf, sizeof (buf), MSG_TRUNC, (struct sockaddr *)&sa, &sl); |
554 | |
557 | |
555 | if (len <= HDR_SIZE_IP4) |
558 | if (len <= HDR_SIZE_IP4) |
556 | break; |
559 | break; |
557 | |
560 | |
558 | IP4HDR *iphdr = (IP4HDR *)buf; |
561 | IP4HDR *iphdr = (IP4HDR *)buf; |
… | |
… | |
597 | PKT pkt; |
600 | PKT pkt; |
598 | tstamp now = NOW (); |
601 | tstamp now = NOW (); |
599 | |
602 | |
600 | for (;;) |
603 | for (;;) |
601 | { |
604 | { |
602 | int len = recvfrom (icmp6_fd, &pkt, sizeof (pkt), MSG_DONTWAIT | MSG_TRUNC, &sa, &sl); |
605 | int len = recvfrom (icmp6_fd, &pkt, sizeof (pkt), MSG_TRUNC, (struct sockaddr *)&sa, &sl); |
603 | |
606 | |
604 | if (len != sizeof (PKT)) |
607 | if (len != sizeof (PKT)) |
605 | break; |
608 | break; |
606 | |
609 | |
607 | if (!res_av |
610 | if (!res_av |