line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::Async::Ping::ICMPv6; |
2
|
|
|
|
|
|
|
$Net::Async::Ping::ICMPv6::VERSION = '0.004001'; |
3
|
1
|
|
|
1
|
|
1401
|
use Moo; |
|
1
|
|
|
|
|
6649
|
|
|
1
|
|
|
|
|
7
|
|
4
|
1
|
|
|
1
|
|
1278
|
use warnings NONFATAL => 'all'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
70
|
|
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
539
|
use Future; |
|
1
|
|
|
|
|
7600
|
|
|
1
|
|
|
|
|
46
|
|
7
|
1
|
|
|
1
|
|
9
|
use Time::HiRes; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
6
|
|
8
|
1
|
|
|
1
|
|
114
|
use Carp qw( croak ); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
61
|
|
9
|
1
|
|
|
1
|
|
683
|
use Net::Ping qw(); |
|
1
|
|
|
|
|
14249
|
|
|
1
|
|
|
|
|
44
|
|
10
|
1
|
|
|
1
|
|
13
|
use IO::Socket; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
20
|
|
11
|
1
|
|
|
1
|
|
1222
|
use IO::Async::Socket; |
|
1
|
|
|
|
|
9164
|
|
|
1
|
|
|
|
|
34
|
|
12
|
1
|
|
|
1
|
|
7
|
use Scalar::Util qw( blessed ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
47
|
|
13
|
1
|
|
|
|
|
81
|
use Socket qw( |
14
|
|
|
|
|
|
|
SOCK_RAW SOCK_DGRAM AF_INET6 IPPROTO_ICMPV6 NI_NUMERICHOST NIx_NOSERV |
15
|
|
|
|
|
|
|
inet_pton pack_sockaddr_in6 unpack_sockaddr_in6 getnameinfo inet_ntop |
16
|
1
|
|
|
1
|
|
6
|
); |
|
1
|
|
|
|
|
2
|
|
17
|
1
|
|
|
1
|
|
500
|
use Net::Frame::Layer::IPv6 qw(:consts); |
|
1
|
|
|
|
|
69728
|
|
|
1
|
|
|
|
|
267
|
|
18
|
|
|
|
|
|
|
|
19
|
1
|
|
|
1
|
|
9
|
use constant ICMPv6_UNREACHABLE => 1; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
51
|
|
20
|
1
|
|
|
1
|
|
4
|
use constant ICMPv6_TIME_EXCEEDED => 3; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
45
|
|
21
|
1
|
|
|
1
|
|
6
|
use constant ICMPv6_ECHO => 128; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
36
|
|
22
|
1
|
|
|
1
|
|
5
|
use constant ICMPv6_ECHOREPLY => 129; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
49
|
|
23
|
1
|
|
|
1
|
|
6
|
use constant ICMP_STRUCT => "C2 n3 A"; # Structure of a minimal ICMP |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
44
|
|
24
|
|
|
|
|
|
|
# and ICMPv6 packet |
25
|
1
|
|
|
1
|
|
6
|
use constant SUBCODE => 0; # No ICMP subcode for ECHO and ECHOREPLY |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
44
|
|
26
|
1
|
|
|
1
|
|
5
|
use constant ICMPv6_FLAGS => 0; # No special flags for send or recv |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
67
|
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
extends 'IO::Async::Notifier'; |
29
|
|
|
|
|
|
|
|
30
|
1
|
|
|
1
|
|
7
|
use namespace::clean; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
16
|
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
has default_timeout => ( |
33
|
|
|
|
|
|
|
is => 'ro', |
34
|
|
|
|
|
|
|
default => 5, |
35
|
|
|
|
|
|
|
); |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
has bind => ( is => 'rw' ); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
has _is_raw_socket_setup_done => ( |
40
|
|
|
|
|
|
|
is => 'rw', |
41
|
|
|
|
|
|
|
default => 0, |
42
|
|
|
|
|
|
|
); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
has _raw_socket => ( |
45
|
|
|
|
|
|
|
is => 'lazy', |
46
|
|
|
|
|
|
|
); |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub _build__raw_socket { |
49
|
1
|
|
|
1
|
|
31
|
my $self = shift; |
50
|
|
|
|
|
|
|
|
51
|
1
|
|
|
|
|
28
|
my $fh = IO::Socket->new; |
52
|
1
|
50
|
|
|
|
223
|
$fh->socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) || |
53
|
|
|
|
|
|
|
croak("Unable to create raw socket ($!). Are you running as root?" |
54
|
|
|
|
|
|
|
." If not, and your system supports ping sockets, try setting" |
55
|
|
|
|
|
|
|
." /proc/sys/net/ipv4/ping_group_range"); |
56
|
|
|
|
|
|
|
#TODO: IPv6 sockets support filtering, should we? |
57
|
|
|
|
|
|
|
#$fh->setsockopt($proto_num, 1, NF_ICMPv6_TYPE_ECHO_REQUEST); |
58
|
|
|
|
|
|
|
#print "SOCKOPT: '" . $fh->getsockopt($proto_num, 1) . "'\n"; |
59
|
|
|
|
|
|
|
|
60
|
1
|
50
|
|
|
|
88
|
if ( $self->bind ) { |
61
|
0
|
0
|
|
|
|
0
|
$fh->bind(pack_sockaddr_in6(0, inet_pton(AF_INET6, $self->bind))) |
62
|
|
|
|
|
|
|
or croak "Failed to bind to " . $self->bind; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
my $on_recv = $self->_capture_weakself(sub { |
66
|
0
|
0
|
|
0
|
|
0
|
my $self = shift or return; # weakref, may have disappeared |
67
|
0
|
|
|
|
|
0
|
my ( undef, $recv_msg, $from_saddr ) = @_; |
68
|
|
|
|
|
|
|
|
69
|
0
|
|
|
|
|
0
|
my $from_data = $self->_parse_icmpv6_packet($recv_msg, $from_saddr); |
70
|
|
|
|
|
|
|
return |
71
|
0
|
0
|
0
|
|
|
0
|
unless defined $from_data && ref $from_data eq 'HASH'; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# ignore received packets which are not a response to one of |
74
|
|
|
|
|
|
|
# our echo requests |
75
|
0
|
|
|
|
|
0
|
my $f = $self->_raw_socket_queue->{$from_data->{ip}}; |
76
|
|
|
|
|
|
|
return |
77
|
|
|
|
|
|
|
unless defined $f |
78
|
|
|
|
|
|
|
&& $from_data->{id} == $self->_pid |
79
|
0
|
0
|
0
|
|
|
0
|
&& $from_data->{seq} == $self->seq; |
|
|
|
0
|
|
|
|
|
80
|
|
|
|
|
|
|
|
81
|
0
|
0
|
|
|
|
0
|
if ($from_data->{type} == ICMPv6_ECHOREPLY) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
82
|
0
|
|
|
|
|
0
|
$f->done; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
elsif ($from_data->{type} == ICMPv6_UNREACHABLE) { |
85
|
0
|
|
|
|
|
0
|
$f->fail('ICMP Unreachable'); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
elsif ($from_data->{type} == ICMPv6_TIME_EXCEEDED) { |
88
|
0
|
|
|
|
|
0
|
$f->fail('ICMP Timeout'); |
89
|
|
|
|
|
|
|
} |
90
|
1
|
|
|
|
|
31
|
}); |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
my $socket = IO::Async::Socket->new( |
93
|
|
|
|
|
|
|
handle => $fh, |
94
|
|
|
|
|
|
|
on_send_error => sub { |
95
|
1
|
|
|
1
|
|
847
|
my ( $self, $errno ) = @_; |
96
|
1
|
|
|
|
|
45
|
warn "Send error: $errno\n"; |
97
|
|
|
|
|
|
|
}, |
98
|
|
|
|
|
|
|
on_recv_error => sub { |
99
|
0
|
|
|
0
|
|
0
|
my ( $self, $errno ) = @_; |
100
|
0
|
|
|
|
|
0
|
warn "Receive error: $errno\n"; |
101
|
|
|
|
|
|
|
}, |
102
|
1
|
|
|
|
|
66
|
on_recv => $on_recv, |
103
|
|
|
|
|
|
|
); |
104
|
|
|
|
|
|
|
|
105
|
1
|
|
|
|
|
245
|
return $socket; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
has _raw_socket_queue => ( |
109
|
|
|
|
|
|
|
is => 'rw', |
110
|
|
|
|
|
|
|
default => sub { {} }, |
111
|
|
|
|
|
|
|
); |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
has _pid => ( |
114
|
|
|
|
|
|
|
is => 'lazy', |
115
|
|
|
|
|
|
|
); |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
sub _build__pid |
118
|
1
|
|
|
1
|
|
10
|
{ my $self = shift; |
119
|
1
|
|
|
|
|
24
|
$$ & 0xffff; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
has seq => ( |
123
|
|
|
|
|
|
|
is => 'ro', |
124
|
|
|
|
|
|
|
default => 1, |
125
|
|
|
|
|
|
|
); |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# Whether to try and use ping sockets. This option used in tests |
128
|
|
|
|
|
|
|
# to force normal ping to be used |
129
|
|
|
|
|
|
|
has use_ping_socket => ( |
130
|
|
|
|
|
|
|
is => 'ro', |
131
|
|
|
|
|
|
|
default => 1, |
132
|
|
|
|
|
|
|
); |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub _parse_icmpv6_packet { |
135
|
0
|
|
|
0
|
|
0
|
my ( $self, $recv_msg, $from_saddr ) = @_; |
136
|
|
|
|
|
|
|
# IPv6 raw sockets never return the IPv6 header so they are identical to |
137
|
|
|
|
|
|
|
# what a ping socket returns |
138
|
0
|
|
|
|
|
0
|
my $offset = 0; |
139
|
|
|
|
|
|
|
|
140
|
0
|
|
|
|
|
0
|
my $from_ip = -1; |
141
|
0
|
|
|
|
|
0
|
my $from_pid = -1; |
142
|
0
|
|
|
|
|
0
|
my $from_seq = -1; |
143
|
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
0
|
my ($from_type, $from_subcode) = |
145
|
|
|
|
|
|
|
unpack("C2", substr($recv_msg, $offset, 2)); |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# extract source ip, identifier and sequence depending on |
148
|
|
|
|
|
|
|
# packet type |
149
|
0
|
0
|
|
|
|
0
|
if ($from_type == ICMPv6_ECHOREPLY) { |
|
|
0
|
|
|
|
|
|
150
|
0
|
|
|
|
|
0
|
(my $err, $from_ip) = getnameinfo($from_saddr, |
151
|
|
|
|
|
|
|
NI_NUMERICHOST, NIx_NOSERV); |
152
|
0
|
0
|
|
|
|
0
|
croak "getnameinfo: $err" |
153
|
|
|
|
|
|
|
if $err; |
154
|
0
|
0
|
|
|
|
0
|
($from_pid, $from_seq) = |
155
|
|
|
|
|
|
|
unpack("n2", substr($recv_msg, $offset + 4, 4)) |
156
|
|
|
|
|
|
|
if length $recv_msg >= $offset + 8; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
# an ICMPv6 error message includes the original header |
159
|
|
|
|
|
|
|
# IPv6 + ICMPv6 + ICMPv6::Echo |
160
|
|
|
|
|
|
|
elsif ($from_type == ICMPv6_UNREACHABLE) { |
161
|
0
|
|
|
|
|
0
|
my $ipv6 = Net::Frame::Layer::IPv6->new( |
162
|
|
|
|
|
|
|
# 8 byte is the length of the ICMPv6 destination |
163
|
|
|
|
|
|
|
# unreachable header |
164
|
|
|
|
|
|
|
raw => substr($recv_msg, $offset + 8) |
165
|
|
|
|
|
|
|
)->unpack; |
166
|
|
|
|
|
|
|
# skip if contained packet isn't an ICMPv6 packet |
167
|
|
|
|
|
|
|
return |
168
|
0
|
0
|
|
|
|
0
|
if $ipv6->protocol != NF_IPv6_PROTOCOL_ICMPv6; |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# skip if contained packet isn't an icmp echo request packet |
171
|
0
|
|
|
|
|
0
|
my ($to_type, $to_subcode) = |
172
|
|
|
|
|
|
|
unpack("C2", substr($ipv6->payload, 0, 2)); |
173
|
|
|
|
|
|
|
return |
174
|
0
|
0
|
|
|
|
0
|
if $to_type != ICMPv6_ECHO; |
175
|
|
|
|
|
|
|
|
176
|
0
|
|
|
|
|
0
|
$from_ip = $ipv6->dst; |
177
|
0
|
|
|
|
|
0
|
($from_pid, $from_seq) = |
178
|
|
|
|
|
|
|
unpack("n2", substr($ipv6->payload, 4, 4)); |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
# no packet we care about, raw sockets receive broadcasts, |
181
|
|
|
|
|
|
|
# multicasts etc, ours is only limited to IPv6 containing ICMPv6 |
182
|
|
|
|
|
|
|
else { |
183
|
0
|
|
|
|
|
0
|
return; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
return { |
187
|
0
|
|
|
|
|
0
|
type => $from_type, |
188
|
|
|
|
|
|
|
ip => $from_ip, |
189
|
|
|
|
|
|
|
id => $from_pid, |
190
|
|
|
|
|
|
|
seq => $from_seq, |
191
|
|
|
|
|
|
|
}; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
# Overrides method in IO::Async::Notifier to allow specific options in this class |
195
|
|
|
|
|
|
|
sub configure_unknown |
196
|
1
|
|
|
1
|
1
|
1587
|
{ my $self = shift; |
197
|
1
|
|
|
|
|
5
|
my %params = @_; |
198
|
|
|
|
|
|
|
delete $params{$_} |
199
|
1
|
|
|
|
|
6
|
for qw( default_timeout bind seq use_ping_socket ); |
200
|
|
|
|
|
|
|
return |
201
|
1
|
50
|
|
|
|
6
|
unless keys %params; |
202
|
0
|
|
|
|
|
0
|
my $class = ref $self; |
203
|
0
|
|
|
|
|
0
|
croak "Unrecognised configuration keys for $class - " . |
204
|
|
|
|
|
|
|
join( " ", keys %params ); |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub ping { |
209
|
1
|
|
|
1
|
1
|
153
|
my $self = shift; |
210
|
|
|
|
|
|
|
# Maintain compat with old API |
211
|
1
|
50
|
|
|
|
6
|
my $legacy = blessed $_[0] and $_[0]->isa('IO::Async::Loop'); |
212
|
1
|
50
|
|
|
|
7
|
my $loop = $legacy ? shift : $self->loop; |
213
|
|
|
|
|
|
|
|
214
|
1
|
|
|
|
|
7
|
my ($host, $timeout) = @_; |
215
|
1
|
|
33
|
|
|
8
|
$timeout //= $self->default_timeout; |
216
|
|
|
|
|
|
|
|
217
|
1
|
|
|
|
|
7
|
my $t0 = [Time::HiRes::gettimeofday]; |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
$loop->resolver->getaddrinfo( |
220
|
|
|
|
|
|
|
host => $host, |
221
|
|
|
|
|
|
|
protocol => IPPROTO_ICMPV6, |
222
|
|
|
|
|
|
|
family => AF_INET6, |
223
|
|
|
|
|
|
|
)->then( sub { |
224
|
1
|
|
|
1
|
|
49607
|
my $saddr = $_[0]->{addr}; |
225
|
1
|
|
|
|
|
25
|
my ($err, $dst_ip) = getnameinfo($saddr, NI_NUMERICHOST, NIx_NOSERV); |
226
|
1
|
50
|
|
|
|
21
|
croak "getnameinfo: $err" |
227
|
|
|
|
|
|
|
if $err; |
228
|
1
|
|
|
|
|
10
|
my $f = $loop->new_future; |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# Let's try a ping socket (unprivileged ping) first. See |
231
|
|
|
|
|
|
|
# https://github.com/torvalds/linux/commit/6d0bfe22611602f36617bc7aa2ffa1bbb2f54c67 |
232
|
1
|
|
|
|
|
26
|
my ($socket, $ping_socket, $ident); |
233
|
1
|
50
|
|
|
|
94
|
if ( $self->use_ping_socket) { |
234
|
0
|
|
|
|
|
0
|
my $ping_fh = IO::Socket->new; |
235
|
0
|
0
|
|
|
|
0
|
if ($ping_fh->socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6)) { |
236
|
0
|
|
|
|
|
0
|
($ident) = unpack_sockaddr_in6 getsockname($ping_fh); |
237
|
|
|
|
|
|
|
|
238
|
0
|
0
|
|
|
|
0
|
if ($self->bind) { |
239
|
0
|
0
|
|
|
|
0
|
$ping_fh->bind(pack_sockaddr_in6(0, |
240
|
|
|
|
|
|
|
inet_pton(AF_INET6, $self->bind))) |
241
|
|
|
|
|
|
|
or croak "Failed to bind to ".$self->bind; |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
my $on_recv = $self->_capture_weakself( |
245
|
|
|
|
|
|
|
sub { |
246
|
0
|
0
|
|
|
|
0
|
my $self = shift or return; # weakref, may have disappeared |
247
|
0
|
|
|
|
|
0
|
my ( undef, $recv_msg, $from_saddr ) = @_; |
248
|
|
|
|
|
|
|
|
249
|
0
|
|
|
|
|
0
|
my $from_data = $self->_parse_icmpv6_packet($recv_msg, |
250
|
|
|
|
|
|
|
$from_saddr); |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# ignore received packets which are not a response to one of |
253
|
|
|
|
|
|
|
# our echo requests |
254
|
|
|
|
|
|
|
return |
255
|
|
|
|
|
|
|
unless $from_data->{ip} eq $dst_ip |
256
|
0
|
0
|
0
|
|
|
0
|
&& $from_data->{seq} == $self->seq; |
257
|
|
|
|
|
|
|
|
258
|
0
|
0
|
|
|
|
0
|
if ($from_data->{type} == ICMPv6_ECHOREPLY) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
259
|
0
|
|
|
|
|
0
|
$f->done; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
elsif ($from_data->{type} == ICMPv6_UNREACHABLE) { |
262
|
0
|
|
|
|
|
0
|
$f->fail('ICMP Unreachable'); |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
elsif ($from_data->{type} == ICMPv6_TIME_EXCEEDED) { |
265
|
0
|
|
|
|
|
0
|
$f->fail('ICMP Timeout'); |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
}, |
268
|
0
|
|
|
|
|
0
|
); |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
$socket = IO::Async::Socket->new( |
271
|
|
|
|
|
|
|
handle => $ping_fh, |
272
|
|
|
|
|
|
|
on_send_error => sub { |
273
|
0
|
|
|
|
|
0
|
my ( $self, $errno ) = @_; |
274
|
0
|
|
|
|
|
0
|
$f->fail("Send error: $errno"); |
275
|
|
|
|
|
|
|
}, |
276
|
|
|
|
|
|
|
on_recv_error => sub { |
277
|
0
|
|
|
|
|
0
|
my ( $self, $errno ) = @_; |
278
|
0
|
|
|
|
|
0
|
$f->fail("Receive error: $errno"); |
279
|
|
|
|
|
|
|
}, |
280
|
0
|
|
|
|
|
0
|
on_recv => $on_recv, |
281
|
|
|
|
|
|
|
); |
282
|
0
|
0
|
|
|
|
0
|
$legacy ? $loop->add($socket) : $self->add_child($socket); |
283
|
0
|
|
|
|
|
0
|
$ping_socket = 1; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
# fallback to raw socket or if no ping socket was requested |
288
|
1
|
50
|
|
|
|
10
|
if (not defined $socket) { |
289
|
1
|
|
|
|
|
42
|
$socket = $self->_raw_socket; |
290
|
1
|
|
|
|
|
23
|
$ident = $self->_pid; |
291
|
1
|
50
|
|
|
|
19
|
if (!$self->_is_raw_socket_setup_done) { |
292
|
1
|
50
|
|
|
|
26
|
$legacy ? $loop->add($socket) : $self->add_child($socket); |
293
|
1
|
|
|
|
|
287
|
$self->_is_raw_socket_setup_done(1); |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
# remember raw socket requests |
298
|
1
|
50
|
|
|
|
6
|
if (!$ping_socket) { |
299
|
1
|
50
|
|
|
|
12
|
if (exists $self->_raw_socket_queue->{$dst_ip}) { |
300
|
0
|
|
|
|
|
0
|
warn "$dst_ip already in raw queue, $host probably duplicate\n"; |
301
|
|
|
|
|
|
|
} |
302
|
1
|
|
|
|
|
14
|
$self->_raw_socket_queue->{$dst_ip} = $f; |
303
|
|
|
|
|
|
|
} |
304
|
1
|
|
|
|
|
5
|
$socket->send( $self->_msg($ident), ICMPv6_FLAGS, $saddr ); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Future->wait_any( |
307
|
|
|
|
|
|
|
$f, |
308
|
|
|
|
|
|
|
$loop->timeout_future(after => $timeout) |
309
|
|
|
|
|
|
|
) |
310
|
|
|
|
|
|
|
->then( sub { |
311
|
0
|
|
|
|
|
0
|
Future->done(Time::HiRes::tv_interval($t0)); |
312
|
|
|
|
|
|
|
}) |
313
|
|
|
|
|
|
|
->followed_by( sub { |
314
|
1
|
|
|
|
|
1001218
|
my $f = shift; |
315
|
|
|
|
|
|
|
|
316
|
1
|
50
|
|
|
|
6
|
if ($ping_socket) { |
317
|
0
|
|
|
|
|
0
|
$socket->remove_from_parent; |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
else { |
320
|
|
|
|
|
|
|
# remove from raw socket queue |
321
|
1
|
|
|
|
|
14
|
delete $self->_raw_socket_queue->{$dst_ip}; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
1
|
|
|
|
|
7
|
return $f; |
325
|
|
|
|
|
|
|
}) |
326
|
1
|
|
|
|
|
11
|
}); |
|
1
|
|
|
|
|
184
|
|
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub _msg { |
330
|
1
|
|
|
1
|
|
3
|
my ($self, $ident) = @_; |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# data_size to be implemented later |
333
|
1
|
|
|
|
|
2
|
my $data_size = 0; |
334
|
1
|
|
|
|
|
7
|
my $data = ''; |
335
|
1
|
|
|
|
|
2
|
my $checksum = 0; |
336
|
1
|
|
|
|
|
10
|
my $msg = pack(ICMP_STRUCT . $data_size, ICMPv6_ECHO, SUBCODE, |
337
|
|
|
|
|
|
|
$checksum, $ident, $self->seq, $data); |
338
|
1
|
|
|
|
|
34
|
$checksum = Net::Ping->checksum($msg); |
339
|
1
|
|
|
|
|
51
|
$msg = pack(ICMP_STRUCT . $data_size, ICMPv6_ECHO, SUBCODE, |
340
|
|
|
|
|
|
|
$checksum, $ident, $self->seq, $data); |
341
|
1
|
|
|
|
|
5
|
return $msg; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
1; |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
__END__ |