CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/proto/kademlia/bootstrap_response.rb
Views: 11704
1
# -*- coding: binary -*-
2
3
4
module Rex
5
module Proto
6
module Kademlia
7
# Opcode for a bootstrap response
8
BOOTSTRAP_RESPONSE = 0x09
9
10
# A Kademlia bootstrap response message
11
class BootstrapResponse < Message
12
# @return [String] the ID of the peer that send the bootstrap response
13
attr_reader :peer_id
14
# @return [Integer] the TCP port that the responding peer is listening on
15
attr_reader :tcp_port
16
# @return [Integer] the version of this peer
17
attr_reader :version
18
# @return [Array<Hash<String, Object>>] the peer ID, IP address, UDP/TCP ports and version of each peer
19
attr_reader :peers
20
21
# Constructs a new bootstrap response
22
#
23
# @param peer_id [String] the ID of this peer
24
# @param tcp_port [Integer] the TCP port that this peer is listening on
25
# @param version [Integer] the version of this peer
26
# @param peers [Array<Hash<String, Object>>] the peer ID, IP address, UDP/TCP ports and version of each peer
27
def initialize(peer_id, tcp_port, version, peers)
28
@peer_id = peer_id
29
@tcp_port = tcp_port
30
@version = version
31
@peers = peers
32
end
33
34
# The minimum size of a peer in a KADEMLIA2_BOOTSTRAP_RES message:
35
# peer ID (16-bytes), IP (4 bytes), UDP port (2 bytes), TCP port (2 bytes)
36
# and version (1 byte)
37
BOOTSTRAP_PEER_SIZE = 25
38
39
# Builds a bootstrap response from given data
40
#
41
# @param data [String] the data to decode
42
# @return [BootstrapResponse] the bootstrap response if the data is valid, nil otherwise
43
def self.from_data(data)
44
message = Message.from_data(data)
45
# abort if this isn't a valid response
46
return unless message
47
return unless message.type == BOOTSTRAP_RESPONSE
48
return unless message.body.size >= 23
49
bootstrap_peer_id = Rex::Proto::Kademlia.decode_peer_id(message.body.slice!(0, 16))
50
bootstrap_tcp_port, bootstrap_version, num_peers = message.body.slice!(0, 5).unpack('vCv')
51
# protocol says there are no peers and the body confirms this, so just return with no peers
52
if num_peers == 0 && message.body.to_s.strip.empty?
53
peers = []
54
else
55
peers_data = message.body
56
# peers data is too long/short, abort
57
return if peers_data.size % BOOTSTRAP_PEER_SIZE != 0
58
peers = []
59
until peers_data.to_s.strip.empty?
60
peer_data = peers_data.slice!(0, BOOTSTRAP_PEER_SIZE)
61
peer_id = Rex::Proto::Kademlia.decode_peer_id(peer_data.slice!(0, 16))
62
ip, udp_port, tcp_port, version = peer_data.unpack('VvvC')
63
peers << {
64
id: peer_id,
65
ip: Rex::Socket.addr_itoa(ip),
66
tcp_port: tcp_port,
67
udp_port: udp_port,
68
version: version
69
}
70
end
71
end
72
BootstrapResponse.new(bootstrap_peer_id, bootstrap_tcp_port, bootstrap_version, peers)
73
end
74
end
75
end
76
end
77
end
78
79