11# -*- coding: binary -*-
2+
23require 'rex/proto/kademlia'
34
45module Msf
@@ -10,109 +11,5 @@ module Msf
1011###
1112module Auxiliary ::Kademlia
1213 include Rex ::Proto ::Kademlia
13-
14- # Opcode for a BOOTSTRAP request
15- BOOTSTRAP_REQ = 0x01
16- # Opcode for a BOOTSTRAP response
17- BOOTSTRAP_RES = 0x09
18- # Opcode for a PING request
19- PING = 0x60
20- # Opcode for a PING response
21- PONG = 0x61
22- # The minimum size of a peer in a KADEMLIA2_BOOTSTRAP_RES message:
23- # peer ID (16-bytes), IP (4 bytes), UDP port (2 bytes), TCP port (2 bytes)
24- # and version (1 byte)
25- BOOTSTRAP_PEER_SIZE = 25
26-
27- # Builds a BOOTSTRAP request
28- #
29- # @return [String] a BOOTSTRAP request
30- def bootstrap
31- Message . new ( BOOTSTRAP_REQ )
32- end
33-
34- # Decodes a BOOTSTRAP response
35- #
36- # @param response [String] the response to decode
37- # @return [Array] the discovered peer ID, TCP port, version and a list of peers
38- # if the response if valid, nil otherwise
39- def decode_bootstrap_res ( response )
40- message = Message . from_data ( response )
41- # abort if this isn't a valid response
42- return nil unless message . type = BOOTSTRAP_RES
43- return nil unless message . body . size >= 23
44- peer_id = decode_peer_id ( message . body . slice! ( 0 , 16 ) )
45- tcp_port , version , num_peers = message . body . slice! ( 0 , 5 ) . unpack ( 'vCv' )
46- # protocol says there are no peers and the body confirms this, so just return with no peers
47- return [ tcp_port , version , [ ] ] if num_peers == 0 && message . body . blank?
48- peers = decode_bootstrap_peers ( message . body )
49- # abort if the peer data was invalid
50- return nil unless peers
51- [ peer_id , tcp_port , version , peers ]
52- end
53-
54- # Builds a PING request
55- #
56- # @return [String] a PING request
57- def ping
58- Message . new ( PING )
59- end
60-
61- # Decode a PING response, PONG
62- #
63- # @param response [String] the response to decode
64- # @return [Integer] the source port from the PING response if the response is valid, nil otherwise
65- def decode_pong ( response )
66- message = Message . from_data ( response )
67- # abort if this isn't a pong
68- return nil unless message . type == PONG
69- # abort if the response is too large/small
70- return nil unless message . body && message . body . size == 2
71- # this should always be equivalent to the source port from which the PING was received
72- message . body . unpack ( 'v' ) [ 0 ]
73- end
74-
75- # Decode a list of peers from a BOOTSTRAP response
76- #
77- # @param peers_data [String] the peers data from a BOOTSTRAP response
78- # @return [Array] a list of the peers and their associated metadata extracted
79- # from the response if valid, nil otherwise
80- def decode_bootstrap_peers ( peers_data )
81- # sanity check total size
82- return nil unless peers_data . size % BOOTSTRAP_PEER_SIZE == 0
83- peers = [ ]
84- until peers_data . blank?
85- peers << decode_bootstrap_peer ( peers_data . slice! ( 0 , BOOTSTRAP_PEER_SIZE ) )
86- end
87- peers
88- end
89-
90- # Decodes a single set of peer data from a BOOTSTRAP reseponse
91- #
92- # @param peer-data [String] the peer data for one peer from a BOOSTRAP response
93- # @return [Array] the peer ID, IPv4 addresss, UDP port, TCP port and version of this peer
94- def decode_bootstrap_peer ( peer_data )
95- # sanity check the size of this peer's data
96- return nil unless peer_data . size == BOOTSTRAP_PEER_SIZE
97- # TODO; interpret this properly
98- peer_id = peer_data . slice! ( 0 , 16 )
99- ip , udp_port , tcp_port , version = peer_data . unpack ( 'VvvC' )
100- [ decode_peer_id ( peer_id ) , Rex ::Socket . addr_itoa ( ip ) , udp_port , tcp_port , version ]
101- end
102-
103- # Decodes an on-the-wire representation of a Kademlia peer to its 16-character hex equivalent
104- #
105- # @param bytes [String] the on-the-wire representation of a Kademlia peer
106- # @return [String] the peer ID if valid, nil otherwise
107- def decode_peer_id ( bytes )
108- peer_id = 0
109- return nil unless bytes . size == 16
110- bytes . unpack ( 'VVVV' ) . map { |p | peer_id <<= 32 ; peer_id ^= p ; }
111- peer_id . to_s ( 16 ) . upcase
112- end
113-
114- # TODO
115- # def encode_peer_id(id)
116- # end
11714end
11815end
0 commit comments