123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- require 'zlib'
- require_relative 'telnet/codes'
- require_relative 'rfc1143'
- require_relative 'monolog'
- # This Telnet class implements a subset of the Telnet protocol.
- #
- class Telnet
- include Monolog
- include Telnet::Codes
- # Allowed telnet state codes
- STATES = [:data, :iac, :will, :wont, :do, :dont, :sb, :sb_data, :sb_data_iac]
-
- # Helper structs
- Telopt = Struct.new(:telopt, :us, :him)
-
-
- def initialize(client)
- @client = client
- @telopts = {} # Telopt support.
- @rfc1143 = {} # RFC1143 support.
- @buffer = "" # Subrequest buffer
- @state = :data # state of telnet protocol parser.
- @sb_telopt = nil; # current subnegotiation
- @compress = false # compression state
- end
-
- # Wait for input from the server
- def wait_for_input
- return Fiber.yield
- end
-
- # Called when client data should be filtered before being passed to the server
- def client_to_server(data)
- result = ""
- data.each_byte do | b |
- iac = TELNET_IAC.chr
-
- case @buffer
- when /\A#{iac}#{iac}\Z/
-
- # ongoing negotiation
- when /\A#{iac}\Z/
- return nil
- else
-
-
- end
- end
- end
-
- # Sends unescaped data to client, possibly compressing it if needed
- def send_raw(buf)
- if @compress
- zbuf = Zlib.deflate(buf)
- else
- zbuf = buf
- end
- @client.send_data(zbuf)
- end
-
- # Send data to client (escapes IAC bytes)
- def send_escaped(buf)
- iac = TELNET_IAC.chr
- self.send_raw(buf.gsub("#{iac}", "#{iac}#{iac}")
- end
-
- # Send negotiation bytes
-
- /* send negotiation bytes */
- def send_negotiate(cmd, telopt)
- bytes = ""
- bytes << TELNET_IAC
- bytes << cmd
- bytes << telopt
- send_raw(bytes)
- end
-
- # Check if we support a particular telopt;
- def us_support(telopt)
- have = @telopts[telopt]
- return false unless have
- return (have.telopt == telopt) && have.us
- end
-
- # Check if the remote supports a telopt
- def him_support(telopt)
- have = @telopts[telopt]
- return false unless have
- return (have.telopt == telopt) && have.him
- end
-
-
- # retrieve RFC1143 option state
- def rfc1143_get(telopt)
- @rfc1143[telopt]
- end
-
-
- # save RFC1143 option state
- def rfc1143_set(telopt, us, him)
- agree = we_support(telopt)
- @rfc1143[telopt] = RFC1143.new(telopt, us, him, agree)
- return @rfc1143[telopt]
- end
-
-
- # RFC1143 telnet option negotiation helper
- def rfc1143_negotiate_will(rfc1143)
- return rfc1143.handle_will
- end
-
- # RFC1143 telnet option negotiation helper
- def rfc1143_negotiate_wont(rfc1143)
- return rfc1143.handle_wont
- end
-
- # RFC1143 telnet option negotiation helper
- def rfc1143_negotiate_do(rfc1143)
- return rfc1143.handle_do
- end
-
- # RFC1143 telnet option negotiation helper
- def rfc1143_negotiate_dont(rfc1143)
- return rfc1143.handle_dont
- end
-
- # RFC1143 telnet option negotiation helper
- def rfc1143_negotiate(telopt)
- q = rfc1143_get(telopt)
- return nil, nil unless q
-
- case @state
- when :will
- return rfc1143_negotiate_will(q)
- when :wont
- return rfc1143_negotiate_wont(q)
- when :do
- return rfc1143_negotiate_do(q)
- when :dont
- return rfc1143_negotiate_dont(q)
- end
- end
-
- def do_negotiate(telopt)
- res, arg = rfc1143_negotiate(telopt)
- return unless res
- if res == :error
- log_error(arg)
- else
- send_negotiate(res, arg)
- end
- end
-
-
-
- # Called when server data should be filtered before being passed to the client
- def server_to_client(data)
-
- end
- end
|