1. # nf_aliasExec.tcl --
  2. #
  3. # Sample Tcl script containing multiple procedures, call the script from
  4. # alias exec commands or from within the Tcl shell.
  5. # !Do not use with the 'scripting tcl init [location/file.tcl]' global
  6. # configuration command and or call with 'tclsh file procedure' as well as
  7. # using alias exec commands, doing so will cause procedures to be ran twice
  8. # when called with tclsh.
  9. # To use with the 'scripting tcl init...' command remove the control script
  10. # section at the bottom and save the file with another name.
  11. #
  12. #
  13. # Copyright (C) 2009 Nigel Franklin.
  14. #
  15. # This program is free software: you can redistribute it and/or modify
  16. # it under the terms of the GNU General Public License as published by
  17. # the Free Software Foundation, either version 3 of the License,
  18. # or any later version.
  19. #
  20. # This program is distributed in the hope that it will be useful,
  21. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. # GNU General Public License for more details.
  24. #
  25. # You should have received a copy of the GNU General Public License
  26. # along with this program. If not, see http://www.gnu.org/licenses/.
  27. #
  28. #
  29. #
  30. # Revision # : 1.0
  31. # Last Revised : May 29, 2009
  32. # Author : Nigel Franklin, www.nigelfranklin.co.uk
  33. # Router Requirements :
  34. # None
  35. #
  36. # Cisco Products tested : 1801, 1841
  37. # Cisco IOS versions tested : 12.4(11)
  38. #
  39. # Examples:
  40. # alias exec pings tclsh flash:/tcl/nf_aliasExec.tcl pings {3 47 1 Dialer0 0 1 1 {8.8.4.4 8.8.4.4}}
  41. # proc pings {repeat size timeout source data validate DF {iplist}}
  42. # proc pingsD: Calls pings with a default list of fields set in the proc
  43. # if pings is called with no fields.
  44. #
  45. # alias exec GetOne tclsh flash:/tcl/nf_aliasExec.tcl snmpGetOne {1.3.6.1.2.1.1.5.0 1.3.6.1.2.1.1.6.0 1.3.6.1.2.1.1.3.0}
  46. # proc snmpGetOne {oidList}
  47. #
  48. # alias exec ftp tclsh flash:/tcl/nf_aliasExec.tcl ftp filename
  49. # proc ftp filename arg
  50.  
  51.  
  52. #***************
  53. # ftp --
  54. #
  55. # Copys via FTP a file to the routers flash, automatically
  56. # overwriting existing EEM Policy.
  57. # Primarily configured for Tcl and EEM Tcl script testing.
  58. #
  59. # Arguments:
  60. # filename (required) name of file to be copied, will also be save name
  61. # If no extension is given .tcl is assumed and added.
  62. # args (optional) if e the file is treated as a EEM Tcl Script, a
  63. # new folder source is defined, after upload the script name
  64. # is un/re registered as a global config event manager policy.
  65. #
  66. # Assumption:
  67. # FTP/Flash folder structure assumed as;
  68. # root/tcl for tcl files
  69. # root/tcl/eem for EEM Tcl scripts
  70. # FTP connection variables need setting.
  71. #
  72. # Results:
  73. # File copied to router flash, if EEM script event manager policy renewed.
  74. proc ftp {filename args} {
  75. #defaults
  76. set ftpUser cisco
  77. set ftpPass cisco
  78. set ftpServer 192.168.1.2
  79. set routerDest flash:
  80. set folder "/tcl/"
  81. set eemScript 0
  82. if {![string match *.??? $filename]} {
  83. set filename "$filename.tcl"
  84. }
  85. switch $args {
  86. e {
  87. set eemScript 1
  88. set folder "/tcl/eem/"
  89. }
  90. }
  91.  
  92. exec [typeahead "\ny\n"]
  93. exec [copy ftp://$ftpUser:$ftpPass@$ftpServer$folder$filename $routerDest$folder$filename]
  94. if {$eemScript} {
  95. #un/re register event policy
  96. ios_config "no event manager policy $filename type user" "end"
  97. ios_config "event manager policy $filename type user" "end"
  98. }
  99. }
  100.  
  101.  
  102.  
  103. #***************
  104. # pings --
  105. #
  106. # Runs cisco ping with shortcut commands.
  107. # Counts number of none '.' responses and reports, also counts max number
  108. # of consecutive dropped packets.
  109. #
  110. # Arguments:
  111. # {repeat size timeout source data validate DF {iplist}}
  112. # repeat, size, timeout -> Integers
  113. # source -> the named interface to send the pings from.
  114. # data -> a valid data pattern [0(default)|0000|FFFF|AAAA|rotate|...]
  115. # validate (reply), DF (Set DF bit in IP header) -> [0|1] (meaning no|yes)
  116. # iplist -> A Tcl list of IP addresses.
  117. #
  118. # Example:
  119. # pings {repeat size timeout source data validate DF iplist}
  120. # pings 20 56 1 Dialer0 0 0 1 {8.8.8.8 8.8.4.4}
  121. #
  122. # Results:
  123. # Ping ran and results shown
  124. #http://www.cisco.com/en/US/tech/tk365/technologies_tech_note09186a0080093f22.shtml
  125. proc pings {repeat size timeout source data validate DF iplist} {
  126.  
  127. if {$repeat != 0 } {lappend command repeat $repeat}
  128. if {$size != 0 } {lappend command size $size}
  129. if {$timeout != 0 } {lappend command timeout $timeout}
  130. if {$source != 0 } {
  131. lappend command source $source
  132. lappend note "From interface $source, "
  133. }
  134. if {$data != 0 } {lappend command data $data}
  135. if {$validate != 0 } {
  136. lappend command validate
  137. lappend note "Reply data validated, "
  138. }
  139. if {$DF != 0 } {
  140. lappend command DF
  141. lappend note "DF bit set in IP header."
  142. }
  143. foreach ip $iplist {
  144. puts "\n"
  145. set result [exec ping ip $ip $command]
  146. if [string match "*%*" $result] {
  147. regsub {^..} $result "" result
  148. puts "Cannot ping $ip, error was: $result"
  149. } else {
  150. set resultRespAll [regexp -all -line -inline {^[UQM\u003F\u0026!\.]+} $result]
  151. foreach packetResp {U Q M \\u003F \\u0026 \\.} {
  152. set packetRespCount($packetResp) [regexp -all $packetResp $resultRespAll]
  153. }
  154. set count 0
  155. set max 0
  156.  
  157. for {set x 0} {$x<[llength $resultRespAll]} {incr x} {
  158. for {set y 0} {$y<[llength [split [lindex $resultRespAll $x] {}]]} {incr y} {
  159. if {[lindex [split [lindex $resultRespAll $x] {}] $y] == "."} {
  160. incr count
  161. if {$count > $max} {set max $count}
  162. } elseif {[lindex [split [lindex $resultRespAll $x] {}] $y] == "!"} {
  163. set count 0
  164. }
  165. }
  166. }
  167. set result [split $result "\n"]
  168. puts "[lindex $result 2]"
  169. puts " [join $note]"
  170.  
  171. if {$max != 0} {
  172. puts " Max timed out packets in a row: $max"
  173. }
  174. puts "[lindex $result [expr ([llength $result] - 1)]]"
  175. foreach name [lsort [array names packetRespCount]] {
  176. if {$packetRespCount($name) != 0} {
  177. set nameDecode [string map -nocase {
  178. "\\u003F" "Lifetime exceeded: "
  179. "\\u0026" "Unknown type: "
  180. "\\." "Timed out: "
  181. "U" "Destination unreachable: "
  182. "M" "Could not fragment: "
  183. "Q" "Destination too busy: "
  184. } $name]
  185. if {![string match "Timed out: " $nameDecode]} {lappend drops ", $nameDecode$packetRespCount($name)"}
  186. }
  187. }
  188. if {[info exists drops]} {
  189. puts " Number of dropped packets by type [join $drops]"
  190. unset drops
  191. }
  192. }
  193. }
  194. }
  195. #***
  196. proc pingsD {} {
  197. puts "pings 50 56 1 Dialer0 0 0 1 {8.8.8.8 8.8.4.4}\n"
  198. pings 50 56 1 Dialer0 0 0 1 {8.8.8.8 8.8.4.4}
  199. }
  200.  
  201.  
  202. #***************
  203. # snmpGetOne --
  204. #
  205. # Gets one or more snmp entries via the snmp_getone command.
  206. #
  207. # Arguments:
  208. # oidList (required) list of one or more OID's
  209. #
  210. # Results:
  211. # list of snmp values returned
  212. proc snmpGetOne {oidList} {
  213. set communityStr tcl
  214. set oidResult [list]
  215. #set oidList [join $oidList]
  216. foreach oid $oidList {
  217. set snmpResult [snmp_getone $communityStr $oid]
  218. if [string match "*snmp error*" $snmpResult] {
  219. regexp {text='(.*)'} $snmpResult regexAll bRefValue
  220. lappend oidResult "Error: $bRefValue"
  221. } elseif [string match "*NO_SUCH_I*" $snmpResult] {
  222. regexp {val='(.*)'} $snmpResult regexExp bRefVal
  223. lappend oidResult "Error: $bRefVal"
  224. } else {
  225. regexp {val='(.*)'} $snmpResult regexExp bRefVal
  226. lappend oidResult $bRefVal
  227. }
  228. }
  229. return $oidResult
  230. }
  231.  
  232.  
  233. #***************
  234. # syslog --
  235. #
  236. # writes message to syslog
  237. #
  238. # Arguments:
  239. # scriptName (required) can be {}, Name of script calling procedure.
  240. # msg (required) message to be written
  241. #
  242. # Results:
  243. # New syslog entry created
  244. proc syslog {scriptName msg} {
  245. set Syslog [open "syslog: " w+]
  246. puts $Syslog "%$scriptName-6-ScriptMsg: $msg"
  247. close $Syslog
  248. }
  249.  
  250.  
  251. # ############################################
  252. #Script control.
  253. #Remove this section and save as a different file if you want to use with \
  254. scripting tcl init
  255.  
  256.  
  257. if {(![info exists argv0]) || ($argc == 0)} {
  258. #?
  259. } elseif {[string match pings [lindex $argv 0]]} {
  260. if {[llength [lindex $argv 1]] != 8} {
  261. puts "This version of pings requires 8 variables, \
  262. 'repeat size timeout source data validate DF iplist. \
  263. alias exec pings tclsh flash:/tcl/aliasExec.tcl pings {3 47 1 Dialer0 0 1 1 {8.8.4.4 8.8.4.4}}
  264. \nRunning defaults pingsD"
  265. pingsD
  266. } else {
  267. puts "Running Ping: [join $argv]"
  268. eval [join $argv]
  269. }
  270. } elseif {[string match syslog [lindex $argv 0]]} {
  271. if {[llength [lindex $argv 1]] != 2} {
  272. puts "This version of nf_syslog requires 2 variables, \
  273. 'scriptName message'."
  274. } else {
  275. puts "nf_syslog: [join $argv]"
  276. eval [join $argv]
  277. }
  278. } elseif {[string match ftp [lindex $argv 0]]} {
  279. if {[llength $argv] <= 1} {
  280. puts -nonewline "Enter file to upload and arg 'e' if required, eg 'ciscoInit': "
  281. flush stdout
  282. gets stdin args_
  283. ftp $args_
  284. } else {
  285. eval [join $argv]
  286. }
  287. } elseif {[string match snmpGetOne [lindex $argv 0]]} {
  288. if {[llength $argv] != 2} {
  289. puts "snmpGetOne requires a single list of OID's to be provided, {1.3.6.1.2.1.1.5.0 1.3.6.1.2.1.1.6.0 1.3.6.1.2.1.1.3.0}"
  290. puts -nonewline "Enter a {list} of OID's: "
  291. flush stdout
  292. gets stdin oidList
  293. snmpGetOne $oidList
  294. } else {
  295. puts "snmpGetOne: [lindex $argv 1]"
  296. puts "[snmpGetOne [lindex $argv 1]]"
  297. }
  298. } else {
  299. puts "Procedure not found, available procedures are: [info procs]"
  300. }