| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
33
|
|
|
33
|
|
501346
|
use v5.40; |
|
|
33
|
|
|
|
|
151
|
|
|
2
|
33
|
|
|
33
|
|
203
|
use feature 'class'; |
|
|
33
|
|
|
|
|
64
|
|
|
|
33
|
|
|
|
|
4355
|
|
|
3
|
33
|
|
|
33
|
|
207
|
no warnings 'experimental::class'; |
|
|
33
|
|
|
|
|
73
|
|
|
|
33
|
|
|
|
|
9802
|
|
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
my @CRC32C_TABLE; |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
sub _init_table { |
|
8
|
33
|
50
|
|
33
|
|
195
|
return if @CRC32C_TABLE; |
|
9
|
33
|
|
|
|
|
198
|
for my $i ( 0 .. 255 ) { |
|
10
|
8448
|
|
|
|
|
9968
|
my $res = $i; |
|
11
|
8448
|
100
|
|
|
|
56971
|
$res = ( $res & 1 ) ? ( $res >> 1 ) ^ 0x82F63B78 : ( $res >> 1 ) for 1 .. 8; |
|
12
|
8448
|
|
|
|
|
13750
|
$CRC32C_TABLE[$i] = $res & 0xFFFFFFFF; |
|
13
|
|
|
|
|
|
|
} |
|
14
|
|
|
|
|
|
|
} |
|
15
|
|
|
|
|
|
|
# |
|
16
|
|
|
|
|
|
|
_init_table(); |
|
17
|
|
|
|
|
|
|
# |
|
18
|
|
|
|
|
|
|
class Net::BitTorrent::DHT::Security v2.0.6 { |
|
19
|
33
|
|
|
33
|
|
15768
|
use Socket qw[inet_aton inet_pton AF_INET AF_INET6]; |
|
|
33
|
|
|
|
|
79416
|
|
|
|
33
|
|
|
|
|
30313
|
|
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
method _crc32c ($data) { |
|
22
|
|
|
|
|
|
|
my $crc = 0xFFFFFFFF; |
|
23
|
|
|
|
|
|
|
$crc = ( $crc >> 8 ) ^ $CRC32C_TABLE[ ( $crc ^ $_ ) & 0xFF ] for unpack 'C*', $data; |
|
24
|
|
|
|
|
|
|
return ( $crc ^ 0xFFFFFFFF ) & 0xFFFFFFFF; |
|
25
|
|
|
|
|
|
|
} |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
method generate_node_id ( $ip, $seed //= undef ) { |
|
28
|
|
|
|
|
|
|
$seed //= int rand 256; |
|
29
|
|
|
|
|
|
|
my $ip_bin; |
|
30
|
|
|
|
|
|
|
my @v4_mask = ( 0x03, 0x0f, 0x3f, 0xff ); |
|
31
|
|
|
|
|
|
|
my @v6_mask = ( 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff ); |
|
32
|
|
|
|
|
|
|
my $ip_masked = ''; |
|
33
|
|
|
|
|
|
|
if ( $ip !~ /:/ ) { |
|
34
|
|
|
|
|
|
|
$ip_bin = inet_aton($ip); |
|
35
|
|
|
|
|
|
|
my @bytes = unpack( 'C*', $ip_bin ); |
|
36
|
|
|
|
|
|
|
$bytes[$_] &= $v4_mask[$_] for 0 .. 3; |
|
37
|
|
|
|
|
|
|
$ip_masked = pack( 'C*', @bytes ); |
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
else { |
|
40
|
|
|
|
|
|
|
$ip_bin = inet_pton( AF_INET6, $ip ); |
|
41
|
|
|
|
|
|
|
my @bytes = unpack( 'C*', $ip_bin ); |
|
42
|
|
|
|
|
|
|
$bytes[$_] &= $v6_mask[$_] for 0 .. 7; |
|
43
|
|
|
|
|
|
|
$ip_masked = pack 'C*', @bytes[ 0 .. 7 ]; |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
my $input = $ip_masked . chr( $seed & 0x07 ); |
|
46
|
|
|
|
|
|
|
my $crc = $self->_crc32c($input); |
|
47
|
|
|
|
|
|
|
my @id; |
|
48
|
|
|
|
|
|
|
$id[0] = ( $crc >> 24 ) & 0xFF; |
|
49
|
|
|
|
|
|
|
$id[1] = ( $crc >> 16 ) & 0xFF; |
|
50
|
|
|
|
|
|
|
$id[2] = ( ( $crc >> 8 ) & 0xF8 ) | ( int( rand(256) ) & 0x07 ); |
|
51
|
|
|
|
|
|
|
$id[$_] = int rand(256) for 3 .. 18; |
|
52
|
|
|
|
|
|
|
$id[19] = $seed & 0xFF; |
|
53
|
|
|
|
|
|
|
pack 'C*', @id; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
method validate_node_id ( $id_bin, $ip ) { |
|
57
|
|
|
|
|
|
|
return 1 if !$ip; # Can't validate without IP |
|
58
|
|
|
|
|
|
|
my $seed = unpack 'C', substr $id_bin, 19, 1; |
|
59
|
|
|
|
|
|
|
my $expected_id = $self->generate_node_id( $ip, $seed ); |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# Compare first 21 bits |
|
62
|
|
|
|
|
|
|
my @id = unpack( 'C*', $id_bin ); |
|
63
|
|
|
|
|
|
|
my @exp = unpack( 'C*', $expected_id ); |
|
64
|
|
|
|
|
|
|
return 0 if $id[0] != $exp[0]; |
|
65
|
|
|
|
|
|
|
return 0 if $id[1] != $exp[1]; |
|
66
|
|
|
|
|
|
|
return 0 if ( $id[2] & 0xF8 ) != ( $exp[2] & 0xF8 ); |
|
67
|
|
|
|
|
|
|
return 1; |
|
68
|
|
|
|
|
|
|
} |
|
69
|
|
|
|
|
|
|
}; |
|
70
|
|
|
|
|
|
|
# |
|
71
|
|
|
|
|
|
|
1; |