@@ -43,16 +43,41 @@ def run_batch_size
43
43
datastore [ 'BATCHSIZE' ] . to_i
44
44
end
45
45
46
+ def udp_sock ( ip , port )
47
+ @udp_socks_mutex . synchronize do
48
+ key = "#{ ip } :#{ port } "
49
+ unless @udp_socks . key? ( key )
50
+ @udp_socks [ key ] =
51
+ Rex ::Socket ::Udp . create ( {
52
+ 'LocalHost' => datastore [ 'CHOST' ] || nil ,
53
+ 'LocalPort' => datastore [ 'CPORT' ] || 0 ,
54
+ 'PeerHost' => ip ,
55
+ 'PeerPort' => port ,
56
+ 'Context' => { 'Msf' => framework , 'MsfExploit' => self }
57
+ } )
58
+ add_socket ( @udp_socks [ key ] )
59
+ end
60
+ return @udp_socks [ key ]
61
+ end
62
+ end
63
+
64
+ def cleanup_udp_socks
65
+ @udp_socks_mutex . synchronize do
66
+ @udp_socks . each do |key , sock |
67
+ @udp_socks . delete ( key )
68
+ remove_socket ( sock )
69
+ sock . close
70
+ end
71
+ end
72
+ end
73
+
46
74
# Start scanning a batch of IP addresses
47
75
def run_batch ( batch )
48
- @udp_sock = Rex ::Socket ::Udp . create ( {
49
- 'LocalHost' => datastore [ 'CHOST' ] || nil ,
50
- 'LocalPort' => datastore [ 'CPORT' ] || 0 ,
51
- 'Context' => { 'Msf' => framework , 'MsfExploit' => self }
52
- } )
53
- add_socket ( @udp_sock )
76
+ @udp_socks = { }
77
+ @udp_socks_mutex = Mutex . new
54
78
55
79
@udp_send_count = 0
80
+ @interval_mutex = Mutex . new
56
81
57
82
# Provide a hook for pre-scanning setup
58
83
scanner_prescan ( batch )
@@ -95,9 +120,10 @@ def scanner_spoof_send(data, ip, port, srcip, num_packets=1)
95
120
def scanner_send ( data , ip , port )
96
121
97
122
resend_count = 0
123
+ sock = nil
98
124
begin
99
-
100
- @udp_sock . sendto ( data , ip , port , 0 )
125
+ sock = udp_sock ( ip , port )
126
+ sock . send ( data , 0 )
101
127
102
128
rescue ::Errno ::ENOBUFS
103
129
resend_count += 1
@@ -112,15 +138,16 @@ def scanner_send(data, ip, port)
112
138
113
139
retry
114
140
115
- rescue ::Rex ::ConnectionError
141
+ rescue ::Rex ::ConnectionError , :: Errno :: ECONNREFUSED
116
142
# This fires for host unreachable, net unreachable, and broadcast sends
117
143
# We can safely ignore all of these for UDP sends
118
144
end
119
145
120
- @udp_send_count += 1
121
-
122
- if @udp_send_count % datastore [ 'ScannerRecvInterval' ] == 0
123
- scanner_recv ( 0.1 )
146
+ @interval_mutex . synchronize do
147
+ @udp_send_count += 1
148
+ if @udp_send_count % datastore [ 'ScannerRecvInterval' ] == 0
149
+ scanner_recv ( 0.1 )
150
+ end
124
151
end
125
152
126
153
true
@@ -129,29 +156,38 @@ def scanner_send(data, ip, port)
129
156
# Process incoming packets and dispatch to the module
130
157
# Ensure a response flood doesn't trap us in a loop
131
158
# Ignore packets outside of our project's scope
132
- def scanner_recv ( timeout = 0.1 )
159
+ def scanner_recv ( timeout = 0.1 )
133
160
queue = [ ]
134
- while ( res = @udp_sock . recvfrom ( 65535 , timeout ) )
161
+ start = Time . now
162
+ while Time . now - start < timeout do
163
+ readable , _ , _ = ::IO . select ( @udp_socks . values , nil , nil , timeout )
164
+ if readable
165
+ for sock in readable
166
+ res = sock . recvfrom ( 65535 , timeout )
135
167
136
- # Ignore invalid responses
137
- break if not res [ 1 ]
168
+ # Ignore invalid responses
169
+ break if not res [ 1 ]
138
170
139
- # Ignore empty responses
140
- next if not ( res [ 0 ] and res [ 0 ] . length > 0 )
171
+ # Ignore empty responses
172
+ next if not ( res [ 0 ] and res [ 0 ] . length > 0 )
141
173
142
- # Trim the IPv6-compat prefix off if needed
143
- shost = res [ 1 ] . sub ( /^::ffff:/ , '' )
174
+ # Trim the IPv6-compat prefix off if needed
175
+ shost = res [ 1 ] . sub ( /^::ffff:/ , '' )
144
176
145
- # Ignore the response if we have a boundary
146
- next unless inside_workspace_boundary? ( shost )
177
+ # Ignore the response if we have a boundary
178
+ next unless inside_workspace_boundary? ( shost )
147
179
148
- queue << [ res [ 0 ] , shost , res [ 2 ] ]
180
+ queue << [ res [ 0 ] , shost , res [ 2 ] ]
149
181
150
- if queue . length > datastore [ 'ScannerRecvQueueLimit' ]
151
- break
182
+ if queue . length > datastore [ 'ScannerRecvQueueLimit' ]
183
+ break
184
+ end
185
+ end
152
186
end
153
187
end
154
188
189
+ cleanup_udp_socks
190
+
155
191
queue . each do |q |
156
192
scanner_process ( *q )
157
193
end
0 commit comments