1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
module Oxidized
require 'net/telnet'
require 'oxidized/input/cli'
class Telnet < Input
RescueFail = {}
include Input::CLI
attr_reader :telnet
def connect node
@node = node
@timeout = Oxidized.config.timeout
@node.model.cfg['telnet'].each { |cb| instance_exec(&cb) }
@log = File.open(Oxidized::Config::Log + "/#{@node.ip}-telnet", 'w') if Oxidized.config.input.debug?
port = vars(:telnet_port) || 23
telnet_opts = { 'Host' => @node.ip,
'Port' => port.to_i,
'Timeout' => @timeout,
'Model' => @node.model,
'Log' => @log }
@telnet = Net::Telnet.new telnet_opts
begin
login
rescue Timeout::Error
raise PromptUndetect, ['unable to detect prompt:', @node.prompt].join(' ')
end
connected?
end
def connected?
@telnet and not @telnet.sock.closed?
end
def cmd cmd_str, expect = @node.prompt
return send(cmd_str + "\n") unless expect
Oxidized.logger.debug "Telnet: #{cmd_str} @#{@node.name}"
args = { 'String' => cmd_str,
'Match' => expect,
'Timeout' => @timeout }
@telnet.cmd args
end
def send data
@telnet.write data
end
def output
@telnet.output
end
private
def expect re
@telnet.oxidized_expect expect: re, timeout: @timeout
end
def disconnect
begin
disconnect_cli
@telnet.close
rescue Errno::ECONNRESET
ensure
@log.close if Oxidized.config.input.debug?
(@telnet.close rescue true) unless @telnet.sock.closed?
end
end
end
end
class Net::Telnet
## how to do this, without redefining the whole damn thing
## FIXME: we also need output (not sure I'm going to support this)
attr_reader :output
def oxidized_expect(options) # :yield: recvdata
model = @options["Model"]
@log = @options["Log"]
expects = [options[:expect]].flatten
time_out = options[:timeout] || @options["Timeout"] || Oxidized.config.timeout?
Timeout::timeout(time_out) do
line = ""
rest = ""
buf = ""
loop do
c = @sock.readpartial(1024 * 1024)
@output = c
c = rest + c
if Integer(c.rindex(/#{IAC}#{SE}/no) || 0) <
Integer(c.rindex(/#{IAC}#{SB}/no) || 0)
buf = preprocess(c[0...c.rindex(/#{IAC}#{SB}/no)])
rest = c[c.rindex(/#{IAC}#{SB}/no)..-1]
elsif pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) ||
c.rindex(/\r\z/no)
buf = preprocess(c[0...pt])
rest = c[pt..-1]
else
buf = preprocess(c)
rest = ''
end
if Oxidized.config.input.debug?
@log.print buf
@log.flush
end
line += buf
line = model.expects line
match = expects.find { |re| line.match re }
return match if match
end
end
end
end
|