[rancid] patch for "out of band" access to devices

Ed Ravin eravin at panix.com
Thu May 18 21:50:27 UTC 2006

On Fri, May 12, 2006 at 10:47:49PM -0400, Ed Ravin wrote:
> On Tue, Aug 16, 2005 at 03:56:04PM +1000, Andrew Pollock wrote:
> ...
> > So the only way of managing the devices is via SSHing to the Cyclades and
> > getting on the console port. We can SSH directly to a specific port of the
> > Cyclades, and after authenticating, get on the console attached to that
> > port, and disconnect by way of the standard SSH disconnect break sequence
> > when we're done.
> > 
> > I'm wondering if RANCID has evolved over the last nearly 2 years to include
> > such out of band access to devices, or if it's much of a muchness still?

As I posted previously, I've implemented this, and I now think/hope
it's clean enough to release a patch.  Here's how it works in cloginrc:

   add method testrouter {usercmd}
   add usercmd testrouter {ssh} {-t} {termserver01} {cu -l /dev/tty01 -s 9600}
   add usercmd_chat testrouter {Connected.} {\r}

The patches below to clogin define a new method, "usercmd" (i.e. instead
of "telnet" or "ssh"), which tells clogin to use the exact text supplied
in the "usercmd" directive for that router as the command to spawn.  Note
the way the command line args are delimited, the braces have to be used
to mark off the arguments or the spawn command will fail.

Since whatever out-of-band gizmo you're using to access the router
might need some more interaction to let you get to the router,
the usercmd_chat directive is a list of expect/send pairs - match
something, send something, match the next something, send something,
etc.  This is pretty primitive but it should be enough to get through
conserver, cu, kermit, or whatever you're using as the out-of-band
connector.  In the above case, usercmd_chat is defined to "wait for the
string 'Connected.' and then send a CR".

For Andrew's case above, he might have to do something like:

   add usercmd routeronc1 {ssh} {-t} {-p 12345} {cyclades01}
   add usercmd_chat routeronc1 {Login:} {operator\r} {Password:} {secret\r} {Connected.} {\r}

to get past the authentication he describes, and then send a CR to the router
to get it to display a prompt.

I didn't code anything yet for the situation Andrew describes where he
wants to send an SSH break sequence when he's done.  The attached patch
includes a fix to clogin so that it will hang up if it times out after it's
already sent "exit" to the router - though it wastes a few more seconds
timing out, it is a reliable way to close the connection in my environment.
If it turns out someone needs to have more chat interaction upon exit, I'd
be happy to code it in.

The patch to clogin is attached.  The first chunk may need to be applied
by hand, since one of the surrounding lines is from my S/Key patches.

	-- Ed
-------------- next part --------------
--- rancid-panix-3/libexec/rancid/clogin	2006-05-13 00:38:40.000000000 -0400
+++ rancid-panix-4/libexec/rancid/clogin	2006-05-15 21:00:20.000000000 -0400
@@ -288,7 +288,7 @@
 # Log into the router.
 proc login { router user userpswd passwd enapasswd cmethod cyphertype } {
     global spawn_id in_proc do_command do_script platform
-    global prompt u_prompt p_prompt e_prompt sshcmd
+    global prompt u_prompt p_prompt e_prompt sshcmd usercmd usercmd_chat
 	global otpinuse
     set in_proc 1
     set uprompt_seen 0
@@ -319,6 +319,22 @@
 		send_user "\nError: $sshcmd failed: $reason\n"
 		exit 1
+	} elseif [string match "usercmd" $prog] { # user supplies connect cmd
+		set retval [ catch {eval spawn $usercmd} reason ]
+		if { $retval } {
+		    send_user "\nError: '$usercmd' failed: $reason\n"
+		    exit 1
+		}
+		if { [llength $usercmd_chat] > 0 } {
+			#send_user "\nExecuting usercmd_chat: $usercmd_chat\n"
+			sleep 0.3
+			foreach {i j} $usercmd_chat {
+				expect {
+					-re $i { eval send "\"$j\""}
+					timeout { send "\r"; send_user "\nTimeout in usercmd_chat waiting for -re $i: punting with CR\n"; break }
+				}
+			}
+		}
 	} elseif ![string compare $prog "rsh"] {
 	    if [ catch {spawn rsh -l $user $router} reason ] {
 		send_user "\nError: rsh failed: $reason\n"
@@ -626,7 +642,7 @@
 	-re "\[\n\r]+"				{ exp_continue }
-	timeout					{ return 0 }
+	timeout					{ close; return 0 }
 	eof					{ return 0 }
     set in_proc 0
@@ -752,6 +768,10 @@
     set sshcmd [find sshcmd $router]
     if { "$sshcmd" == "" } { set sshcmd {ssh} }
+    # If user provides a router-specific connection method, use it
+    set usercmd [find usercmd $router]
+    set usercmd_chat [find usercmd_chat $router]
     # Login to the router
     if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype]} {

More information about the Rancid-discuss mailing list