telnet.rb 14 KB

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