#!/usr/bin/ruby # dumb telnet client # Author: Yoann Guillot 2009 # License: WtfPLv2 require 'socket' class Telnet attr_accessor :s def initialize(host, port=23) @s = TCPSocket.open(host, port) end # reads from the socket until nothing is available for timeout seconds # interprets & reject telnet negotiation messages def read(timeout=0.4) buf = '' while IO.select([@s], nil, nil, timeout) and buf.length < 512 case c = @s.read(1)[0] when 255 # telnet msg case c = @s.read(1)[0] when 253, 251 # want/will use option c = @s.read(1)[0] puts "telnetneg: refusing #{c}" if $DEBUG @s.write [255, 252, c].pack('C*') else puts "telnetneg: unk msg #{c}" if $VERBOSE end when 0x80..0xff puts "telnetneg: unk #{c}" if $VERBOSE else buf << c end end buf end def write(s) @s.write s end def puts(*s) s.each { |s_| write s_.chomp + "\r\n" } end # calls puts() and read() def cmd(*s) puts(*s) ; read end end if __FILE__ == $0 require 'optparse' # default options opts = { :host => '192.168.1.1', :port => 23, :login => 'root', :pass => 'root', :cmd => [] } # 1st arg: [login[:pass]@]host[:port] if ARGV.first =~ /^(?:(.*?)(?::(.*?))?@)?([a-zA-Z0-9].*?)(?::(.*?))?$/ opts[:login] = $1 if $1 opts[:pass] = $2 if $2 opts[:host] = $3 opts[:port] = $4 if $4 end # parse options OptionParser.new { |opt| opt.on('-h h', '--host h') { |h| opts[:host] = h } opt.on('-p p', '--port p') { |p| opts[:port] = p } opt.on('-l l', '--login l') { |l| opts[:login] = l } opt.on('-P p', '--pass p') { |p| opts[:pass] = p } opt.on('-c cmd', '--cmd c') { |c| opts[:cmd] << c } }.parse!(ARGV) p opts if $DEBUG $stdout.sync = true # connect t = Telnet.new(opts[:host], opts[:port]) # login cx = t.cmd(opts[:login]) + t.cmd(opts[:pass]) print cx if $VERBOSE # send cmdline commands opts[:cmd].each { |c| print t.cmd(c) } # keyboard interact loop do next if not IO.select([$stdin, t.s], nil, nil, 4) print t.read(0) if IO.select([$stdin], nil, nil, 0) c = $stdin.gets print t.cmd(c) end end end