telnet.cr 15 KB

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