07-13-2013 12:56 PM
I've been trying to write a script that would telnet to another device to run some commands. Unfortunately, whatever I do, it seems I'm never getting past the motd banner. When executed, the script does open the session, and I get the full banner, but then it stops until the other device times out. I never the "Username:" prompt. Wireshark tells me the prompt is delivered, so I don't know what I'm doing wrong.
Help!
proc waitfor {sock pattern {delay 500}} {
while { 1 } {
after $delay { return -code error "delay expired" }
gets $sock line
puts $line
if { [string match [string tolower $pattern] [string tolower $line]] } {
puts "match"
return -code ok
}
}
}
set host "yoink!"
set username "yoink!"
set password "yoink!"
set hostname "yoink!"
puts "Trying to connect to $host\n\n"
set sock [socket $host 23]
waitfor $sock "username:"
puts $sock $username
waitfor $sock "password:"
puts $sock $password
waitfor $sock "$hostname#"
puts $sock "show clock"
waitfor $sock "$hostname#"
close $sock
07-13-2013 06:52 PM
After some more tests, I found something odd.
Here's an output while running the script.
router#tclsh tftp://10.120.1.2/telnet3.tcl
Loading telnet3.tcl from 10.120.1.2 (via GigabitEthernet0/0): !
[OK - 811 bytes]
Trying to connect to 10.180.39.1
{^A{^C}^X}^_ <- Telnet negociation garbage
MOTD Banner Here!
Username: <- There's a long delay (auth timeout) before this appears
And all following lines appear at once.
step 2 <- Some debug
% Username: timeout expired!
error reading "sock0": broken pipe
while executing
"gets $sock line"
(procedure "waitfor" line 4)
invoked from within
"waitfor $sock "password:""
(file "tftp://10.120.1.2/telnet3.tcl" line 28)
router#
So I did a manual telnet, and it looks like this.
router#telnet 10.180.39.1
Trying 10.180.39.1 ... Open
MOTD Banner Here!
User Access Verification <- This line doesn't appear in the script
Username:
So it seems this line is causing the script to bog down somehow.
07-14-2013 08:43 AM
Waiting doesn't help when it comes to sockets. You need to read from them to drain them of data. Have a look at
http://wiki.tcl.tk/684 for an example Tcl telnet client. This client will also handle the telnet negotiation characters for you.
07-14-2013 06:19 PM
If I take this down to its simplest form, it looks something like this:
set sock [socket 10.10.128.201 23]
while {[gets $sock line] >= 0 } {
puts $line
}
close $sock
Technically, if I run this, it should give me the same output as if I telnet from the originating device. When I do telnet, I get this:
switch#telnet 10.10.128.201
Trying 10.10.128.201 ... Open
User Access Verification
Password:
When I run the script, I get this:
switch#tclsh tftp://10.120.1.2/telnet5.tcl
Loading telnet5.tcl from 10.120.1.2 (via Vlan31): !
[OK - 129 bytes]
{^C{^A{^C{^A
User Access Verification
I still don't get that final line, and I don't know why.
07-14-2013 10:32 PM
Because you aren't speaking the telnet protocol. Telnet is more than a raw socket. Those negotiation options control things like echo and flow control. You need to acknowledge them in order to continue the session.
07-15-2013 06:04 AM
I think I figured out at least part of the problem. The username, password or router prompts don't end with a CrLf. From what I'm reading, they can't be pulled with a gets as long as it hasn't reached an eol. I've tried using the previous line's text as my trigger to send the proper input and now I'm getting further.
Do you know how I can make gets / fconfigure ignore oel's and send whatever it has? I'd have to reconstruct lines myself, but I don't think I have much of a choice.
As an aside, in a previous iteration, I parsed and answered the WILLs and DOs with WONTs and DOs, and the telnet server (from a debug telnet on the receiving device) liked them, but it didn't change the behavior regarding the last line. I think the CrLf makes sence.
Thank you for your precious help.
07-15-2013 12:08 PM
I was able to make the telnet client example I posted work (I got the prompts). There were two things I needed to change, though. One was to change iso8859-1 to utf-8 and the other was to change the "$byte" variable in the switch statement of the protocol function to "$op". Then you can add in your bits to automatically interact with the prompts. The other fconfigures in there already do the job for making the socket fully readable.
Another option you might consider, which might be a bit easier, is to wrap the "telnet" CLI command from IOS. If you interact with that, it takes all of the socket reading and writing out of the equation. I did a script called the EASy command shell at http://www.cisco.com/go/easy that does this.
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide