home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.ee.lbl.gov
/
2014.05.ftp.ee.lbl.gov.tar
/
ftp.ee.lbl.gov
/
acld-1.11.tar.gz
/
acld-1.11.tar
/
acld-1.11
/
cisco.expect
< prev
next >
Wrap
Text File
|
2012-02-18
|
32KB
|
1,447 lines
# @(#) $Id: cisco.expect 812 2012-02-18 06:09:03Z leres $ (LBL)
#
# Copyright (c) 2002, 2006, 2007, 2008, 2009, 2010, 2011, 2012
# The Regents of the University of California. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that: (1) source code distributions
# retain the above copyright notice and this paragraph in its entirety, (2)
# distributions including binary code include the above copyright notice and
# this paragraph in its entirety in the documentation or other materials
# provided with the distribution, and (3) all advertising materials mentioning
# features or use of this software display the following acknowledgement:
# ``This product includes software developed by the University of California,
# Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
# the University nor the names of its contributors may be used to endorse
# or promote products derived from this software without specific prior
# written permission.
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
# cisco.expect - acld script for controlling a cisco router
#
#
# Always include an explicit "return" in each procedure:
#
# This will cause an expect error if the procedure is supposed
# to kreturn a value
#
# Always exclude \r\n in negated regex character classes:
#
# Otherwise the regex can match more than one line
#
set timeout 10
match_max 2048
set cprompt "\[^#\r\n]*#"
set currentmode "logout"
set currentacl ""
set f "expect.log"
set logname "/var/log/acld/expect.log"
if [catch {log_file -a $logname} err] {
#send_error "$prog: warning: $err\n"
set logname $f
if [catch {log_file -a $logname} err] {
send_error "warning: $err\n"
#send_error "$prog: warning: $err\n"
}
}
set lastseq 2147483647
# Cleanup if our child dies
trap { wait } SIGCHLD
# Higher level is easier if the prompt doesn't change
proc prompt1 {} {
return "expect>"
}
# Required procedures
proc attr {acl attrlist} {
global isipv6
foreach attr $attrlist {
if { $attr == "ipv6" } {
set isipv6($acl) 1
continue
}
puts "attr-failed -"
puts "unknown attr \"$attr\""
puts "."
return
}
puts "attr"
return
}
proc drop {addr acl seq} {
global logname
if { [string first "/" $addr] > 0 } {
# Network with mask
set addr [prefix2wild $addr]
if {$addr == 1} {
puts "drop-failed -"
puts "Invalid prefix."
puts "."
return
}
aclcmd "drop" $acl $seq "" "deny ip $addr any"
} else {
# Host address
aclcmd "drop" $acl $seq "" "deny ip host $addr any"
}
#Reopen the logfile from time to time
log_file
log_file -a $logname
return
}
proc blockhosthost {addr1 addr2 acl seq} {
aclcmd "blockhosthost" $acl $seq "" "deny ip host $addr1 host $addr2"
return
}
proc dropudpport {port acl seq} {
aclcmd "dropudpport" $acl $seq "" "deny udp any any eq $port"
return
}
proc droptcpport {port acl seq} {
aclcmd "droptcpport" $acl $seq "" "deny tcp any any eq $port"
return
}
proc dropudpdsthostport {addr port acl seq} {
aclcmd "dropudpdsthostport" $acl $seq "" \
"deny udp any host $addr eq $port"
return
}
proc droptcpdsthostport {addr port acl seq} {
aclcmd "droptcpdsthostport" $acl $seq "" \
"deny tcp any host $addr eq $port"
return
}
proc ayt {} {
global cprompt
sendcmd ""
set timeout 10
expect {
-re $cprompt {
# done
}
timeout {
puts "ayt-failed -"
puts "timeout ($timeout seconds)"
puts "."
exit
}
default {
puts "ayt-failed -"
puts "unknown error"
puts "."
exit
}
}
puts "ayt"
return
}
#$acl not used with Cisco sup720-3B when using 'tcam' command
#(tcam command displays match count of ACEs processed by hardware, but no seq#)
#$interface not used when using show ip access-list $acl
proc listacl {acl interface} {
global cprompt
global currentmode
set err [entermode "enable" ""]
if { $err != "" } {
puts "listacl-failed -"
puts "$err"
puts "."
return
}
set ip [acl2ip $acl]
set cmd "show $ip access-list $acl"
sendcmd "$cmd"
#(above command displays match count of ACEs processed by software)
#(below command displays match count of ACEs processed by hardware)
#sendcmd "show tcam interface &interface acl in ip"
set timeout 10
expect {
-re "^$cmd\[\r\n]*\r\n" {
exp_continue
}
-re "(Standard IP|Extended IP|IPv6) access list $acl\[\r\n]*\r\n" {
puts "listacl -"
expect {
-re "^ *(\[^\r\n]*)\[\r\n]*\r\n" {
set str $expect_out(1,string)
printacl $str
exp_continue
}
-re "Connection to.*closed by remote host\." {
puts "$what-failed -"
puts "$expect_out(0,string)"
puts "."
exit
}
-re "Connection to.*closed\." {
puts "$what-failed -"
puts "$expect_out(0,string)"
puts "."
exit
}
-re $cprompt {
# This action must be last
puts "."
return
}
timeout {
puts "listacl-failed -"
puts "timeout ($timeout seconds)"
puts "."
exit
}
default {
puts "listacl-failed -"
puts "reason unknown"
puts "."
exit
}
}
}
-re "^ *(\[^\r\n]*)\[\r\n]*\r\n" {
set str $expect_out(1,string)
puts "listacl-failed -"
puts "unparsed \"$str\""
puts "."
exit
}
-re "Connection to.*closed by remote host\." {
puts "$what-failed -"
puts "$expect_out(0,string)"
puts "."
exit
}
-re "Connection to.*closed\." {
puts "$what-failed -"
puts "$expect_out(0,string)"
puts "."
exit
}
-re $cprompt {
# Empty: the ACL doesn't exist
puts "listacl -"
puts "."
return
}
timeout {
puts "listacl-failed -"
puts "timeout ($timeout seconds)"
puts "."
exit
}
default {
puts "listacl-failed -"
puts "reason unknown"
puts "."
exit
}
}
return
}
# List both IPv4 and IPv6 routes
# XXX there's no easy way to return an error if IPv4 are listed ok
# but IPv6 routes fail
proc listroute {} {
global currentmode
set err [entermode "enable" ""]
if { $err != "" } {
puts "listroute-failed -"
puts "$err"
puts "."
return
}
puts "listroute -"
_listroute ip
_listroute ipv6
puts "."
return
}
proc login {addr cuser cpass1 cpass2 euser epass1 epass2} {
global spawn_id
global cprompt
global currentmode
# Fire up subprocess
set pid [spawn ssh "-2ax" "-o" "stricthostkeychecking=no" $euser@$addr]
# Wait for connect
set timeout 10
expect {
eof {
catch {close} err
# Don't hammer on router if we're misconfigured
sleep 10
puts "login-failed -"
puts "child died (1)"
puts "."
exit
}
timeout {
catch {close} err
puts "login-failed -"
puts "connect timeout ($timeout seconds)"
puts "."
exit
}
"Connection refused" {
catch {close} err
# Don't hammer on router if we're misconfigured
sleep 10
puts "login-failed -"
puts "connection refused"
puts "."
exit
}
"assword: " {
#done
}
default {
#exec kill $pid
catch {close} err
puts "login-failed -"
puts "unknown response: $expect_out(buffer)"
puts "."
#return
exit
}
}
#sendpass for non-autoenable users
#set cprompt "\[^>\r\n]*>"
#if { ![sendpass "connect" $cuser $cpass1 $cpass2] } {
# close
# return
#}
#set currentmode "connect"
#sendcmd "enable"
set cprompt "\[^#\r\n]*#"
if { ![sendpass "enable" $epass1 $epass2] } {
catch {close} err
return
}
sendcmd "terminal length 0"
expect -re $cprompt
set currentmode "enable"
puts "login -"
puts "child ssh pid is $pid"
puts "."
return
}
proc logout {} {
global currentmode
set err [entermode "enable" ""]
if { $err != "" } {
puts "logout-failed -"
puts "$err"
puts "."
#return
exit
}
set currentmode "logout"
sendcmd "logout"
set timeout 10
expect {
-re "(\[^\r\n]*)\[\r\n]*\r\n.*#" {
catch {close} err
puts "logout"
puts "$expect_out(1,string)"
puts "."
return
}
-re "Connection to.*closed by remote host\." {
catch {close} err
puts "logout"
puts "$expect_out(0,string)"
puts "."
exit
}
-re "Connection to.*closed\." {
catch {close} err
puts "logout"
puts "$expect_out(0,string)"
puts "."
exit
}
timeout {
puts "logout-failed -"
puts "timeout ($timeout seconds)"
puts "."
exit
}
default {
puts "logout-failed -"
puts "reason unknown"
puts "."
exit
}
}
return
}
proc nonullzero {addr} {
nullzerocmd "nonullzero" $addr "no"
return
}
#if route already exists, IOS returns normally (no error).
proc nullzero {addr} {
nullzerocmd "nullzero" $addr {}
return
}
proc permitudpdsthostport {addr port acl seq} {
aclcmd "permitudpdsthostport" $acl $seq "" \
"permit udp any host $addr eq $port"
return
}
proc permittcpdsthostport {addr port acl seq} {
aclcmd "permittcpdsthostport" $acl $seq "" "permit tcp any host $addr eq $port"
return
}
#if sequence number doesn't exist, IOS returns normally (no error).
proc restore {addr acl seq} {
aclcmd "restore" $acl $seq "no" ""
return
}
#if sequence number doesn't exist, IOS returns normally (no error).
proc restorehosthost {addr1 addr2 acl seq} {
aclcmd "restorehosthost" $acl $seq "no" ""
return
}
#if sequence number doesn't exist, IOS returns normally (no error).
proc restoreudpport {port acl seq} {
aclcmd "restoreudpport" $acl $seq "no" "deny udp any any eq $port"
return
}
#if sequence number doesn't exist, IOS returns normally (no error).
proc restoretcpport {port acl seq} {
aclcmd "restoretcpport" $acl $seq "no" "deny tcp any any eq $port"
return
}
#if sequence number doesn't exist, IOS returns normally (no error).
proc restoreudpdsthostport {addr port acl seq} {
aclcmd "restoreudpdsthostport" $acl $seq "no" ""
return
}
#if sequence number doesn't exist, IOS returns normally (no error).
proc restoretcpdsthostport {addr port acl seq} {
aclcmd "restoretcpdsthostport" $acl $seq "no" ""
return
}
proc sync {} {
global cprompt
global currentmode
global currentacl
set err [entermode "enable" ""]
if { $err != "" } {
puts "sync-failed -"
puts "$err"
puts "."
return
}
sendcmd "write memory"
set timeout 30
expect {
-re "Building configuration...\[^\r\n]*\r\n" {
#puts "Writing config to NVRAM..."
exp_continue
}
-re "(startup-config file open failed\[^\r\n]*)\[r\n]*\r\n.*#" {
puts "sync-failed -"
puts "$expect_out(1,string)"
return
}
-re $cprompt {
puts "sync"
return
}
timeout {
puts "sync-failed -"
puts "timeout ($timeout seconds)"
puts "exiting"
puts "."
exit
}
default {
puts "sync-failed -"
puts "$expect_out(buffer)"
puts "exiting"
puts "."
exit
}
}
}
proc unpermitudpdsthostport {addr port acl seq} {
aclcmd "unpermitudpdsthostport" $acl $seq "no" ""
return
}
#if sequence number doesn't exist, IOS returns normally (no error).
proc unpermittcpdsthostport {addr port acl seq} {
aclcmd "unpermittcpdsthostport" $acl $seq "no" ""
return
}
# Local procedures
# Returns "ip" or "ipv6" based on the acl name
proc acl2ip {acl} {
global isipv6
if [catch { set ipv6 [set isipv6($acl)] } err] {
set ipv6 0
}
if { $ipv6 } {
set ip "ipv6"
} else {
set ip "ip"
}
return $ip
}
proc aclcmd {what acl seq pre cmd} {
global cprompt
global lastseq
if { $seq != 0 } {
if { $seq > $lastseq } {
puts "$what-failed -"
puts "sequence too large ($seq > $lastseq)"
puts "."
return
}
set ip [acl2ip $acl]
if { $ip == "ip" } {
set cmd "$seq $cmd"
} else {
set cmd "sequence $seq $cmd"
}
}
if { [string length $pre] > 0 } {
set cmd "$pre $cmd"
}
set err [entermode "acl" $acl]
if { $err != "" } {
puts "$what-failed -"
puts "$err"
puts "."
return
}
sendcmd "$cmd"
set timeout 30
expect {
#generic error catcher for cisco
-re "(%\[^\r\n]*)\[\r\n]*\r\n.*#" {
puts "$what-failed -"
puts "$expect_out(1,string)"
puts "."
return
}
-re "Connection to.*closed by remote host\." {
puts "$what-failed -"
puts "$expect_out(0,string)"
puts "."
exit
}
-re "Connection to.*closed\." {
puts "$what-failed -"
puts "$expect_out(0,string)"
puts "."
exit
}
-re $cprompt {
# success
puts "$what"
return
}
timeout {
puts "$what-failed -"
puts "aclcmd: timeout ($timeout seconds)"
puts "."
exit
}
default {
puts "$what-failed -"
puts "aclcmd: unknown problem"
puts "."
exit
}
}
}
proc _listroute {ip} {
global cprompt
set what ""
set src ""
set dst ""
sendcmd "show $ip route"
set timeout 10
# Loop over routes
expect {
-re "^Gateway of last resort is (\[^ \r\n]+) to network (\[^ \r\n]+)\[\r\n]*\r\n" {
# IPv4 (Cisco's are so funny)
set what "S"
set src $expect_out(2,string)
set dst $expect_out(1,string)
printroute $what $src $dst
exp_continue
}
-re "^Codes:\[^\r\n]+\[\r\n]*\r\n" {
exp_continue
}
-re "^show \[^\r\n]+\[\r\n]*\r\n" {
exp_continue
}
-re "^IPv6 Routing Table \[^\r\n]+\[\r\n]*\r\n" {
exp_continue
}
-re "^(\[CS])\[* ] +(\[^ \r\n]+) is directly connected, (\[^\r\n]+)\[\r\n]*\r\n" {
set what $expect_out(1,string)
set src $expect_out(2,string)
set dst {}
printroute $what $src $dst
exp_continue
}
-re "^(\[BCS])\[* ] +(\[^ \r\n]+) \[^ \r\n]+ via (\[^,\r\n]+)\[^\r\n]*\[\r\n]*\r\n" {
set what $expect_out(1,string)
set src $expect_out(2,string)
set dst $expect_out(3,string)
printroute $what $src $dst
exp_continue
}
-re "^(\[BCSL])\[* ] +(\[^ \r\n]+) \[^\r\n]+\[\r\n]*\r\n" {
# IPv6: first line
set what $expect_out(1,string)
set src $expect_out(2,string)
set dst {}
exp_continue
}
-re "^(\[BCSL])\[* ] +(\[^ \r\n]+) \[^\r\n]+\[\r\n]*\r\n" {
# IPv6: first line
# B 2A03:C600::/32 [20/0]
set what $expect_out(1,string)
set src $expect_out(2,string)
exp_continue
}
-re "^(\[BCSL])\[* ] +(\[^\r\n]+)\[\r\n]*\r\n" {
# IPv6: first line
set what $expect_out(1,string)
set src $expect_out(2,string)
exp_continue
}
-re "^ +via (\[^,\r\n]+), \[^\r\n]+\[\r\n]*\r\n" {
# IPv6: second line
set dst $expect_out(1,string)
printroute $what $src $dst
exp_continue
}
-re "^ +via (\[^\r\n]+)\[\r\n]*\r\n" {
# IPv6: second line
set dst $expect_out(1,string)
printroute $what $src $dst
exp_continue
}
-re "^ +(\[^ \r\n]+) is subnetted, \[^\r\n]+\[\r\n]*\r\n" {
# Skip
exp_continue
}
-re "^ +(\[^ \r\n]+) is variably subnetted, \[^\r\n]+\[\r\n]*\r\n" {
# Skip
exp_continue
}
-re "^ +\[^ \r\n]+ - \[^ \r\n]+ \[^\r\n]+\[\r\n]*\r\n" {
exp_continue
}
-re "^ *(\[^\r\n]+)\[\r\n]*\r\n" {
puts "# junk $expect_out(1,string)"
exp_continue
}
-re $cprompt {
# This action must be last
# done
return
}
timeout {
puts "# timeout ($timeout seconds)"
}
}
puts "."
return
}
proc printacl {str} {
# Break into a list
set av [split $str " "]
set an [llength $av]
# XXX gag me: remove empty elements (caused by multiple blanks)
set n 0
while { $n < $an } {
if { [lindex $av $n] == "" } {
set av [concat [lrange $av 0 [expr $n - 1]] \
[lrange $av [expr $n + 1] [expr $an - 1]]]
set an [expr $an - 1]
} else {
incr n
}
#remove carraige return from last element...
if { $n == [expr $an - 1] } {
set lastav [lindex $av $n]
set newav [string trimright $lastav " \r\n"]
lset av $n $newav
}
}
if { $an < 5 } {
error "# printacl: not enough args \"$str\""
}
if { [lindex $av [expr $an - 2]] == "sequence" } {
# deny ipv6 host 2001:400:610:102::CB any sequence 1002
# This is the "new" ipv6 way
set seq [lindex $av [expr $an - 1]]
# Remove sequence from argument vector
set an [expr $an - 2]
set av [lrange $av 0 [expr $an - 1]]
} elseif { [lindex $av 0] == "seq" } {
# This is the old extended access-list way
set seq [lindex $av 1]
# Remove sequence from argument vector
set av [lrange $av 2 $an]
set an [expr $an - 2]
} else {
# 60090 deny tcp any host 198.128.24.1 eq 22 (319 matches)
# This is the normal extended access-list way
set seq [lindex $av 0]
# Remove sequence from argument vector
set av [lrange $av 1 $an]
set an [expr $an - 1]
}
set avn [lindex $av [expr $an - 1]]
if { $avn == "matches)" || $avn == "match)" } {
set count [lindex $av [expr $an - 2]]
set count [string trimleft $count "("]
# Remove from argument vector
set an [expr $an - 2]
set av [lrange $av 0 $an]
} else {
set count 0
}
set which [lindex $av 0]
if { $which == "deny" } {
set which "block"
} elseif { $which != "permit" } {
error "# printacl: can't find permit/deny \"$av\""
}
set proto [lindex $av 1]
set what "unknown # $str"
set append ""
if { $proto == "ip" || $proto == "ipv6" || $proto == "icmp" } {
if { $proto == "icmp" } {
set protostr $proto
} else {
set protostr ""
}
if { $an == 5 &&
[lindex $av 2] == "host" &&
[lindex $av 4] == "any" } {
# "permithost/blockhost"
# "permitimcphost/blockicmphost"
# deny ip host 10.0.0.1 any
# 0 1 2 3 4
set what "[set which][set protostr]host"
append append [lindex $av 3]
} elseif { $an == 6 &&
[lindex $av 2] == "host" &&
[lindex $av 4] == "host" } {
# "permithosthost/blockhosthost"
# "permiticmphosthost/blockicmphosthost"
# deny ip host 1.2.3.4 host 4.5.6.7
# 0 1 2 3 4 5
set what "[set which][set protostr]hosthost"
append append "[lindex $av 3] [lindex $av 5]"
} elseif { $an == 5 &&
[split [lindex $av 3] "."] > 0 &&
[lindex $av 4] == "any" } {
set wild [lindex $av 3]
set wild [wild2width $wild]
# "permitnet/blocknet"
# "permiticmpnet/blockicmpnet"
# permit ip 10.0.0.0 0.0.0.225 any
# 0 1 2 3 4
set what "[set which][set protostr]net"
append append [lindex $av 2]$wild
} elseif { $an == 5 &&
[lrange $av 2 3] == "any host" } {
# "permitdsthost/blockdsthost"
# "permiticmpdsthost/blockicmpdsthost"
# permit icmp any host 10.0.0.1
# 0 1 2 3 4
set what "$which[set protostr]dsthost"
append append "[lindex $av 4]"
} elseif { $an == 5 &&
[split [lindex $av 4] "."] > 0 &&
[lindex $av 2] == "any"} {
set wild [lindex $av 4]
set wild [wild2width $wild]
# "permitdstnet/blockdstnet"
# "permiticmpdstnet/blockicmpdstnet"
# "show ip accounting" style
# (net and mask width one word)
# permit ip any 10.0.0.0 0.255.255.255
# 0 1 2 3 4
set what "[set which][set protostr]dstnet"
append append [lindex $av 3]$wild
} elseif { $an == 4 && [lrange $av 2 3] == "any any" } {
# "permitany/blockany"
# "permiticmpany/blockicmpany"
# permit ip any any
# 0 1 2 3
set what "[set which][set protostr]any"
} elseif { $an == 6 &&
[split [lindex $av 3] "."] > 0 &&
[lindex $av 4] == "host" } {
set wild [lindex $av 3]
set wild [wild2width $wild]
# "permitnethost/blocknethost"
# "permiticmpnethost/blockicmpnethost"
# permit ip 10.0.0.0 0.0.0.255 host 10.1.2.3
# 0 1 2 3 4 5
set what "$which[set protostr]nethost"
append append "[lindex $av 2]$wild [lindex $av 5]"
}
} elseif { $proto == "udp" || $proto == "tcp" } {
if { $an == 6 &&
[lrange $av 2 4] == "any any eq" } {
# "permitudpport/blockudpport"
# "permittcpport/blocktcpport"
# deny udp any any eq 666
# 0 1 2 3 4 5
set port [lindex $av 5]
if {[regexp {[a-z]} $port result]} {
set port [name2num $proto $port]
}
set what "$which[set proto]port"
#append append [lindex $av 5]
append append $port
} elseif { $an == 7 &&
[lindex $av 2] == "host" &&
[lrange $av 4 5] == "any eq" } {
# "permitudphostport/blockudphostport"
# "permittcphostport/blocktcphostport"
# permit udp host 10.0.0.1 any eq 666
# 0 1 2 3 4 5 6
set port [lindex $av 6]
if {[regexp {[a-z]} $port result]} {
set port [name2num $proto $port]
}
set what "$which[set proto]hostport"
append append "[lindex $av 3] $port"
} elseif { $an == 7 &&
[lrange $av 2 3] == "any host" &&
[lindex $av 5] == "eq" } {
# "permitudpdsthostport/blockudpdsthostport"
# "permittcpdsthostport/blocktcpdsthostport"
# permit udp any host 10.0.0.1 eq 666
# 0 1 2 3 4 5 6
set port [lindex $av 6]
if {[regexp {[a-z]} $port result]} {
set port [name2num $proto $port]
}
set what "$which[set proto]dsthostport"
append append "[lindex $av 3] $port"
} elseif { $an == 7 &&
[lindex $av 2] == "host" &&
[lindex $av 4] == "eq" &&
[lindex $av 6] == "any" } {
# "permitudphostsrcport/blockudphostsrcport"
# "permittcphostsrcport/blocktcphostsrcport"
# permit udp host 10.0.0.1 eq 666 any
# 0 1 2 3 4 5 6
set port [lindex $av 5]
if {[regexp {[a-z]} $port result]} {
set port [name2num $proto $port]
}
set what "$which[set proto]hostsrcport"
append append "[lindex $av 3] $port"
} elseif { $an == 8 &&
[lindex $av 2] == "host" &&
[lindex $av 4] == "host" &&
[lindex $av 6] == "eq" } {
# "permitudphostpairdstport/blockudphostpairdstport"
# "permittcphostpairdstport/blocktcphostpairdstport"
# permit udp host 10.0.0.1 host 10.0.0.2 eq 666
# 0 1 2 3 4 5 6 7
set port [lindex $av 7]
if {[regexp {[a-z]} $port result]} {
set port [name2num $proto $port]
}
set what "$which[set proto]hostpairdstport"
append append "[lindex $av 3] [lindex $av 5] $port"
} elseif { $an == 5 &&
[lrange $av 2 3] == "any host" } {
# "permitudpdsthost/blockudpdsthost"
# "permittcpdsthost/blocktcpdsthost"
# permit udp any host 10.0.0.1
# 0 1 2 3 4
set what "$which[set proto]dsthost"
append append "[lindex $av 4]"
}
}
set msg "$seq $count $what"
if { $append != "" } {
append msg " $append"
}
puts $msg
return
}
proc printroute {what src dst} {
# Strip trailing /32 from host routes
if { [string first "." $src] > 0 } {
set w "32"
} else {
set w "128"
}
set i [string first "/$w" $src]
if { $i > 1 } {
set src [string range $src 0 [expr $i - 1]]
}
if { $what == "C" || $what == "L" } {
# interface
puts "I $src"
} elseif { $what == "O" || $what == "B" || $what == "R" } {
# dynamic
puts "D $src $dst"
} elseif { $what == "S" } {
if { $dst == "Nu 0" || $dst == "Null0" } {
# null zero
puts "N $src"
} else {
# static
puts "S $src $dst"
}
} else {
puts "# unknown $what $src $dst"
}
return
}
proc nullzerocmd {what addr pre} {
global cprompt
set err [entermode "config" {}]
if { $err != "" } {
puts "$what-failed -"
puts "$err"
puts "."
return
}
if { [string first "." $addr] > 0 } {
set ip "ip"
} else {
set ip "ipv6"
}
if { [string first "/" $addr] > 0 } {
# Network with mask
set addr [prefix2mask $addr]
if {$addr == 1} {
puts "nullzerocmd-failed -"
puts "Invalid prefix."
puts "."
return
}
set cmd "$ip route $addr null 0"
} elseif { $ip == "ip" } {
# IPv4 host address
set cmd "ip route $addr 255.255.255.255 null 0"
} else {
# IPv6 host address
set cmd "ipv6 route $addr/128 null 0"
}
if { $pre != "" } {
set cmd "$pre $cmd"
}
sendcmd $cmd
set timeout 10
expect {
#generic error catcher for cisco
-re "(%\[^\r\n]*)\[\r\n]*\r\n.*#" {
puts "$what-failed -"
puts "$expect_out(1,string)"
puts "."
return
}
-re "Connection to.*closed by remote host\." {
puts "$what-failed -"
puts "$expect_out(0,string)"
puts "."
exit
}
-re "Connection to.*closed\." {
puts "$what-failed -"
puts "$expect_out(0,string)"
puts "."
exit
}
-re $cprompt {
# This action must be last
# success
puts "$what"
return
}
timeout {
puts "$what-failed -"
puts "nullzerocmd: timeout ($timeout seconds)"
puts "."
exit
}
default {
puts "$what-failed -"
puts "nullzerocmd: unknown problem"
puts "."
return
}
}
return
}
proc sendcmd {cmd} {
global spawn_id
if [catch {send -- "$cmd\r"} err] {
puts "sendcmd: $err"
# exit so acld will start a fresh expect session
exit
}
return 1
}
# $user not used with the cisco
proc sendpass {what pass1 pass2} {
global spawn_id
global cprompt
# Send first password
sendcmd "$pass1"
set timeout 10
set which "first"
expect {
timeout {
puts "login-failed -"
puts "sendpass: timeout ($timeout seconds)"
puts "."
return 0
}
"Received disconnect from " {
puts "login-failed -"
puts "device timed out while waiting for password"
puts "."
return 0
}
"Password:" {
if { $which == "first" } {
set which "second"
sendcmd "$pass2"
exp_continue
}
}
-re $cprompt {
return 1
}
default {
puts "login-failed -"
puts "can't get here"
puts "."
return 0
}
}
}
# Modes we currently know about:
#
# enable
# config
# acl
#
# This table tells entermode how to get from one mode to another
#
set modemoves(enable,enable) { }
set modemoves(enable,config) { "config t" }
set modemoves(enable,acl) { "config t" "acl" }
set modemoves(config,enable) { "exit" }
set modemoves(config,config) { }
set modemoves(config,acl) { "acl" }
set modemoves(acl,enable) { "exit" "exit" }
set modemoves(acl,config) { "exit" }
set modemoves(acl,acl) { "acl" }
proc entermode {mode acl} {
global cprompt
global currentmode
global currentacl
global modemoves
set timeout 10
if [catch {set moves $modemoves($currentmode,$mode)} err] {
puts "entermode: $err"
# exit so acld will start a fresh expect session
exit
}
set n [llength $moves]
if { $n == 0 } {
return ""
}
set ip [acl2ip $acl]
set errstr ""
for { set i 0 } { $i < $n } { incr i } {
set move [lindex $moves $i]
if { $move != "acl" } {
set cmd "$move"
} elseif { $currentmode != "acl" || $currentacl != $acl } {
if { $ip == "ip" } {
set cmd "ip access-list extended $acl"
} else {
set cmd "ipv6 access-list $acl"
}
} else {
# already there
continue
}
sendcmd "$cmd"
expect {
#generic error catcher for cisco
-re "(%\[^\r\n]*)\[\r\n]*\r\n.*#" {
puts "entermode failed -"
puts "$expect_out(1,string)"
puts "."
return
}
#This error not supported on cisco (but we need an equivalent)
-re "(% Error: IPv6 Access-list not supported on this CAM profile\.)\[\r\n]*\r\n" {
set errstr "$expect_out(1,string)"
set currentmode "config"
exp_continue
}
-re "Connection to.*closed by remote host\." {
puts "entermode failed -"
puts "$expect_out(0,string)"
puts "."
exit
}
-re "Connection to.*closed\." {
puts "entermode failed -"
puts "$expect_out(0,string)
puts "."
exit
}
-re $cprompt {
# This action must be last
# done
}
timeout {
puts "entermode: timeout ($timeout seconds)"
exit
}
}
# Bail at the first sign of trouble
if { $errstr != "" } {
break
}
# Keep track of current mode in case we're making more than one
if { $move == "config t" } {
set currentmode "config"
} else {
set currentmode $mode
}
if { $move == "acl" } {
set currentacl $acl
}
}
return $errstr
}
# Calculate ip address with subnet mask given an ip address with
# subnet mask prefix (A.B.C.D/xx). Used by proc 'nullzerocmd'
proc prefix2mask {addr} {
set iplist [split $addr "/"]
set ipaddr [lindex $iplist 0]
set prefix [lindex $iplist 1]
set numOctet 0
set mask ""
if { ($prefix < 0) || ($prefix > 32) } {
#puts "invalid prefix ($prefix)."
return 1
}
set fullOct [expr $prefix / 8]
set partOct [expr $prefix % 8]
while {$fullOct > 0} {
append mask 255
incr fullOct -1
if {$numOctet < 3} {
append mask "."
}
incr numOctet
}
if {$partOct > 0} {
set num 0
for {set j $partOct} {$j > 0} {incr j -1} {
set bit [expr 8-$j]
set num [expr pow(2, $bit) + $num]
}
#num became float after doing math,
#need to cast it back to an int
set num [expr int($num)]
append mask $num
incr numOctet
if {$numOctet <= 3} {
append mask "."
}
}
while {$numOctet <= 3} {
append mask "0"
incr numOctet
if {$numOctet <= 3} {
append mask "."
}
}
set result "$ipaddr $mask"
return $result
}
# Calculate Cisco wildcard given a prefix (e.g. /24)
# Used by proc 'drop'
proc prefix2wild {addr} {
set iplist [split $addr "/"]
set ipaddr [lindex $iplist 0]
set prefix [lindex $iplist 1]
set numOctet 0
set wild ""
if { ($prefix < 1) || ($prefix > 32) } {
#puts "invalid prefix ($prefix)."
return 1
}
set emptyOct [expr $prefix / 8]
set partOct [expr $prefix % 8]
while {$emptyOct > 0} {
append wild 0
incr emptyOct -1
if {$numOctet < 3} {
append wild "."
}
incr numOctet
}
if {$partOct > 0} {
set num 0
for {set j $partOct} {$j > 0} {incr j -1} {
set bit [expr 8-$j]
set num [expr pow(2, $bit) + $num]
}
set num [expr 255 - $num]
#num became float after doing math,
#so need to cast it back to an int
set num [expr int($num)]
append wild $num
incr numOctet
if {$numOctet <= 3} {
append wild "."
}
}
while {$numOctet <= 3} {
append wild "255"
incr numOctet
if {$numOctet <= 3} {
append wild "."
}
}
set result "$ipaddr $wild"
return $result
}
# Calculate mask width (number of subnet mask bits) given a cisco style "wildcard"
# Used by proc 'printacl'
proc wild2width {wild} {
set av [split $wild "."]
set an [llength $av]
if { $an != 4 } {
error "# wild2width: wrong number of octets ($an != 4)"
}
set width 0
for { set i [expr $an - 1] } { $i >= 0 } { incr i -1} {
set octet [lindex $av $i]
while {$octet > 0} {
incr width
set octet [expr $octet / 2]
}
}
set width [expr 32 - $width]
return "/$width"
}
#The following arrays are used by proc 'name2num' (below)...
#TCP
set tcp(bgp) 179
set tcp(chargen) 19
set tcp(cmd) 514
set tcp(daytime) 13
set tcp(discard) 9
set tcp(domain) 53
set tcp(echo) 7
set tcp(exec) 512
set tcp(finger) 79
set tcp(ftp) 21
set tcp(ftp-data) 20
set tcp(gopher) 70
set tcp(hostname) 101
set tcp(ident) 113
set tcp(irc) 194
set tcp(klogin) 543
set tcp(kshell) 544
set tcp(login) 513
set tcp(lpd) 515
set tcp(nntp) 119
set tcp(pim-auto-rp) 496
set tcp(pop2) 109
set tcp(pop3) 110
set tcp(smtp) 25
set tcp(sunrpc) 111
set tcp(tacacs) 49
set tcp(talk) 517
set tcp(telnet) 23
set tcp(uucp) 540
set tcp(whois) 43
set tcp(www) 80
#UDP
set udp(biff) 512
set udp(bootpc) 68
set udp(bootps) 67
set udp(discard) 9
set udp(dnsix) 195
set udp(domain) 53
set udp(echo) 7
set udp(isakmp) 500
set udp(mobile-ip) 434
set udp(nameserver) 42
set udp(netbios-dgm) 138
set udp(netbios-ns) 137
set udp(netbios-ss) 139
set udp(non500-isakmp) 4500
set udp(ntp) 123
set udp(pim-auto-rp) 496
set udp(rip) 520
set udp(snmp) 161
set udp(snmptrap) 162
set udp(sunrpc) 111
set udp(syslog) 514
set udp(tacacs) 49
set udp(talk) 517
set udp(tftp) 69
set udp(time) 37
set udp(who) 513
set udp(xdmcp) 177
# Convert user-friendly port name to port number
# Used by 'printacl'
proc name2num {proto name} {
global tcp
global udp
set portnum "unknown"
if { $proto == "tcp" } {
set portnum $tcp($name)
} elseif { $proto == "udp" } {
set portnum $udp($name)
}
#puts "leaving proc name2num..."
#puts "return value is $portnum"
return $portnum
}
# These are required to be at the end
log_user 0
interpreter