telnet.rb 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. require 'zlib'
  2. require_relative 'telnet/codes'
  3. require_relative 'rfc1143'
  4. require_relative 'monolog'
  5. # This Telnet class implements a subset of the Telnet protocol.
  6. #
  7. class Telnet
  8. include Monolog
  9. include Telnet::Codes
  10. # Allowed telnet state codes
  11. STATES = [:data, :iac, :will, :wont, :do, :dont, :sb, :sb_data, :sb_data_iac]
  12. # Helper structs
  13. Telopt = Struct.new(:telopt, :us, :him)
  14. attr_reader :telopts
  15. def initialize(client)
  16. @client = client
  17. @telopts = {} # Telopt support.
  18. @rfc1143 = {} # RFC1143 support.
  19. @buffer = "" # Subrequest buffer
  20. @state = :data # state of telnet protocol parser.
  21. @sb_telopt = nil; # current subnegotiation
  22. @compress = false # compression state
  23. @zdeflate = Zlib::Deflate.new() # Deflate stream for compression2 support.
  24. @zinflate = Zlib::Inflate.new() # Inflate stream for compression2 support.
  25. end
  26. # Closes the telnet connection, send last compressed data if needed.
  27. def close
  28. if @compress
  29. zbuf = @zdeflate.flush(Zlib::FINISH)
  30. @client.telnet_send_data(zbuf)
  31. end
  32. @zdeflate.close
  33. @zinflate.close
  34. end
  35. # Send an event to the client to notify it of a state change or of data
  36. def send_event(type, *data)
  37. @client.telnet_event(type, *data)
  38. end
  39. # Sends unescaped data to client, possibly compressing it if needed
  40. def send_raw(buf)
  41. if @compress
  42. @zdeflate << buf
  43. zbuf = @zdeflate.flush(Zlib::SYNC_FLUSH)
  44. p "Deflating #{buf} -> #{zbuf}"
  45. else
  46. zbuf = buf
  47. end
  48. # Don't use send_event here, since that's only for events received
  49. @client.telnet_send_data(zbuf)
  50. end
  51. # Send data to client (escapes IAC bytes)
  52. def send_escaped(buf)
  53. iac = TELNET_IAC.chr
  54. self.send_raw(buf.gsub("#{iac}", "#{iac}#{iac}"))
  55. end
  56. # Send negotiation bytes
  57. # negotiation bytes
  58. def send_negotiate(cmd, telopt)
  59. bytes = ""
  60. bytes << TELNET_IAC
  61. bytes << cmd
  62. bytes << telopt
  63. send_raw(bytes)
  64. end
  65. #
  66. # Check if we support a particular telsopt using the RFC1143 state
  67. def us_support(telopt)
  68. have = @rfc1143[telopt]
  69. return false unless have
  70. return (have.telopt == telopt) && have.us == :yes
  71. end
  72. # Check if the remote supports a telopt (and it is enabled)
  73. def him_support(telopt)
  74. have = @rfc1143[telopt]
  75. return false unless have
  76. return (have.telopt == telopt) && have.him == :yes
  77. end
  78. # Set that we support an option (using the RFC1143 state)
  79. def set_support(telopt, support=true, us = :no, him = :no)
  80. rfc1143_set(telopt, support=true, us = :no, him = :no)
  81. end
  82. # retrieve RFC1143 option state
  83. def rfc1143_get(telopt)
  84. @rfc1143[telopt]
  85. end
  86. # save RFC1143 option state
  87. def rfc1143_set(telopt, support=true, us = :no, him = :no)
  88. agree = support
  89. @rfc1143[telopt] = RFC1143.new(telopt, us, him, agree)
  90. return @rfc1143[telopt]
  91. end
  92. # RFC1143 telnet option negotiation helper
  93. def rfc1143_negotiate(telopt)
  94. q = rfc1143_get(telopt)
  95. return nil, nil unless q
  96. case @state
  97. when :will
  98. return q.handle_will
  99. when :wont
  100. return q.handle_wont
  101. when :do
  102. return q.handle_do
  103. when :dont
  104. return q.handle_dont
  105. end
  106. end
  107. # Performs a telnet negotiation
  108. def do_negotiate(telopt)
  109. res, arg = rfc1143_negotiate(telopt)
  110. send_event(@state, telopt, res, arg)
  111. end
  112. # Process a subnegotiation buffer for a naws event
  113. def subnegotiate_naws(buffer)
  114. arr = buffer.bytes.to_a
  115. w = (arr[0] << 8) + arr[1]
  116. h = (arr[2] << 8) + arr[3]
  117. send_event(:naws, w, h)
  118. end
  119. # Storage for environment values
  120. class Environment
  121. attr_accessor :type
  122. attr_accessor :value
  123. def initialize(type, value)
  124. @type = type
  125. @value = value
  126. end
  127. end
  128. # process an ENVIRON/NEW-ENVIRON subnegotiation buffer
  129. def subnegotiate_environ(buffer)
  130. vars = []
  131. cmd = ""
  132. arr = buffer.bytes.to_a
  133. fb = arr.first
  134. # first byte must be a valid command
  135. if fb != TELNET_ENVIRON_SEND && fb != TELNET_ENVIRON_IS && fb != TELNET_ENVIRON_INFO
  136. log_error("telopt environment subneg command not valid")
  137. return 0
  138. end
  139. cmd << fb
  140. if (buffer.size == 1)
  141. send_event(:environment, fb, vars)
  142. return false
  143. end
  144. # Second byte must be VAR or USERVAR, if present
  145. sb = arr[1]
  146. if sb != TELNET_ENVIRON_VAR && fb != TELNET_ENVIRON_USEVAR
  147. log_error("telopt environment subneg missing variable type")
  148. return false
  149. end
  150. # ensure last byte is not an escape byte (makes parsing later easier)
  151. lb = arr.last
  152. if lb == TELNET_ENVIRON_ESC
  153. log_error("telopt environment subneg ends with ESC")
  154. return false
  155. end
  156. var = nil
  157. index = 1
  158. escape = false
  159. arr.shift
  160. arr.each do | c |
  161. case c
  162. when TELNET_ENVIRON_VAR
  163. when TELNET_ENVIRON_VALUE
  164. when TELNET_ENVIRON_USERVAR
  165. if escape
  166. escape = false
  167. var.value << c
  168. elsif var
  169. vars << var
  170. var = Environment.new(c, "")
  171. else
  172. var = Environment.new(c, "")
  173. end
  174. when TELNET_ENVIRON_ESC
  175. escape = true
  176. else
  177. var.value << c
  178. end # case
  179. end # each
  180. send_event(:environment, fb, vars)
  181. return false
  182. end
  183. # process an MSSP subnegotiation buffer
  184. def subnegotiate_mssp(buffer)
  185. telnet_event_t ev;
  186. struct telnet_environ_t *values;
  187. char *var = 0;
  188. char *c, *last, *out;
  189. size_t i, count;
  190. unsigned char next_type;
  191. if buffer.size < 1
  192. return 0
  193. end
  194. arr = buffer.bytes.to_a
  195. fb = arr.first
  196. # first byte must be a valid command
  197. if fb != TELNET_MSSSP_VAR
  198. log_error("telopt MSSP subneg data not valid")
  199. return false
  200. end
  201. vars = {}
  202. var = ""
  203. val = ""
  204. mstate = :var
  205. while index < arr.size
  206. c = arr[index]
  207. case c
  208. when TELNET_MSSP_VAR
  209. mstate = :var
  210. if mstate == :val
  211. vars[var] = val
  212. var = ""
  213. val = ""
  214. end
  215. when TELNET_MSSP_VAL
  216. mstate = :val
  217. else
  218. if mstate == :var
  219. var << c
  220. elsif mstate == :val
  221. val << c
  222. end
  223. end # case
  224. index += 1
  225. end # while
  226. send_event(:mssp, vars)
  227. return false
  228. end
  229. # parse ZMP command subnegotiation buffers
  230. def subnegotiate_zmp(buffer)
  231. args = []
  232. arg = ""
  233. buffer.each_byte do |b|
  234. if b == 0
  235. args << arg
  236. arg = ""
  237. else
  238. arg << byte
  239. end
  240. end
  241. send_event(:zmp, vars)
  242. return false
  243. end
  244. # parse TERMINAL-TYPE command subnegotiation buffers
  245. def subnegotiate_ttype(buffer)
  246. # make sure request is not empty
  247. if buffer.size == 0
  248. log_error("Incomplete TERMINAL-TYPE request");
  249. return 0
  250. end
  251. arr = buffer.bytes
  252. fb = arr.first
  253. term = nil
  254. if fb == TELNET_TTYPE_IS
  255. term = buffer[1, buffer.size]
  256. send_event(:ttype_is, term)
  257. elsif fb == TELNET_TTYPE_SEND
  258. term = buffer[1, buffer.size]
  259. send_event(:ttype_send, term)
  260. else
  261. log_error("TERMINAL-TYPE request has invalid type")
  262. return false
  263. end
  264. return false
  265. end
  266. # process a subnegotiation buffer; returns true if the current buffer
  267. # must be aborted and reprocessed due to COMPRESS2 being activated
  268. def do_subnegotiate(buffer)
  269. case @sb_teloptTELNET_MSSSP_VAR
  270. when TELNET_TELOPT_COMPRESS2
  271. # received COMPRESS2 begin marker, setup our zlib box and
  272. # start handling the compressed stream if it's not already.
  273. @compress = true
  274. send_event(:compress, @compress)
  275. return true
  276. # specially handled subnegotiation telopt types
  277. when TELNET_TELOPT_ZMP
  278. return subnegotiate_zmp(buffer)
  279. when TELNET_TELOPT_TTYPE
  280. return subnegotiate_ttype(buffer)
  281. when TELNET_TELOPT_ENVIRON
  282. return subnegotiate_environ(buffer)
  283. when TELNET_TELOPT_NEW_ENVIRON
  284. return subnegotiate_environ(buffer)
  285. when TELNET_TELOPT_MSSP
  286. return subnegotiate_mssp(buffer)
  287. when TELNET_TELOPT_NAWS
  288. return subnegotiate_naws(buffer)
  289. else
  290. send_event(:subnegotiate, @sb_telopt, buffer)
  291. return false
  292. end
  293. end
  294. def process_byte(byte)
  295. # p "process_byte, #{@state} #{byte}"
  296. case @state
  297. # regular data
  298. when :data
  299. if byte == TELNET_IAC
  300. # receive buffered bytes as data and go to IAC state if it's notempty
  301. send_event(:data, @buffer) unless @buffer.empty?
  302. @buffer = ""
  303. @state = :iac
  304. else
  305. @buffer << byte
  306. end
  307. # IAC received before
  308. when :iac
  309. case byte
  310. # subnegotiation
  311. when TELNET_SB
  312. @state = :sb
  313. # negotiation commands
  314. when TELNET_WILL
  315. @state = :will
  316. when TELNET_WONT
  317. @state = :wont
  318. when TELNET_DO
  319. @state = :do
  320. when TELNET_DONT
  321. @state = :dont
  322. # IAC escaping
  323. when TELNET_IAC
  324. @buffer << byte
  325. send_raw(@buffer)
  326. @buffer = ""
  327. @state = :data
  328. # some other command
  329. else
  330. send_event(:iac, byte)
  331. @state = :data
  332. end
  333. # negotiation received before
  334. when :will, :wont, :do, :dont
  335. do_negotiate(byte)
  336. @state = :data
  337. # subnegotiation started, determine option to subnegotiate
  338. when :sb
  339. @sb_telopt = byte
  340. @state = :sb_data
  341. # subnegotiation data, buffer bytes until the end request
  342. when :sb_data
  343. # IAC command in subnegotiation -- either IAC SE or IAC IAC
  344. if (byte == TELNET_IAC)
  345. @state = :sb_data_iac
  346. elsif (@sb_telopt == TELNET_TELOPT_COMPRESS && byte == TELNET_WILL)
  347. # MCCPv1 defined an invalid subnegotiation sequence (IAC SB 85 WILL SE)
  348. # to start compression. Catch and discard this case, only support
  349. # MMCPv2.
  350. @state = data
  351. else
  352. @buffer << byte
  353. end
  354. # IAC received inside a subnegotiation
  355. when :sb_data_iac
  356. case byte
  357. # end subnegotiation
  358. when TELNET_SE
  359. @state = :data
  360. # process subnegotiation
  361. compress = do_subnegotiate(@buffer)
  362. # if compression was negotiated, the rest of the stream is compressed
  363. # and processing it requires decompressing it. Return true to signal
  364. # this.
  365. @buffer = ""
  366. return true if compress
  367. # escaped IAC byte
  368. when TELNET_IAC
  369. # push IAC into buffer */
  370. @buffer << byte
  371. @state = :sb_data
  372. # something else -- protocol error. attempt to process
  373. # content in subnegotiation buffer, then evaluate the
  374. # given command as an IAC code.
  375. else
  376. log_error("Unexpected byte after IAC inside SB: %d", byte)
  377. @state = :iac
  378. # subnegotiate with the buffer anyway, even though it's an error
  379. compress = do_subnegotiate(@buffer)
  380. # if compression was negotiated, the rest of the stream is compressed
  381. # and processing it requires decompressing it. Return true to signal
  382. # this.
  383. @buffer = ""
  384. return true if compress
  385. end
  386. when :data
  387. # buffer any other bytes
  388. @buffer << byte
  389. else
  390. # programing error, shouldn't happen
  391. raise "Error in telet state machine!"
  392. end
  393. # return false to signal compression needn't start
  394. return false
  395. end
  396. def process_bytes(bytes)
  397. # I have a feeling this way of handling strings isn't very efficient.. :p
  398. arr = bytes.bytes.to_a
  399. byte = arr.shift
  400. while byte
  401. compress = process_byte(byte)
  402. if compress
  403. # paper over this for a while...
  404. new_bytes = Zlib.inflate(arr.pack('c*')) rescue nil
  405. if new_bytes
  406. arr = new_bytes.bytes.to_a
  407. end
  408. end
  409. byte = arr.shift
  410. end
  411. send_event(:data, @buffer) unless @buffer.empty?
  412. @buffer = ""
  413. end
  414. # Call this when the server receives data from the client
  415. def telnet_receive(data)
  416. # the COMPRESS2 protocol seems to be half-duplex in that only
  417. # the server's data stream is compressed (unless maybe if the client
  418. # is asked to also compress with a DO command ?)
  419. process_bytes(data)
  420. end
  421. # Send a bytes array (raw) to the client
  422. def telnet_send_bytes(*bytes)
  423. s = bytes.pack('C*')
  424. send_raw(s)
  425. end
  426. # send an iac command
  427. def telnet_send_iac(cmd)
  428. telnet_send_bytes(TELNET_IAC, cmd)
  429. end
  430. # send negotiation
  431. def telnet_send_negotiate(cmd, telopt)
  432. # get current option states
  433. q = rfc1143_get(telopt)
  434. unless q
  435. rfc1143_set(telopt)
  436. q = rfc1143_get(telopt)
  437. end
  438. act, arg = nil, nil
  439. case cmd
  440. when TELNET_WILL
  441. act, arg = q.send_will
  442. when TELNET_WONT
  443. act, arg = q.send_wont
  444. when TELNET_DO
  445. act, arg = q.send_do
  446. when TELNET_DONT
  447. act, arg = q.send_dont
  448. end
  449. return false unless act
  450. telnet_send_bytes(TELNET_IAC, act, telopt)
  451. end
  452. # send non-command data (escapes IAC bytes)
  453. def telnet_send(buffer)
  454. send_escaped(buffer)
  455. end
  456. # send subnegotiation header
  457. def telnet_begin_sb(telopt)
  458. telnet_send_bytes(TELNET_IAC, TELNET_SB, telopt)
  459. end
  460. # send subnegotiation ending
  461. def telnet_end_sb()
  462. telnet_send_bytes(TELNET_IAC, TELNET_SE)
  463. end
  464. # send complete subnegotiation
  465. def telnet_subnegotiation(telopt, buffer = nil)
  466. telnet_send_bytes(TELNET_IAC, TELNET_SB, telopt)
  467. telnet_send(buffer) if buffer;
  468. telnet_send_bytes(TELNET_IAC, TELNET_SE)
  469. end
  470. # start compress2 compression
  471. def telnet_begin_compress2()
  472. telnet_send_bytes(TELNET_IAC, TELNET_SB, TELNET_TELOPT_COMPRESS2, TELNET_IAC, TELNET_SE);
  473. @compress = true
  474. end
  475. # send formatted data
  476. def telnet_raw_printf(fmt, *args)
  477. buf = sprintf(fmt, *args)
  478. telnet_send(buf)
  479. end
  480. # send formatted data with \r and \n translation in addition to IAC IAC
  481. def telnet_printf(fmt, *args)
  482. crlf = "\r\n"
  483. clnul = "\r\0"
  484. buf = sprintf(fmt, *args)
  485. buf.gsub!("\r", crnul)
  486. buf.gsub!("\n", crlf)
  487. telnet_send(buf)
  488. end
  489. # begin NEW-ENVIRON subnegotation
  490. def telnet_begin_newenviron(cmd)
  491. telnet_begin_sb(TELNET_TELOPT_NEW_ENVIRON)
  492. telnet_send_bytes(cmd)
  493. end
  494. # send a NEW-ENVIRON value
  495. def telnet_newenviron_value(type, value)
  496. telnet_send_bytes(type)
  497. telnet_send(string)
  498. end
  499. # send TERMINAL-TYPE SEND command
  500. def telnet_ttype_send()
  501. telnet_send_bytes(TELNET_IAC, TELNET_SB, TELNET_TELOPT_TTYPE, TELNET_TTYPE_SEND, TELNET_IAC, TELNET_SE)
  502. end
  503. # send TERMINAL-TYPE IS command
  504. def telnet_ttype_is(ttype)
  505. telnet_send_bytes(TELNET_IAC, TELNET_SB, TELNET_TELOPT_TTYPE, TELNET_TTYPE_IS)
  506. telnet_send(ttype)
  507. end
  508. # send MSSP data
  509. def telnet_send_mssp(mssp)
  510. buf = ""
  511. mssp.each do | key, val|
  512. buf << TELNET_MSSP_VAR.chr
  513. buf << key
  514. buf << TELNET_MSSP_VAL.chr
  515. buf << val
  516. end
  517. telnet_subnegotiation(TELNET_TELOPT_MSSP, buf)
  518. end
  519. end