Fixes #434. Always use Timeout.timeout() -- on Ruby 1.9 this results in the Timeout::TimeoutError exception vs RuntimeError

git-svn-id: file:///home/svn/framework3/trunk@7323 4d416f70-5f16-0410-b530-b9f4589650da
unstable
HD Moore 2009-11-02 18:14:57 +00:00
parent 80a262f991
commit 075b8c5fa4
11 changed files with 324 additions and 313 deletions

View File

@ -20,7 +20,7 @@ def initialize(info = {})
[
OptInt.new('RUNTIME', [ true, "The number of seconds to run the test", 5 ] )
], Auxiliary::Timed)
end
#
@ -30,10 +30,11 @@ def run
secs = datastore['RUNTIME']
print_status("Running module for #{secs} seconds...")
begin
timeout(secs) { self.run_timed }
Timeout.timeout(secs) { self.run_timed }
rescue Timeout::Error
end
end
end
end
end

View File

@ -11,7 +11,7 @@ require 'msf/core/exploit/tcp'
module Exploit::Remote::FtpServer
include Exploit::Remote::TcpServer
#
# Creates an instance of an FTP exploit module.
#
@ -24,90 +24,90 @@ module Exploit::Remote::FtpServer
OptPort.new('SRVPORT', [ true, "The local port to listen on.", 21 ])
], Msf::Exploit::Remote::FtpServer)
end
def setup
super
@state = {}
end
def on_client_connect(c)
@state[c] = {
:name => "#{c.peerhost}:#{c.peerport}",
:ip => c.peerhost,
:port => c.peerport,
:user => nil,
:name => "#{c.peerhost}:#{c.peerport}",
:ip => c.peerhost,
:port => c.peerport,
:user => nil,
:pass => nil
}
active_data_port_for_client(c, 20)
c.put "220 FTP Server Ready\r\n"
end
def on_client_data(c)
data = c.get_once
return if not data
cmd,arg = data.strip.split(/\s+/, 2)
arg ||= ""
return if not cmd
# Allow per-command overrides
if(self.respond_to?("on_client_command_#{cmd.downcase}"))
return self.send("on_client_command_#{cmd.downcase}", c, arg)
end
case cmd.upcase
when 'USER'
@state[c][:user] = arg
c.put "331 User name okay, need password...\r\n"
return
when 'PASS'
@state[c][:pass] = arg
print_status("#{@state[c][:name]} LOGIN #{@state[c][:user]} / #{@state[c][:pass]}")
c.put "230 Login OK\r\n"
return
return
when 'QUIT'
c.put "221 Logout\r\n"
return
when 'SYST'
c.put "215 UNIX Type: L8\r\n"
return
when 'TYPE'
c.put "200 Type is set\r\n"
return
when 'CWD'
c.put "250 CWD command successful.\r\n"
return
when 'PWD'
c.put "257 \"/\" is current directory.\r\n"
return
when 'SIZE'
c.put "213 1\r\n"
return
when 'MDTM'
c.put "213 #{Time.now.strftime("%Y%m%d%H%M%S")}\r\n"
return
when 'PORT'
port = arg.split(',')[4,2]
if(not port and port.length == 2)
c.put("500 Illegal PORT command.\r\n")
return
end
port = port.map{|x| x.to_i}.pack('C*').unpack('n')[0]
active_data_port_for_client(c, port)
c.put "200 PORT command successful.\r\n"
return
@ -119,28 +119,28 @@ module Exploit::Remote::FtpServer
pasv = (daddr.split('.') + [dport].pack('n').unpack('CC')).join(',')
c.put "227 Entering Passive Mode (#{pasv})\r\n"
return
when /^(STOR|MKD|REM|DEL|RMD)$/
c.put "500 Access Denied\r\n"
return
else
print_status("#{@state[c][:name]} UNKNOWN '#{cmd} #{arg}'")
print_status("#{@state[c][:name]} UNKNOWN '#{cmd} #{arg}'")
c.put("500 '#{cmd} #{arg}': command not understood.\r\n")
return
end
return
end
def on_client_close(c)
@state.delete(c)
end
def passive_data_port_for_client(c)
@state[c][:mode] = :passive
if(not @state[c][:passive_sock])
s = Rex::Socket::TcpServer.create(
'LocalHost' => '0.0.0.0',
@ -153,13 +153,13 @@ module Exploit::Remote::FtpServer
@state[c][:passive_sock] = s
@state[c][:passive_port] = dport
end
@state[c][:passive_port]
end
def active_data_port_for_client(c,port)
@state[c][:mode] = :active
connector = Proc.new {
host = c.peerhost.dup
sock = Rex::Socket::Tcp.create(
@ -171,12 +171,12 @@ module Exploit::Remote::FtpServer
@state[c][:active_connector] = connector
@state[c][:active_port] = port
end
def establish_data_connection(c)
end
def establish_data_connection(c)
begin
Timeout.timeout(20) do
Timeout.timeout(20) do
if(@state[c][:mode] == :active)
return @state[c][:active_connector].call()
end
@ -184,13 +184,14 @@ module Exploit::Remote::FtpServer
return @state[c][:passive_sock].accept
end
end
rescue ::Exception => e
print_error("Failed to establish data connection: #{e.class} #{e}")
end
nil
nil
end
end
end

View File

@ -34,7 +34,7 @@ module Stream
def write(buf, opts = {})
tsent = 0
bidx = 0
begin
while (bidx < buf.length)
sent = fd.syswrite(buf[bidx, 32768])
@ -112,14 +112,14 @@ module Stream
def >>
get_once
end
#
# This method writes to the stream, optionally timing out after a period of
# time.
#
def timed_write(buf, wait = def_write_timeout, opts = {})
if (wait and wait > 0)
timeout(wait) {
Timeout.timeout(wait) {
return write(buf, opts)
}
else
@ -133,7 +133,7 @@ module Stream
#
def timed_read(length = nil, wait = def_read_timeout, opts = {})
if (wait and wait > 0)
timeout(wait) {
Timeout.timeout(wait) {
return read(length, opts)
}
else
@ -167,7 +167,7 @@ module Stream
end
#
#
# This method emulates the behavior of Pex::Socket::Recv in MSF2
#
def get_once(length = -1, timeout = def_read_timeout)
@ -175,14 +175,14 @@ module Stream
if (has_read_data?(timeout) == false)
return nil
end
bsize = (length == -1) ? def_block_size : length
begin
return read(bsize)
rescue Exception
end
return ''
end
@ -213,7 +213,7 @@ module Stream
rescue EOFError
eof = true
end
# If we read zero bytes and we had data, then we've hit EOF
if (temp and temp.length == 0)
eof = true
@ -235,7 +235,7 @@ module Stream
buf += temp
lps += 1
break if (lps >= def_max_loops)
end
@ -296,3 +296,4 @@ protected
end
end end

View File

@ -1,7 +1,7 @@
#!/usr/bin/env ruby
require 'timeout'
require 'thread'
require 'thread'
module Rex
module Post
@ -32,7 +32,7 @@ class PacketResponseWaiter
end
#
# Checks to see if this waiter instance is waiting for the supplied
# Checks to see if this waiter instance is waiting for the supplied
# packet based on its request identifier.
#
def waiting_for?(packet)
@ -57,7 +57,7 @@ class PacketResponseWaiter
#
def wait(interval)
begin
timeout(interval) {
Timeout.timeout(interval) {
while(not self.done)
select(nil, nil, nil, 0.1)
end
@ -74,3 +74,4 @@ class PacketResponseWaiter
end
end; end; end

View File

@ -20,11 +20,11 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
def setup_test(read, write, force_mock = false)
srand(0)
mock_unmake() # always do this, just to be sure. yes, it slows it down. but...
mock_unmake() # always do this, just to be sure. yes, it slows it down. but...
if (force_mock or !$_REX_TEST_NO_MOCK)
mock_make(read,write)
end
end
end
def mock_make(read, write)
@ -40,7 +40,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
mock.mock_handle(:close) { nil }
mock.mock_handle(:read) { read.shift }
mock.mock_handle(:get_once) { read.shift }
mock.mock_handle(:write) { |data|
mock.mock_handle(:write) { |data|
expected = write.shift
if data != expected
write_id = write_size - write.size
@ -49,7 +49,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
end
data.length
}
mock.mock_handle(:put) { |data|
mock.mock_handle(:put) { |data|
expected = write.shift
if data != expected
write_id = write_size - write.size
@ -98,7 +98,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
c = Klass.new(handle, socket)
assert_instance_of(Rex::Proto::DCERPC::Client, c, 'instance')
end
def test_bind_fail
write = ["\x05\x00\x0b\x03\x10\x00\x00\x00\x48\x00\x00\x00\x00\x00\x00\x00\xd0\x16\xd0\x16\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\xbb\xbb\xaa\xaa\x00\x00\x10\x36\x98\x33\x46\xc3\xf8\x7e\x34\x5a\x02\x00\x00\x00\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60\x02\x00\x00\x00"]
read = [ "\x05\x00\x0c\x03\x10\x00\x00\x00\x3c\x00\x00\x00\x00\x00\x00\x00\xd0\x16\xd0\x16\x6c\x66\x00\x00\x04\x00\x31\x33\x35\x00\x92\xc0\x01\x00\x00\x00\x02\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"]
@ -139,10 +139,10 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
"\x05\x00\x03\x23\x10\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01\x1c\x00\x00\x00\x00"
]
setup_test(read, write)
socket = Rex::Socket.create_tcp('PeerHost' => $_REX_TEST_SMB_HOST, 'PeerPort' => 135)
handle = Rex::Proto::DCERPC::Handle.new(['E1AF8308-5D1F-11C9-91A4-08002B14A0FA', '3.0'], 'ncacn_ip_tcp', $_REX_TEST_SMB_HOST, [135])
c = Klass.new(handle, socket)
assert_instance_of(Rex::Proto::DCERPC::Client, c, 'instance')
assert_raise(Rex::Proto::DCERPC::Exceptions::Fault) {
@ -155,10 +155,10 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
def test_segmented_read_writes
bind_expected = "\005\000\v\003\020\000\000\000H\000\000\000\000\000\000\000\320\026\320\026\000\000\000\000\001\000\000\000\000\000\001\000\230\320\377k\022\241\0206\2303F\303\370~4Z\001\000\000\000\004]\210\212\353\034\311\021\237\350\010\000+\020H`\002\000\000\000"
bind_response = "\x05\x00\x0C\x03\x10\x00\x00\x00\x44\x00\x00\x00\x00\x00\x00\x00\xB8\x10\xB8\x10\xB2\x73\x00\x00\x0C\x00\x5C\x50\x49\x50\x45\x5C\x6C\x73\x61\x73\x73\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x5D\x88\x8A\xEB\x1C\xC9\x11\x9F\xE8\x08\x00\x2B\x10\x48\x60\x02\x00\x00\x00"
socket = FlexMock.new
#socket.should_ignore_missing()
@write_data = ''
socket.mock_handle(:write) {
@ -175,7 +175,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
end
data = read_data.slice!(0, size)
if data.length == 0
data = nil
data = nil
end
data
}
@ -186,7 +186,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
end
data = read_data.slice!(0, size)
if data.length == 0
data = nil
data = nil
end
data
}
@ -195,7 +195,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
c = Klass.new(@handle, socket, 'segment_write' => 1, 'segment_read' => 1)
assert_equal(bind_expected, @write_data, 'bind')
assert_instance_of(Rex::Proto::DCERPC::Client, c, 'instance')
# XXX - would be nice to test a success, as well as a failure, but
# hell... we don't care if the decoder is "right" here, just that it
# returns data. Test the decoder in the decoder I say!
@ -213,8 +213,8 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
|size|
data = read_data.slice!(0, size)
if data.length == 0
data = nil
else
data = nil
else
end
data
}
@ -249,7 +249,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
setup_test(read, write)
require 'rex/proto/smb/simpleclient'
begin
timeout($_REX_TEST_TIMEOUT) {
Timeout.timeout($_REX_TEST_TIMEOUT) {
s = Rex::Socket.create_tcp( 'PeerHost' => $_REX_TEST_SMB_HOST, 'PeerPort' => 445)
smb = Rex::Proto::SMB::SimpleClient.new(s, true)
@ -267,7 +267,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
assert_instance_of(Rex::Proto::DCERPC::Handle, handle, 'handle')
dcerpc = Rex::Proto::DCERPC::Client.new(handle, f) # , 'segment_read' => 0)
assert_instance_of(Rex::Proto::DCERPC::Client, dcerpc, 'bind')
s.close
s.close
}
rescue Timeout::Error
flunk('timeout')
@ -285,7 +285,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
]
setup_test(read, write)
begin
timeout($_REX_TEST_TIMEOUT) {
Timeout.timeout($_REX_TEST_TIMEOUT) {
s = Rex::Socket.create_tcp('PeerHost' => $_REX_TEST_SMB_HOST, 'PeerPort' => 135)
handle = Rex::Proto::DCERPC::Handle.new(['E1AF8308-5D1F-11C9-91A4-08002B14A0FA', '3.0'], 'ncacn_ip_tcp', $_REX_TEST_SMB_HOST, [135])
assert_instance_of(Rex::Proto::DCERPC::Handle, handle, 'handle')
@ -294,7 +294,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
stub = "\x00" * (4 * 9) + "\x01\x00\x00\x00"
got = dcerpc.call(0x02, stub)
s.close
s.close
}
rescue Timeout::Error
flunk('timeout')
@ -312,7 +312,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
]
setup_test(read, write)
begin
timeout($_REX_TEST_TIMEOUT) {
Timeout.timeout($_REX_TEST_TIMEOUT) {
s = Rex::Socket.create_tcp('PeerHost' => $_REX_TEST_SMB_HOST, 'PeerPort' => 135)
handle = Rex::Proto::DCERPC::Handle.new(['E1AF8308-5D1F-11C9-91A4-08002B14A0FA', '3.0'], 'ncacn_ip_tcp', $_REX_TEST_SMB_HOST, [135])
assert_instance_of(Rex::Proto::DCERPC::Handle, handle, 'handle')
@ -321,7 +321,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
stub = "\x00" * (4 * 9) + "\x01\x00\x00\x00"
got = dcerpc.call(0x02, stub)
s.close
s.close
}
rescue Timeout::Error
flunk('timeout')
@ -338,7 +338,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
]
setup_test(read, write)
begin
timeout($_REX_TEST_TIMEOUT) {
Timeout.timeout($_REX_TEST_TIMEOUT) {
s = Rex::Socket.create_tcp('PeerHost' => $_REX_TEST_SMB_HOST, 'PeerPort' => 135)
handle = Rex::Proto::DCERPC::Handle.new(['E1AF8308-5D1F-11C9-91A4-08002B14A0FA', '3.0'], 'ncacn_ip_tcp', $_REX_TEST_SMB_HOST, [135])
assert_instance_of(Rex::Proto::DCERPC::Handle, handle, 'handle')
@ -347,7 +347,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
stub = "\x00" * (4 * 9) + "\x01\x00\x00\x00"
got = dcerpc.call(0x02, stub)
s.close
s.close
}
rescue Timeout::Error
flunk('timeout')
@ -363,7 +363,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
write = ["\005\000\v\003\020\000\000\000H\000\000\000\000\000\000\000\320\026\320\026\000\000\000\000\001\000\000\000\000\000\001\000\010\203\257\341\037]\311\021\221\244\010\000+\024\240\372\003\000\000\000\004]\210\212\353\034\311\021\237\350\010\000+\020H`\002\000\000\000"]
setup_test(read, write)
begin
timeout($_REX_TEST_TIMEOUT) {
Timeout.timeout($_REX_TEST_TIMEOUT) {
handle = Rex::Proto::DCERPC::Handle.new(['E1AF8308-5D1F-11C9-91A4-08002B14A0FA', '3.0'], 'ncacn_ip_tcp', $_REX_TEST_SMB_HOST, [135])
assert_instance_of(Rex::Proto::DCERPC::Handle, handle, 'handle')
dcerpc = Rex::Proto::DCERPC::Client.new(handle, nil)
@ -373,7 +373,7 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
flunk('timeout')
end
end
def test_setup_socket_ncacn_np_socket
read = ["\x82\x00\x00\x00",
"\x00\x00\x00\x55\xff\x53\x4d\x42\x72\x00\x00\x00\x00\x98\x01\x28\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2f\xaa\x00\x00\xac\x0a\x11\x03\x00\x03\x0a\x00\x01\x00\x04\x11\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\xfd\xe3\x00\x80\xca\x3d\x91\x3c\x0b\xfd\xc5\x01\xe0\x01\x00\x10\x00\x8b\x3c\x73\xd2\x53\x9e\x28\x48\xa2\xac\x68\xae\xd1\x2e\x41\x5a",
@ -402,8 +402,8 @@ class Rex::Proto::DCERPC::Client::UnitTest < Test::Unit::TestCase
]
setup_test(read, write)
begin
timeout($_REX_TEST_TIMEOUT) {
s = Rex::Socket.create_tcp('PeerHost' => $_REX_TEST_SMB_HOST, 'PeerPort' => 139)
Timeout.timeout($_REX_TEST_TIMEOUT) {
s = Rex::Socket.create_tcp('PeerHost' => $_REX_TEST_SMB_HOST, 'PeerPort' => 139)
handle = Rex::Proto::DCERPC::Handle.new(['4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0'], 'ncacn_np', $_REX_TEST_SMB_HOST, ['\BROWSER'])
assert_instance_of(Rex::Proto::DCERPC::Handle, handle, 'handle')
@ -449,16 +449,16 @@ read = [
]
setup_test(read, write)
timeout($_REX_TEST_TIMEOUT) {
Timeout.timeout($_REX_TEST_TIMEOUT) {
handle = Rex::Proto::DCERPC::Handle.new(['4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0'], 'ncacn_np', $_REX_TEST_SMB_HOST, ['\BROWSER'])
dcerpc = Rex::Proto::DCERPC::Client.new(handle, nil)
assert_instance_of(Rex::Proto::DCERPC::Client, dcerpc, 'bind')
require 'rex/proto/dcerpc/ndr'
stub =
stub =
Rex::Proto::DCERPC::NDR.long(1) +
Rex::Proto::DCERPC::NDR.UnicodeConformantVaryingString('AAAA') +
# Type 33
Rex::Proto::DCERPC::NDR.long(1) +
Rex::Proto::DCERPC::NDR.short(2) +
@ -487,4 +487,5 @@ read = [
end
rescue LoadError
end
end

View File

@ -56,10 +56,10 @@ class Client
'pad_post_params_count' => 8, # integer
'uri_fake_end' => false, # bool
'uri_fake_params_start' => false, # bool
'header_folding' => false, # bool
'header_folding' => false, # bool
'chunked_size' => 0 # integer
}
# This is not used right now...
self.config_types = {
'uri_encode_mode' => ['hex-normal', 'hex-all', 'hex-random', 'u-normal', 'u-random', 'u-all'],
@ -90,7 +90,7 @@ class Client
'chunked_size' => 'integer'
}
end
#
# Set configuration options
#
@ -99,7 +99,7 @@ class Client
self.config[var]=val
end
end
#
# Create an arbitrary HTTP request
#
@ -108,30 +108,30 @@ class Client
c_uri = opts['uri'] || '/'
c_body = opts['data'] || ''
c_meth = opts['method'] || 'GET'
c_prot = opts['proto'] || 'HTTP'
c_prot = opts['proto'] || 'HTTP'
c_vers = opts['version'] || config['version'] || '1.1'
c_qs = opts['query']
c_ag = opts['agent'] || config['agent']
c_cook = opts['cookie'] || config['cookie']
c_host = opts['vhost'] || config['vhost']
c_head = opts['headers'] || config['headers'] || {}
c_rawh = opts['raw_headers']|| config['raw_headers'] || ''
c_conn = opts['connection']
c_rawh = opts['raw_headers']|| config['raw_headers'] || ''
c_conn = opts['connection']
c_auth = opts['basic_auth'] || config['basic_auth'] || ''
uri = set_uri(c_uri)
req = ''
req << set_method(c_meth)
req << set_method_uri_spacer()
req << set_uri_prepend()
req << (c_enc ? set_encode_uri(uri) : uri)
if (c_qs)
req << '?'
req << (c_enc ? set_encode_qs(c_qs) : c_qs)
end
req << set_uri_append()
req << set_uri_version_spacer()
req << set_version(c_prot, c_vers)
@ -141,17 +141,17 @@ class Client
if (c_auth.length > 0)
req << set_basic_auth_header(c_auth)
end
req << set_cookie_header(c_cook)
req << set_connection_header(c_conn)
req << set_extra_headers(c_head)
req << set_raw_headers(c_rawh)
req << set_raw_headers(c_rawh)
req << set_body(c_body)
req
end
#
# Create a CGI compatible request
#
@ -178,16 +178,16 @@ class Client
uri = set_cgi(c_cgi)
qstr = c_qs
pstr = c_body
if (config['pad_get_params'])
1.upto(config['pad_get_params_count'].to_i) do |i|
qstr << '&' if qstr.length > 0
qstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1))
qstr << '='
qstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1))
qstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1))
end
end
c_varg.each_pair do |var,val|
qstr << '&' if qstr.length > 0
qstr << set_encode_uri(var)
@ -200,10 +200,10 @@ class Client
pstr << '&' if qstr.length > 0
pstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1))
pstr << '='
pstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1))
pstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1))
end
end
c_varp.each_pair do |var,val|
pstr << '&' if pstr.length > 0
pstr << set_encode_uri(var)
@ -221,7 +221,7 @@ class Client
req << '?'
req << qstr
end
req << set_path_info(c_path)
req << set_uri_append()
req << set_uri_version_spacer()
@ -232,19 +232,19 @@ class Client
if (c_auth.length > 0)
req << set_basic_auth_header(c_auth)
end
req << set_cookie_header(c_cook)
req << set_connection_header(c_conn)
req << set_connection_header(c_conn)
req << set_extra_headers(c_head)
req << set_content_type_header(c_type)
req << set_content_len_header(pstr.length)
req << set_chunked_header()
req << set_raw_headers(c_rawh)
req << set_body(pstr)
req
end
req
end
#
# Connects to the remote server if possible.
@ -277,7 +277,7 @@ class Client
def close
if (self.conn)
self.conn.shutdown
self.conn.close
self.conn.close
end
self.conn = nil
@ -295,7 +295,7 @@ class Client
# Send a HTTP request to the server
# TODO:
# * Handle junk pipeline requests
def send_request(req)
def send_request(req)
# Connect to the server
connect
@ -307,7 +307,7 @@ class Client
ret
end
#
# Read a response from the server
#
@ -323,7 +323,7 @@ class Client
# do this if t was specified as a negative value indicating an infinite
# wait cycle. If t were specified as nil it would indicate that no
# response parsing is required.
timeout((t < 0) ? nil : t) {
Timeout.timeout((t < 0) ? nil : t) {
# Now, read in the response until we're good to go.
begin
if self.junk_pipeline
@ -379,7 +379,7 @@ class Client
# Close our side if we aren't pipelining
#close if (!pipelining?)
# if the server said stop pipelining, we listen...
# if the server said stop pipelining, we listen...
if resp['Connection'] == 'close'
#close
end
@ -413,38 +413,38 @@ class Client
def pipelining?
pipeline
end
#
# Return the encoded URI
# ['none','hex-normal', 'hex-all', 'u-normal', 'u-all']
def set_encode_uri(uri)
def set_encode_uri(uri)
a = uri
self.config['uri_encode_count'].times {
a = Rex::Text.uri_encode(a, self.config['uri_encode_mode'])
}
return a
end
#
# Return the encoded query string
#
def set_encode_qs(qs)
a = qs
a = qs
self.config['uri_encode_count'].times {
a = Rex::Text.uri_encode(a, self.config['uri_encode_mode'])
}
return a
end
#
# Return the uri
#
def set_uri(uri)
if (self.config['uri_dir_self_reference'])
uri.gsub!('/', '/./')
end
if (self.config['uri_dir_fake_relative'])
buf = ""
uri.split('/').each do |part|
@ -457,7 +457,7 @@ class Client
end
uri = buf
end
if (self.config['uri_full_url'])
url = self.ssl ? "https" : "http"
url << self.config['vhost']
@ -477,7 +477,7 @@ class Client
if (self.config['uri_dir_self_reference'])
uri.gsub!('/', '/./')
end
if (self.config['uri_dir_fake_relative'])
buf = ""
uri.split('/').each do |part|
@ -490,37 +490,37 @@ class Client
end
uri = buf
end
url = uri
if (self.config['uri_full_url'])
url = self.ssl ? "https" : "http"
url << self.config['vhost']
url << (self.port == 80) ? "" : ":#{self.port}"
url << uri
end
url
end
#
# Return the HTTP method string
#
def set_method(method)
ret = method
if (self.config['method_random_valid'])
ret = ['GET', 'POST', 'HEAD'][rand(3)]
end
if (self.config['method_random_invalid'])
ret = Rex::Text.rand_text_alpha(rand(20)+1)
end
if (self.config['method_random_case'])
ret = Rex::Text.to_rand_case(ret)
end
ret
end
@ -529,19 +529,19 @@ class Client
#
def set_version(protocol, version)
ret = protocol + "/" + version
if (self.config['version_random_valid'])
ret = protocol + "/" + ['1.0', '1.1'][rand(2)]
end
if (self.config['version_random_invalid'])
ret = Rex::Text.rand_text_alphanumeric(rand(20)+1)
end
if (self.config['version_random_case'])
ret = Rex::Text.to_rand_case(ret)
end
ret << "\r\n"
end
@ -558,7 +558,7 @@ class Client
end
"\r\n" + chunked + "0\r\n\r\n"
end
#
# Return the HTTP path info
# TODO:
@ -566,7 +566,7 @@ class Client
def set_path_info(path)
path ? path : ''
end
#
# Return the spacing between the method and uri
#
@ -574,18 +574,18 @@ class Client
len = self.config['pad_method_uri_count'].to_i
set = " "
buf = ""
case self.config['pad_method_uri_type']
when 'tab'
set = "\t"
when 'apache'
set = "\t \x0b\x0c\x0d"
end
while(buf.length < len)
buf << set[ rand(set.length) ]
end
return buf
end
@ -596,18 +596,18 @@ class Client
len = self.config['pad_uri_version_count'].to_i
set = " "
buf = ""
case self.config['pad_uri_version_type']
when 'tab'
set = "\t"
when 'apache'
set = "\t \x0b\x0c\x0d"
end
while(buf.length < len)
buf << set[ rand(set.length) ]
end
return buf
end
@ -616,15 +616,15 @@ class Client
#
def set_uri_prepend
prefix = ""
if (self.config['uri_fake_params_start'])
prefix << '/%3fa=b/../'
end
if (self.config['uri_fake_end'])
prefix << '/%20HTTP/1.0/../../'
end
prefix
end
@ -649,7 +649,7 @@ class Client
#
# Return the HTTP agent header
#
def set_agent_header(agent)
def set_agent_header(agent)
agent ? set_formatted_header("User-Agent", agent) : ""
end
@ -664,9 +664,9 @@ class Client
# Return the HTTP connection header
#
def set_connection_header(conn)
conn ? set_formatted_header("Connection", conn) : ""
conn ? set_formatted_header("Connection", conn) : ""
end
#
# Return the content type header
#
@ -697,7 +697,7 @@ class Client
if (self.config['pad_fake_headers'])
1.upto(self.config['pad_fake_headers_count'].to_i) do |i|
buf << set_formatted_header(
Rex::Text.rand_text_alphanumeric(rand(32)+1),
Rex::Text.rand_text_alphanumeric(rand(32)+1),
Rex::Text.rand_text_alphanumeric(rand(32)+1)
)
end
@ -706,7 +706,7 @@ class Client
headers.each_pair do |var,val|
buf << set_formatted_header(var, val)
end
buf
end
@ -721,7 +721,7 @@ class Client
def set_raw_headers(data)
data
end
#
# Return a formatted header string
#
@ -732,7 +732,7 @@ class Client
"#{var}: #{val}\r\n"
end
end
#
@ -767,11 +767,11 @@ class Client
# The proxy list
#
attr_accessor :proxies
# When parsing the request, thunk off the first response from the server, since junk
attr_accessor :junk_pipeline
protected
# https
@ -779,9 +779,10 @@ protected
attr_accessor :hostname, :port # :nodoc:
end
end
end
end

View File

@ -11,7 +11,7 @@ require 'rex/proto/dcerpc'
require 'rex/socket'
class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
Klass = Rex::Proto::SMB::Client
# Alias over the Rex DCERPC protocol modules
@ -19,28 +19,28 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
DCERPCClient = Rex::Proto::DCERPC::Client
DCERPCResponse = Rex::Proto::DCERPC::Response
DCERPCUUID = Rex::Proto::DCERPC::UUID
def test_smb_open_share
share = 'C$'
write_data = ('A' * 256)
filename = 'smb_test.txt'
begin
timeout($_REX_TEST_TIMEOUT) {
Timeout.timeout($_REX_TEST_TIMEOUT) {
s = Rex::Socket.create_tcp(
'PeerHost' => $_REX_TEST_SMB_HOST,
'PeerPort' => 139
)
c = Klass.new(s)
# Request a SMB session over NetBIOS
# puts "[*] Requesting a SMB session over NetBIOS..."
ok = c.session_request()
assert_kind_of(Rex::Struct2::CStruct, ok)
# Check for a positive session response
# A negative response is 0x83
assert_equal(ok.v['Type'], 0x82)
@ -53,22 +53,22 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
ok = c.session_setup_ntlmv2($_REX_TEXT_SMB_USER, $_REX_TEXT_SMB_PASS)
assert_kind_of(Rex::Struct2::CStruct, ok)
assert_not_equal(c.auth_user_id, 0)
# puts "[*] Connecting to the share..."
# puts "[*] Connecting to the share..."
ok = c.tree_connect(share)
assert_kind_of(Rex::Struct2::CStruct, ok)
assert_not_equal(c.last_tree_id, 0)
# puts "[*] Opening a file for write..."
ok = c.open(filename)
assert_kind_of(Rex::Struct2::CStruct, ok)
assert_not_equal(c.last_file_id, 0)
# puts "[*] Writing data to the test file..."
ok = c.write(c.last_file_id, 0, write_data)
assert_kind_of(Rex::Struct2::CStruct, ok)
assert_equal(ok['Payload'].v['CountLow'], write_data.length)
# puts "[*] Closing the test file..."
ok = c.close(c.last_file_id)
assert_kind_of(Rex::Struct2::CStruct, ok)
@ -76,30 +76,30 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
# puts "[*] Opening a file for read..."
ok = c.open(filename, 1)
assert_kind_of(Rex::Struct2::CStruct, ok)
assert_not_equal(c.last_file_id, 0)
assert_not_equal(c.last_file_id, 0)
# puts "[*] Reading data from the test file..."
ok = c.read(c.last_file_id, 0, write_data.length)
assert_kind_of(Rex::Struct2::CStruct, ok)
assert_equal(ok['Payload'].v['DataLenLow'], write_data.length)
read_data = ok.to_s.slice(
ok['Payload'].v['DataOffset'] + 4,
ok['Payload'].v['DataLenLow']
)
)
assert_equal(read_data, write_data)
# puts "[*] Closing the test file..."
ok = c.close(c.last_file_id)
assert_kind_of(Rex::Struct2::CStruct, ok)
# puts "[*] Disconnecting from the tree..."
# puts "[*] Disconnecting from the tree..."
ok = c.tree_disconnect
assert_kind_of(Rex::Struct2::CStruct, ok)
s.close
# Reconnect and delete the file
s = Rex::Socket.create_tcp(
'PeerHost' => $_REX_TEST_SMB_HOST,
@ -107,12 +107,12 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
)
c = Klass.new(s)
# Request a SMB session over NetBIOS
# puts "[*] Requesting a SMB session over NetBIOS..."
ok = c.session_request()
assert_kind_of(Rex::Struct2::CStruct, ok)
# Check for a positive session response
# A negative response is 0x83
assert_equal(ok.v['Type'], 0x82)
@ -125,43 +125,43 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
ok = c.session_setup_ntlmv2($_REX_TEXT_SMB_USER, $_REX_TEXT_SMB_PASS)
assert_kind_of(Rex::Struct2::CStruct, ok)
assert_not_equal(c.auth_user_id, 0)
# puts "[*] Connecting to the share..."
# puts "[*] Connecting to the share..."
ok = c.tree_connect(share)
assert_kind_of(Rex::Struct2::CStruct, ok)
assert_not_equal(c.last_tree_id, 0)
# puts "[*] Deleting the test file..."
ok = c.delete(filename)
assert_kind_of(Rex::Struct2::CStruct, ok)
# puts "[*] Diconnecting from the tree..."
# puts "[*] Diconnecting from the tree..."
ok = c.tree_disconnect
assert_kind_of(Rex::Struct2::CStruct, ok)
s.close
s.close
}
rescue Timeout::Error
flunk('timeout')
end
end
def test_smb_session_request
begin
timeout($_REX_TEST_TIMEOUT) {
Timeout.timeout($_REX_TEST_TIMEOUT) {
s = Rex::Socket.create_tcp(
'PeerHost' => $_REX_TEST_SMB_HOST,
'PeerPort' => 139
)
c = Klass.new(s)
# Request a SMB session over NetBIOS
# puts "[*] Requesting a SMB session over NetBIOS..."
ok = c.session_request()
assert_kind_of(Rex::Struct2::CStruct, ok)
# Check for a positive session response
# A negative response is 0x83
assert_equal(ok.v['Type'], 0x82)
@ -173,13 +173,13 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
# puts "[*] Authenticating with NTLMv2..."
ok = c.session_setup_ntlmv2
assert_kind_of(Rex::Struct2::CStruct, ok)
# puts "[*] Authenticating with NTLMv1..."
# puts "[*] Authenticating with NTLMv1..."
ok = c.session_setup_ntlmv1
assert_kind_of(Rex::Struct2::CStruct, ok)
# puts "[*] Authenticating with clear text passwords..."
begin
begin
ok = c.session_setup_clear
assert_kind_of(Rex::Struct2::CStruct, ok)
rescue Rex::Proto::SMB::Exceptions::ErrorCode
@ -188,28 +188,28 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
end
end
# puts "[*] Connecting to IPC$..."
# puts "[*] Connecting to IPC$..."
ok = c.tree_connect
assert_kind_of(Rex::Struct2::CStruct, ok)
# puts "[*] Opening the \BROWSER pipe..."
# puts "[*] Opening the \BROWSER pipe..."
ok = c.create_pipe('\BROWSER')
assert_kind_of(Rex::Struct2::CStruct, ok)
vers = DCERPCUUID.vers_by_name('SRVSVC')
uuid = DCERPCUUID.uuid_by_name('SRVSVC')
bind, ctx = DCERPCPacket.make_bind_fake_multi(uuid, vers)
# puts "[*] Binding to the Server Service..."
# puts "[*] Binding to the Server Service..."
ok = c.trans_named_pipe(c.last_file_id, bind)
assert_kind_of(Rex::Struct2::CStruct, ok)
data = ok.to_s.slice(
ok['Payload'].v['DataOffset'] + 4,
ok['Payload'].v['DataCount']
)
assert_not_equal(data, nil)
resp = DCERPCResponse.new(data)
assert_equal(resp.type, 12)
}
@ -218,5 +218,6 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
end
end
end
end

View File

@ -8,7 +8,7 @@ require 'rex/proto/dcerpc'
require 'rex/socket'
class Rex::Proto::SMB::SimpleClient::UnitTest < Test::Unit::TestCase
Klass = Rex::Proto::SMB::SimpleClient
# Alias over the Rex DCERPC protocol modules
@ -17,28 +17,28 @@ class Rex::Proto::SMB::SimpleClient::UnitTest < Test::Unit::TestCase
DCERPCResponse = Rex::Proto::DCERPC::Response
DCERPCUUID = Rex::Proto::DCERPC::UUID
XCEPT = Rex::Proto::SMB::Exceptions
FILE_CREATE = 0x10
FILE_TRUNC = 0x02
FILE_OPEN = 0x01
def test_smb_open_share
user = 'SMBTest'
pass = 'SMBTest'
share = 'C$'
write_data = ('A' * (1024 * 8))
filename = 'smb_tester.txt'
begin
timeout($_REX_TEST_TIMEOUT) {
Timeout.timeout($_REX_TEST_TIMEOUT) {
s = Rex::Socket.create_tcp(
'PeerHost' => $_REX_TEST_SMB_HOST,
'PeerPort' => 445
)
c = Klass.new(s, true)
begin
c.login('*SMBSERVER', user, pass)
rescue XCEPT::LoginError
@ -46,19 +46,19 @@ class Rex::Proto::SMB::SimpleClient::UnitTest < Test::Unit::TestCase
end
c.connect(share)
f = c.open(filename, 'rwct')
f << write_data
f.close
f = c.open(filename, 'ro')
d = f.read()
f.close
c.delete(filename)
c.disconnect(share)
s.close
s.close
}
rescue Timeout::Error
flunk('timeout')
@ -67,7 +67,7 @@ class Rex::Proto::SMB::SimpleClient::UnitTest < Test::Unit::TestCase
def test_smb_dcerpc
begin
timeout($_REX_TEST_TIMEOUT) {
Timeout.timeout($_REX_TEST_TIMEOUT) {
s = Rex::Socket.create_tcp(
'PeerHost' => $_REX_TEST_SMB_HOST,
'PeerPort' => 445
@ -86,13 +86,13 @@ class Rex::Proto::SMB::SimpleClient::UnitTest < Test::Unit::TestCase
c.connect('IPC$')
f = c.create_pipe('\BROWSER')
bind, ctx = DCERPCPacket.make_bind_fake_multi(
'4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0',
10,
10,
4
)
# Evasion techniques:
# 1) Write the bind out a few bytes at a time with a random offset
# 2) Read the response back a few bytes at a time with a random offset
@ -101,7 +101,7 @@ class Rex::Proto::SMB::SimpleClient::UnitTest < Test::Unit::TestCase
while (bind.length > 0)
f.write( bind.slice!(0, (rand(20)+5)), rand(1024)+1 )
end
d = ''
# Read the response back a few bytes a time
begin
@ -118,10 +118,11 @@ class Rex::Proto::SMB::SimpleClient::UnitTest < Test::Unit::TestCase
assert_equal(r.ack_result[ctx-0], 0)
assert_equal(r.ack_result[ctx-1], 2)
s.close
s.close
}
rescue Timeout::Error
flunk('timeout')
end
end
end
end

View File

@ -56,8 +56,8 @@ class Rex::Socket::Comm::Local
sock
end
#
# Creates a socket using the supplied Parameter instance.
#
@ -65,7 +65,7 @@ class Rex::Socket::Comm::Local
# Whether to use IPv6 addressing
usev6 = false
# Detect IPv6 addresses and enable IPv6 accordingly
if ( Rex::Socket.support_ipv6?())
@ -77,23 +77,23 @@ class Rex::Socket::Comm::Local
# Force IPv6 mode for non-connected UDP sockets
if (type == ::Socket::SOCK_DGRAM and not param.peerhost)
# FreeBSD allows IPv6 socket creation, but throws an error on sendto()
if (not Rex::Compat.is_freebsd())
usev6 = true
end
end
local = Rex::Socket.resolv_nbo(param.localhost) if param.localhost
peer = Rex::Socket.resolv_nbo(param.peerhost) if param.peerhost
if (local and local.length == 16)
usev6 = true
usev6 = true
end
if (peer and peer.length == 16)
usev6 = true
usev6 = true
end
if (usev6)
if (local and local.length == 4)
if (local == "\x00\x00\x00\x00")
@ -104,7 +104,7 @@ class Rex::Socket::Comm::Local
param.localhost = '::ffff:' + Rex::Socket.getaddress(param.localhost)
end
end
if (peer and peer.length == 4)
if (peer == "\x00\x00\x00\x00")
param.peerhost = '::'
@ -114,28 +114,28 @@ class Rex::Socket::Comm::Local
param.peerhost = '::ffff:' + Rex::Socket.getaddress(param.peerhost)
end
end
param.v6 = true
end
end
else
# No IPv6 support
param.v6 = false
end
# Notify handlers of the before socket create event.
self.instance.notify_before_socket_create(self, param)
# Create the socket
sock = nil
if (param.v6)
sock = ::Socket.new(::Socket::AF_INET6, type, proto)
sock = ::Socket.new(::Socket::AF_INET6, type, proto)
else
sock = ::Socket.new(::Socket::AF_INET, type, proto)
end
# Bind to a given local address and/or port if they are supplied
if (param.localhost || param.localport)
begin
begin
sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, true)
sock.bind(Rex::Socket.to_sockaddr(param.localhost, param.localport))
@ -145,7 +145,7 @@ class Rex::Socket::Comm::Local
raise Rex::AddressInUse.new(param.localhost, param.localport), caller
end
end
# Configure broadcast support for all datagram sockets
if (type == ::Socket::SOCK_DGRAM)
sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_BROADCAST, true)
@ -182,21 +182,21 @@ class Rex::Socket::Comm::Local
end
begin
timeout(param.timeout) do
Timeout.timeout(param.timeout) do
sock.connect(Rex::Socket.to_sockaddr(ip, port))
end
rescue ::Timeout::Error
raise ::Errno::ETIMEDOUT
end
end
rescue ::Errno::EHOSTUNREACH,::Errno::ENETDOWN,::Errno::ENETUNREACH,::Errno::ENETRESET,::Errno::EHOSTDOWN,::Errno::EACCES,::Errno::EINVAL,::Errno::EADDRNOTAVAIL
sock.close
raise Rex::HostUnreachable.new(param.peerhost, param.peerport), caller
rescue Errno::ETIMEDOUT
sock.close
raise Rex::ConnectionTimeout.new(param.peerhost, param.peerport), caller
rescue ::Errno::ECONNRESET,::Errno::ECONNREFUSED,::Errno::ENOTCONN,::Errno::ECONNABORTED
sock.close
raise Rex::ConnectionRefused.new(param.peerhost, param.peerport), caller
@ -224,15 +224,15 @@ class Rex::Socket::Comm::Local
end
}
end
# Now extend the socket with SSL and perform the handshake
if(param.bare? == false and param.ssl)
klass = Rex::Socket::SslTcp
sock.extend(klass)
sock.initsock(param)
sock.initsock(param)
end
end
# Notify handlers that a socket has been created.
@ -240,9 +240,9 @@ class Rex::Socket::Comm::Local
sock
end
def self.proxy(sock, type, host, port)
#$stdout.print("PROXY\n")
case type.downcase
when 'http'
@ -251,7 +251,7 @@ class Rex::Socket::Comm::Local
if (size != setup.length)
raise ArgumentError, "Wrote less data than expected to the http proxy"
end
begin
ret = sock.get_once(39,30)
rescue IOError
@ -299,11 +299,11 @@ class Rex::Socket::Comm::Local
end
if (Rex::Socket.is_ipv4?(host))
addr = Rex::Socket.gethostbyname(host)[3]
addr = Rex::Socket.gethostbyname(host)[3]
setup = [5,1,0,1].pack('C4') + addr + [port.to_i].pack('n')
elsif (Rex::Socket.support_ipv6? and Rex::Socket.is_ipv6?(host))
# IPv6 stuff all untested
addr = Rex::Socket.gethostbyname(host)[3]
addr = Rex::Socket.gethostbyname(host)[3]
setup = [5,1,0,4].pack('C4') + addr + [port.to_i].pack('n')
else
# Then it must be a domain name.
@ -339,7 +339,7 @@ class Rex::Socket::Comm::Local
# Registration
#
##
def self.register_event_handler(handler) # :nodoc:
self.instance.register_event_handler(handler)
end
@ -353,3 +353,4 @@ class Rex::Socket::Comm::Local
end
end

View File

@ -25,7 +25,7 @@ class Event
self.mutex = Mutex.new
self.cond = ConditionVariable.new
end
#
# Sets the event and wakes up anyone who was waiting.
#
@ -33,7 +33,7 @@ class Event
self.param = param
self.mutex.synchronize {
# If this event does not automatically reset its state,
# If this event does not automatically reset its state,
# set the state to true
if (auto_reset == false)
self.state = true
@ -57,23 +57,23 @@ class Event
alias notify set
#
# Waits for the event to become signaled. Timeout is measured in
# Waits for the event to become signaled. Timeout is measured in
# seconds. Raises TimeoutError if the condition does not become signaled.
#
begin
# XXX: we need to replace this code
# continuations slow down YARV
require "continuation" if not defined? callcc
rescue ::LoadError
end
def wait(t = Infinite)
callcc { |ctx|
self.mutex.synchronize {
ctx.call if (self.state == true)
timeout(t) {
Timeout.timeout(t) {
self.cond.wait(self.mutex)
}
}
@ -91,3 +91,4 @@ end
end
end

View File

@ -77,7 +77,7 @@ end
#
class RequestId
MAX_REQUEST_ID = 2**31
def initialize
@lock = Mutex.new
@request_id = rand(MAX_REQUEST_ID)
@ -90,7 +90,7 @@ class RequestId
return @request_id
end
end
def force_next(next_id)
new_request_id = next_id.to_i
if new_request_id < 1 || new_request_id >= MAX_REQUEST_ID
@ -102,7 +102,7 @@ class RequestId
end
end
end
##
# == SNMP Manager
#
@ -118,7 +118,7 @@ end
# manager.close
#
# == Symbolic Object Names
#
#
# Symbolic names for SNMP object IDs can be used as parameters to the
# APIs in this class if the MIB modules are imported and the names of the
# MIBs are included in the MibModules configuration parameter.
@ -131,7 +131,7 @@ end
#
# Additional modules may be imported using the MIB class. The
# current implementation of the importing code requires that the
# external 'smidump' tool is available in your PATH. This tool can be
# external 'smidump' tool is available in your PATH. This tool can be
# obtained from the libsmi website at
# http://www.ibr.cs.tu-bs.de/projects/libsmi/ .
#
@ -169,17 +169,17 @@ class Manager
:MibModules => ["SNMPv2-SMI", "SNMPv2-MIB", "IF-MIB", "IP-MIB", "TCP-MIB", "UDP-MIB"]}
@@request_id = RequestId.new
##
# Retrieves the current configuration of this Manager.
#
attr_reader :config
##
# Retrieves the MIB for this Manager.
#
attr_reader :mib
def initialize(config = {})
if block_given?
warn "SNMP::Manager::new() does not take block; use SNMP::Manager::open() instead"
@ -200,7 +200,7 @@ class Manager
@mib = MIB.new
load_modules(@config[:MibModules], @config[:MibDir])
end
##
# Creates a Manager but also takes an optional block and automatically
# closes the transport connection used by this manager after the block
@ -216,18 +216,18 @@ class Manager
end
end
end
##
# Close the transport connection for this manager.
#
def close
@transport.close
end
def load_module(name)
@mib.load_module(name)
end
##
# Sends a get request for the supplied list of ObjectId or VarBind
# objects.
@ -261,7 +261,7 @@ class Manager
get(object_list).vb_list.first.value
end
end
##
# Sends a get-next request for the supplied list of ObjectId or VarBind
# objects.
@ -273,7 +273,7 @@ class Manager
request = GetNextRequest.new(@@request_id.next, varbind_list)
try_request(request)
end
##
# Sends a get-bulk request. The non_repeaters parameter specifies
# the number of objects in the object_list to be retrieved once. The
@ -289,7 +289,7 @@ class Manager
max_repetitions)
try_request(request)
end
##
# Sends a set request using the supplied list of VarBind objects.
#
@ -312,7 +312,7 @@ class Manager
#
# generic_trap: The generic trap identifier. One of :coldStart,
# :warmStart, :linkDown, :linkUp, :authenticationFailure,
# :egpNeighborLoss, or :enterpriseSpecific
# :egpNeighborLoss, or :enterpriseSpecific
#
# specific_trap: An integer representing the specific trap type for
# an enterprise-specific trap.
@ -320,7 +320,7 @@ class Manager
# timestamp: An integer respresenting the number of hundredths of
# a second that this system has been up.
#
# object_list: A list of additional varbinds to send with the trap.
# object_list: A list of additional varbinds to send with the trap.
#
# For example:
#
@ -343,7 +343,7 @@ class Manager
trap = SNMPv1_Trap.new(ent_oid, agent_ip, generic_trap, specific_int, ticks, vb_list)
send_request(trap, @community, @host, @trap_port)
end
##
# Sends an SNMPv2c style trap.
#
@ -353,16 +353,16 @@ class Manager
# trap_oid: An ObjectId or String with the OID identifier for this
# trap.
#
# object_list: A list of additional varbinds to send with the trap.
# object_list: A list of additional varbinds to send with the trap.
#
def trap_v2(sys_up_time, trap_oid, object_list=[])
vb_list = create_trap_vb_list(sys_up_time, trap_oid, object_list)
trap = SNMPv2_Trap.new(@@request_id.next, vb_list)
send_request(trap, @community, @host, @trap_port)
end
##
# Sends an inform request using the supplied varbind list.
# Sends an inform request using the supplied varbind list.
#
# sys_up_time: An integer respresenting the number of hundredths of
# a second that this system has been up.
@ -370,14 +370,14 @@ class Manager
# trap_oid: An ObjectId or String with the OID identifier for this
# inform request.
#
# object_list: A list of additional varbinds to send with the inform.
# object_list: A list of additional varbinds to send with the inform.
#
def inform(sys_up_time, trap_oid, object_list=[])
vb_list = create_trap_vb_list(sys_up_time, trap_oid, object_list)
request = InformRequest.new(@@request_id.next, vb_list)
try_request(request, @community, @host, @trap_port)
end
##
# Helper method for building VarBindList for trap and inform requests.
#
@ -387,7 +387,7 @@ class Manager
trap_vb = VarBind.new(SNMP::SNMP_TRAP_OID_OID, @mib.oid(trap_oid))
VarBindList.new([uptime_vb, trap_vb, *vb_args])
end
##
# Walks a list of ObjectId or VarBind objects using get_next until
# the response to the first OID in the list reaches the end of its
@ -407,7 +407,7 @@ class Manager
# end
#
# SNMP::Manager.open(:Host => "localhost") do |manager|
# manager.walk(["ifIndex", "ifDescr"]) do |index, descr|
# manager.walk(["ifIndex", "ifDescr"]) do |index, descr|
# puts "#{index.value} #{descr.value}"
# end
# end
@ -420,7 +420,7 @@ class Manager
# Note: If you are getting back rows where all columns have a value of
# NoSuchInstance then your index column is probably missing one of the
# rows. Choose an index column that includes all indexes for the table.
#
#
def walk(object_list, index_column=0)
raise ArgumentError, "expected a block to be given" unless block_given?
vb_list = @mib.varbind_list(object_list, :NullValue)
@ -433,7 +433,7 @@ class Manager
loop do
vb_list = get_next(vb_list).vb_list
index_vb = vb_list[index_column]
break if EndOfMibView == index_vb.value
break if EndOfMibView == index_vb.value
stop_oid = index_vb.name
if stop_oid <= last_oid
warn "OIDs are not increasing, #{last_oid} followed by #{stop_oid}"
@ -449,7 +449,7 @@ class Manager
end
end
end
##
# Helper method for walk. Checks all of the VarBinds in vb_list to
# make sure that the row indices match. If the row index does not
@ -462,7 +462,7 @@ class Manager
row_index = index_vb.name.index(start_vb.name)
vb_list.each_index do |i|
if i != index_column
expected_oid = start_list[i].name + row_index
expected_oid = start_list[i].name + row_index
if vb_list[i].name != expected_oid
vb_list[i] = VarBind.new(expected_oid, NoSuchInstance)
end
@ -471,7 +471,7 @@ class Manager
vb_list
end
private :validate_row
##
# Set the next request-id instead of letting it be generated
# automatically. This method is useful for testing and debugging.
@ -479,7 +479,7 @@ class Manager
def next_request_id=(request_id)
@@request_id.force_next(request_id)
end
private
def warn(message)
@ -487,16 +487,16 @@ class Manager
location = trace[0].sub(/:in.*/,'')
Kernel::warn "#{location}: warning: #{message}"
end
def load_modules(module_list, mib_dir)
module_list.each { |m| @mib.load_module(m, mib_dir) }
end
def try_request(request, community=@community, host=@host, port=@port)
(@retries.to_i + 1).times do |n|
send_request(request, community, host, port)
begin
timeout(@timeout) do
Timeout.timeout(@timeout) do
return get_response(request)
end
rescue Timeout::Error
@ -505,12 +505,12 @@ class Manager
end
raise RequestTimeout, "host #{@config[:Host]} not responding", caller
end
def send_request(request, community, host, port)
message = Message.new(@snmp_version, community, request)
@transport.send(message.encode, host, port)
end
##
# Wait until response arrives. Ignore responses with mismatched IDs;
# these responses are typically from previous requests that timed out
@ -531,7 +531,7 @@ class UDPServerTransport
@socket = UDPSocket.open
@socket.bind(host, port)
end
def close
@socket.close
end
@ -539,7 +539,7 @@ class UDPServerTransport
def send(data, host, port)
@socket.send(data, 0, host, port)
end
def recvfrom(max_bytes)
data, host_info = @socket.recvfrom(max_bytes)
flags, host_port, host_name, host_ip = host_info
@ -571,7 +571,7 @@ class TrapListener
:MaxReceiveBytes => 8000}
NULL_HANDLER = Proc.new {}
##
# Start a trap handler thread. If a block is provided then the block
# is executed before trap handling begins. This block is typically used
@ -598,7 +598,7 @@ class TrapListener
@lock = Mutex.new
@handler_thread = Thread.new(self) { |m| process_traps(m) }
end
##
# Define the default trap handler. The default trap handler block is
# executed only if no other block is applicable. This handler should
@ -608,7 +608,7 @@ class TrapListener
raise ArgumentError, "a block must be provided" unless block
@lock.synchronize { @default_handler = block }
end
##
# Define a trap handler block for a specific trap ObjectId. This handler
# only applies to SNMPv2 traps. Note that symbolic OIDs are not
@ -627,7 +627,7 @@ class TrapListener
raise ArgumentError, "a block must be provided" unless block
@lock.synchronize { @v1_handler = block }
end
##
# Define a trap handler block for all SNMPv2c traps. The trap yielded
# to the block will always be an SNMPv2_Trap. Note that InformRequest
@ -638,7 +638,7 @@ class TrapListener
raise ArgumentError, "a block must be provided" unless block
@lock.synchronize { @v2c_handler = block }
end
##
# Joins the current thread to the trap handler thread.
#
@ -647,7 +647,7 @@ class TrapListener
def join
@handler_thread.join
end
##
# Stops the trap handler thread and releases the socket.
#
@ -657,12 +657,12 @@ class TrapListener
@handler_thread.exit
@transport.close
end
alias kill exit
alias terminate exit
private
def process_traps(trap_listener)
@handler_init.call(trap_listener) if @handler_init
loop do
@ -681,11 +681,11 @@ class TrapListener
puts "Error handling trap: #{e}"
puts e.backtrace.join("\n")
puts "Received data:"
p data
p data
end
end
end
def select_handler(trap)
@lock.synchronize do
if trap.kind_of?(SNMPv2_Trap)
@ -715,3 +715,4 @@ class TrapListener
end
end