summaryrefslogtreecommitdiff
path: root/lib/telnet.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/telnet.rb')
-rw-r--r--lib/telnet.rb169
1 files changed, 131 insertions, 38 deletions
diff --git a/lib/telnet.rb b/lib/telnet.rb
index ca68e1b3e5..9c99e026d7 100644
--- a/lib/telnet.rb
+++ b/lib/telnet.rb
@@ -1,8 +1,14 @@
#
# telnet.rb
-# ver0.13 1998/08/25
+# ver0.14 1998/09/01
# Wakou Aoyama <wakou@fsinet.or.jp>
#
+# ver0.14 1998/09/01
+# IAC WILL SGA send EOL --> CR+NULL
+# IAC WILL SGA IAC DO BIN send EOL --> CR
+# NONE send EOL --> LF
+# add Dump_log option.
+#
# ver0.13 1998/08/25
# add print method.
#
@@ -26,6 +32,7 @@
# host = Telnet.new({"Binmode" => TRUE, default: TRUE
# "Host" => "localhost", default: "localhost"
# "Output_log" => "output_log", default: not output
+# "Dump_log" => "dump_log", default: not output
# "Port" => 23, default: 23
# "Prompt" => /[$%#>] $/, default: /[$%#>] $/
# "Telnetmode" => TRUE, default: TRUE
@@ -131,29 +138,73 @@ class Telnet < SimpleDelegator
is_timeout
end
- # For those who are curious, here are some of the special characters
- # interpretted by the telnet protocol:
- # Name Octal Dec. Description
- CR = "\015"
- LF = "\012"
- EOL = CR + LF # /* end of line */
- IAC = "\377" # 255 /* interpret as command: */
- DONT = "\376" # 254 /* you are not to use option */
- DO = "\375" # 253 /* please, you use option */
- WONT = "\374" # 252 /* I won't use option */
- WILL = "\373" # 251 /* I will use option */
- # SB = "\372" # 250 /* interpret as subnegotiation */
- # GA = "\371" # 249 /* you may reverse the line */
- # EL = "\370" # 248 /* erase the current line */
- # EC = "\367" # 247 /* erase the current character */
- AYT = "\366" # 246 /* are you there */
- # AO = "\365" # 245 /* abort output--but let prog finish */
- # IP = "\364" # 244 /* interrupt process--permanently */
- # BREAK = "\363" # 243 /* break */
- # DM = "\362" # 242 /* data mark--for connect. cleaning */
- # NOP = "\361" # 241 /* nop */
- # SE = "\360" # 240 /* end sub negotiation */
- # EOR = "\357" # 239 /* end of record (transparent mode) */
+ IAC = 255.chr # interpret as command:
+ DONT = 254.chr # you are not to use option
+ DO = 253.chr # please, you use option
+ WONT = 252.chr # I won't use option
+ WILL = 251.chr # I will use option
+ SB = 250.chr # interpret as subnegotiation
+ GA = 249.chr # you may reverse the line
+ EL = 248.chr # erase the current line
+ EC = 247.chr # erase the current character
+ AYT = 246.chr # are you there
+ AO = 245.chr # abort output--but let prog finish
+ IP = 244.chr # interrupt process--permanently
+ BREAK = 243.chr # break
+ DM = 242.chr # data mark--for connect. cleaning
+ NOP = 241.chr # nop
+ SE = 240.chr # end sub negotiation
+ EOR = 239.chr # end of record (transparent mode)
+ ABORT = 238.chr # Abort process
+ SUSP = 237.chr # Suspend process
+ EOF = 236.chr # End of file
+ SYNCH = 242.chr # for telfunc calls
+
+ OPT_BINARY = 0.chr # Binary Transmission
+ OPT_ECHO = 1.chr # Echo
+ OPT_RCP = 2.chr # Reconnection
+ OPT_SGA = 3.chr # Suppress Go Ahead
+ OPT_NAMS = 4.chr # Approx Message Size Negotiation
+ OPT_STATUS = 5.chr # Status
+ OPT_TM = 6.chr # Timing Mark
+ OPT_RCTE = 7.chr # Remote Controlled Trans and Echo
+ OPT_NAOL = 8.chr # Output Line Width
+ OPT_NAOP = 9.chr # Output Page Size
+ OPT_NAOCRD = 10.chr # Output Carriage-Return Disposition
+ OPT_NAOHTS = 11.chr # Output Horizontal Tab Stops
+ OPT_NAOHTD = 12.chr # Output Horizontal Tab Disposition
+ OPT_NAOFFD = 13.chr # Output Formfeed Disposition
+ OPT_NAOVTS = 14.chr # Output Vertical Tabstops
+ OPT_NAOVTD = 15.chr # Output Vertical Tab Disposition
+ OPT_NAOLFD = 16.chr # Output Linefeed Disposition
+ OPT_XASCII = 17.chr # Extended ASCII
+ OPT_LOGOUT = 18.chr # Logout
+ OPT_BM = 19.chr # Byte Macro
+ OPT_DET = 20.chr # Data Entry Terminal
+ OPT_SUPDUP = 21.chr # SUPDUP
+ OPT_SUPDUPOUTPUT = 22.chr # SUPDUP Output
+ OPT_SNDLOC = 23.chr # Send Location
+ OPT_TTYPE = 24.chr # Terminal Type
+ OPT_EOR = 25.chr # End of Record
+ OPT_TUID = 26.chr # TACACS User Identification
+ OPT_OUTMRK = 27.chr # Output Marking
+ OPT_TTYLOC = 28.chr # Terminal Location Number
+ OPT_3270REGIME = 29.chr # Telnet 3270 Regime
+ OPT_X3PAD = 30.chr # X.3 PAD
+ OPT_NAWS = 31.chr # Negotiate About Window Size
+ OPT_TSPEED = 32.chr # Terminal Speed
+ OPT_LFLOW = 33.chr # Remote Flow Control
+ OPT_LINEMODE = 34.chr # Linemode
+ OPT_XDISPLOC = 35.chr # X Display Location
+ OPT_OLD_ENVIRON = 36.chr # Environment Option
+ OPT_AUTHENTICATION = 37.chr # Authentication Option
+ OPT_ENCRYPT = 38.chr # Encryption Option
+ OPT_NEW_ENVIRON = 39.chr # New Environment Option
+
+ NULL = "\000"
+ CR = "\015"
+ LF = "\012"
+ EOL = CR + LF
def initialize(options)
@options = options
@@ -165,21 +216,31 @@ class Telnet < SimpleDelegator
@options["Timeout"] = 10 if not @options.include?("Timeout")
@options["Waittime"] = 0 if not @options.include?("Waittime")
+ @telnet_option = { "SGA" => FALSE, "BINARY" => FALSE }
+
if @options.include?("Output_log")
@log = File.open(@options["Output_log"], 'a+')
@log.sync = TRUE
@log.binmode if @options["Binmode"]
end
+ if @options.include?("Dump_log")
+ @dumplog = File.open(@options["Dump_log"], 'a+')
+ @dumplog.sync = TRUE
+ @dumplog.binmode
+ end
+
message = "Trying " + @options["Host"] + "...\n"
STDOUT.write(message)
@log.write(message) if @options.include?("Output_log")
+ @dumplog.write(message) if @options.include?("Dump_log")
is_timeout = timeout(@options["Timeout"]){
begin
@sock = TCPsocket.open(@options["Host"], @options["Port"])
rescue
@log.write($! + "\n") if @options.include?("Output_log")
+ @dumplog.write($! + "\n") if @options.include?("Dump_log")
raise
end
}
@@ -190,26 +251,51 @@ class Telnet < SimpleDelegator
message = "Connected to " + @options["Host"] + ".\n"
STDOUT.write(message)
@log.write(message) if @options.include?("Output_log")
+ @dumplog.write(message) if @options.include?("Dump_log")
super(@sock)
end
def preprocess(str)
- str.gsub!(/#{EOL}/no, "\n") # combine EOL into "\n"
+ str.gsub!(/#{CR}#{NULL}/no, CR) # combine CR+NULL into CR
+ str.gsub!(/#{EOL}/no, "\n") # combine EOL into "\n"
- # respond to "IAC DO x" or "IAC DON'T x" with "IAC WON'T x"
- str.gsub!(/([^#{IAC}])?#{IAC}[#{DO}#{DONT}](.|\n)/no){
+ # respond to "IAC DO x"
+ str.gsub!(/([^#{IAC}])?#{IAC}#{DO}(.|\n)/no){
+ if OPT_BINARY == $2
+ @telnet_option["BINARY"] = TRUE
+ @sock.write(IAC + WILL + OPT_BINARY)
+ $1
+ else
@sock.write(IAC + WONT + $2)
$1
+ end
}
- # ignore "IAC WILL x" or "IAC WON'T x"
- str.gsub!(/([^#{IAC}])?#{IAC}[#{WILL}#{WONT}](.|\n)/no, '\1')
+ # respond to "IAC DON'T x" with "IAC WON'T x"
+ str.gsub!(/([^#{IAC}])?#{IAC}#{DONT}(.|\n)/no){
+ @sock.write(IAC + WONT + $2)
+ $1
+ }
+
+ # respond to "IAC WILL x"
+ str.gsub!(/([^#{IAC}])?#{IAC}#{WILL}(.|\n)/no){
+ if OPT_SGA == $2
+ @telnet_option["SGA"] = TRUE
+ @sock.write(IAC + DO + OPT_SGA)
+ $1
+ else
+ $1
+ end
+ }
+
+ # ignore "IAC WON'T x"
+ str.gsub!(/([^#{IAC}])?#{IAC}#{WONT}(.|\n)/no, '\1')
# respond to "IAC AYT" (are you there)
str.gsub!(/([^#{IAC}])?#{IAC}#{AYT}/no){
- @sock.write("nobody here but us pigeons" + EOL)
- $1
+ @sock.write("nobody here but us pigeons" + EOL)
+ $1
}
str.gsub(/#{IAC}#{IAC}/no, IAC) # handle escaped IAC characters
@@ -235,11 +321,9 @@ class Telnet < SimpleDelegator
not select([@sock], nil, nil, timeout)
buf = ''
begin
- buf = if @options["Telnetmode"]
- preprocess( @sock.sysread(1024 * 1024) )
- else
- @sock.sysread(1024 * 1024)
- end
+ buf = @sock.sysread(1024 * 1024)
+ @dumplog.print(buf) if @options.include?("Dump_log")
+ buf = preprocess(buf) if @options["Telnetmode"]
rescue EOFError # End of file reached
break
ensure
@@ -252,7 +336,16 @@ class Telnet < SimpleDelegator
end
def print(string)
- @sock.write(string.gsub(/\n/, EOL) + EOL)
+ if @telnet_option["BINARY"] and @telnet_option["SGA"]
+ # IAC WILL SGA IAC DO BIN send EOL --> CR
+ @sock.write(string.gsub(/\n/, CR) + CR)
+ elsif @telnet_option["SGA"]
+ # IAC WILL SGA send EOL --> CR+NULL
+ @sock.write(string.gsub(/\n/, CR + NULL) + CR + NULL)
+ else
+ # NONE send EOL --> LF
+ @sock.write(string.gsub(/\n/, LF) + LF)
+ end
end
def cmd(options)
@@ -268,7 +361,7 @@ class Telnet < SimpleDelegator
end
select(nil, [@sock])
- @sock.write(string.gsub(/\n/, EOL) + EOL)
+ print(string)
if iterator?
waitfor({"Prompt" => match, "Timeout" => timeout}){|c| yield c }
else