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 / force10-telnet.expect < prev    next >
Text File  |  2012-02-17  |  30KB  |  1,376 lines

  1. # @(#) $Id: force10-telnet.expect 811 2012-02-18 04:50:40Z leres $ (LBL)
  2. #
  3. #  Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012
  4. #    The Regents of the University of California.  All rights reserved.
  5. #
  6. #  Redistribution and use in source and binary forms, with or without
  7. #  modification, are permitted provided that: (1) source code distributions
  8. #  retain the above copyright notice and this paragraph in its entirety, (2)
  9. #  distributions including binary code include the above copyright notice and
  10. #  this paragraph in its entirety in the documentation or other materials
  11. #  provided with the distribution, and (3) all advertising materials mentioning
  12. #  features or use of this software display the following acknowledgement:
  13. #  ``This product includes software developed by the University of California,
  14. #  Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
  15. #  the University nor the names of its contributors may be used to endorse
  16. #  or promote products derived from this software without specific prior
  17. #  written permission.
  18. #  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  19. #  WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  20. #  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  21. #
  22. # force10.expect - acld script for controlling a force 10 router (using telnet)
  23. #
  24.  
  25. #
  26. # Always include an explicit "return" in each procedure:
  27. #
  28. #    This will cause an expect error if the procedure is supposed
  29. #    to kreturn a value
  30. #
  31. # Always exclude \r\n in negated regex character classes:
  32. #
  33. #    Otherwise the regex can match more than one line
  34. #
  35.  
  36. set timeout 10
  37. match_max 2048
  38. set cprompt "\[^#\r\n]*#"
  39. set currentmode "logout"
  40. set currentacl ""
  41. set f "expect.log"
  42. set logname "/var/log/acld/expect.log"
  43. if [catch {log_file -a $logname} err] {
  44.     #send_error "$prog: warning: $err\n"
  45.     set logname $f
  46.     if [catch {log_file -a $logname} err] {
  47.         #send_error "$prog: warning: $err\n"
  48.     }
  49. }
  50.  
  51. set lastseq 65535
  52.  
  53. # Cleanup if our child dies
  54. trap { wait } SIGCHLD
  55.  
  56. # Higher level is easier if the prompt doesn't change
  57. proc prompt1 {} {
  58.     return "expect>"
  59. }
  60.  
  61. # Required procedures
  62.  
  63. proc attr {acl attrlist} {
  64.     global isipv6
  65.  
  66.     foreach attr $attrlist {
  67.         if { $attr == "ipv6" } {
  68.             set isipv6($acl) 1
  69.             continue
  70.         }
  71.         puts "attr-failed -"
  72.         puts "unknown attr \"$attr\""
  73.         puts "."
  74.         return
  75.     }
  76.     puts "attr"
  77.     return
  78. }
  79.  
  80. proc drop {addr acl seq} {
  81.     global logname
  82.  
  83.     set ip [acl2ip $acl]
  84.     if { [string first "/" $addr] > 0 } {
  85.         # Network with mask
  86.         aclcmd "drop" $acl $seq "" "deny $ip $addr any"
  87.     } else {
  88.         # Host address
  89.         aclcmd "drop" $acl $seq "" "deny $ip host $addr any"
  90.     }
  91.  
  92.     # Reopen the logfile from time to time
  93.     log_file
  94.     log_file -a $logname
  95.     return
  96. }
  97.  
  98. proc blockhosthost {addr1 addr2 acl seq} {
  99.  
  100.     set ip [acl2ip $acl]
  101.  
  102.     aclcmd "blockhosthost" $acl $seq "" "deny $ip host $addr1 host $addr2"
  103.     return
  104. }
  105.  
  106. proc dropudpport {port acl seq} {
  107.  
  108.     aclcmd "dropudpport" $acl $seq "" "deny udp any any eq $port"
  109.     return
  110. }
  111.  
  112. proc droptcpport {port acl seq} {
  113.  
  114.     aclcmd "droptcpport" $acl $seq "" "deny tcp any any eq $port"
  115.     return
  116. }
  117.  
  118. proc droptcpdsthostport {addr port acl seq} {
  119.  
  120.     aclcmd "droptcpdsthostport" $acl $seq "" \
  121.         "deny tcp any host $addr eq $port"
  122.     return
  123. }
  124.  
  125. proc ayt {} {
  126.     global cprompt
  127.  
  128.     sendcmd ""
  129.     set timeout 10
  130.     expect {
  131.         "Connection closed by foreign host" {
  132.             puts "ayt-failed -"
  133.             puts "telnet session ended"
  134.             puts "."
  135.  
  136.             # exit so acld will start a fresh expect session
  137.             exit
  138.         }
  139.         -re $cprompt {
  140.             # done
  141.         }
  142.         timeout {
  143.             puts "ayt-failed -"
  144.             puts "timeout ($timeout seconds)"
  145.             puts "."
  146.  
  147.             # exit so acld will start a fresh expect session
  148.             exit
  149.         }
  150.     }
  151.     puts "ayt"
  152.     return
  153. }
  154.  
  155. # Try the "show ip accounting" version first (to get counts)
  156. proc listacl {acl interface} {
  157.     global cprompt
  158.     global currentmode
  159.  
  160.     set err [entermode "enable" ""]
  161.     if { $err != "" } {
  162.         puts "listacl-failed -"
  163.         puts "$err"
  164.         puts "."
  165.         return
  166.     }
  167.  
  168.     set ip [acl2ip $acl]
  169.  
  170.     sendcmd "show $ip accounting access-list $acl interface $interface"
  171.  
  172.     set timeout 10
  173.     expect {
  174.         -re "Extended \[^\r\n]+ IP access list $acl on \[^\r\n]+\[\r\n]*\r\n" {
  175.             puts "listacl -"
  176.             expect {
  177.         -re "(Access List is not in sync with running config)\[\r\n]*\r\n" {
  178.                     set s "# "
  179.                     append s $expect_out(1,string)
  180.                     puts $s
  181.                     exp_continue
  182.                 }
  183.         -re "(List is not in sync with running config)\[\r\n]*\r\n" {
  184.                     set s "# "
  185.                     append s $expect_out(1,string)
  186.                     puts $s
  187.                     exp_continue
  188.                 }
  189.                 -re "(Total cam count \[^\r\n]+)\[\r\n]*\r\n" {
  190.                     set s "# "
  191.                     append s $expect_out(1,string)
  192.                     puts $s
  193.                     exp_continue
  194.                 }
  195.                 -re "^ *(\[^\r\n]*)\[\r\n]*\r\n" {
  196.                     printacl $expect_out(1,string)
  197.                     exp_continue
  198.                 }
  199.                 -re $cprompt {
  200.                     # This action must be last
  201.                     # done
  202.                 }
  203.             }
  204.             puts "."
  205.             return
  206.         }
  207.         -re "% Error: Access-list $acl does not exist\.\[\r\n]*\r\n" {
  208.             # Send back an empty list
  209.             expect -re $cprompt
  210.             puts "listacl"
  211.             return
  212.         }
  213.         -re "% Error: Access-list was not applied on this interface\.\[\r\n]*\r\n" {
  214.             # Fall back to config'd ACL (without counts)
  215.             expect -re $cprompt
  216.             listaclsimple $acl
  217.             return
  218.         }
  219.         "Connection closed by foreign host" {
  220.             puts "listacl-failed -"
  221.             puts "telnet session ended"
  222.             puts "."
  223.  
  224.             # exit so acld will start a fresh expect session
  225.             exit
  226.         }
  227.         -re $cprompt {
  228.             # Fall back to config'd ACL (without counts)
  229.             # This action must be last
  230.             listaclsimple $acl
  231.             return
  232.         }
  233.         timeout {
  234.             puts "listacl-failed -"
  235.             puts "timeout ($timeout seconds)"
  236.             puts "."
  237.  
  238.             # exit so acld will start a fresh expect session
  239.             exit
  240.         }
  241.     }
  242.     return
  243. }
  244.  
  245. # List both IPv4 and IPv6 routes
  246. # XXX there's no easy way to return an error if IPv4 are listed ok
  247. # but IPv6 routes fail
  248. proc listroute {} {
  249.     global currentmode
  250.  
  251.     set err [entermode "enable" ""]
  252.     if { $err != "" } {
  253.         puts "listroute-failed -"
  254.         puts "$err"
  255.         puts "."
  256.         return
  257.     }
  258.  
  259.     puts "listroute -"
  260.     _listroute ip
  261.     _listroute ipv6
  262.     puts "."
  263.     return
  264. }
  265.  
  266. proc login {addr cuser cpass1 cpass2 euser epass1 epass2} {
  267.     global spawn_id
  268.     global cprompt
  269.     global currentmode
  270.  
  271.     # Fire up subprocess
  272.     set pid [spawn telnet "-EKc" $addr]
  273.  
  274.     # Wait for connect
  275.     # If the router is busy it can take a long time for the initial connect
  276.     set timeout 60
  277.     expect {
  278.         eof {
  279.             # Don't hammer on router if we're misconfigured
  280.             catch {close} err
  281.             sleep 10
  282.             puts "login-failed -"
  283.             puts "child died (1)"
  284.             puts "."
  285.  
  286.             # exit so acld will start a fresh expect session
  287.             exit
  288.         }
  289.         timeout {
  290.             catch {close} err
  291.             puts "login-failed -"
  292.             puts "connect timeout ($timeout seconds)"
  293.             puts "."
  294.  
  295.             # exit so acld will start a fresh expect session
  296.             exit
  297.         }
  298.         "Connected to " {
  299.             # done
  300.         }
  301.         default {
  302.             catch {close} err
  303.             puts "login-failed -"
  304.             puts "unknown response: $expect_out(buffer)"
  305.             puts "."
  306.  
  307.             # exit so acld will start a fresh expect session
  308.             exit
  309.         }
  310.     }
  311.  
  312.     # Then wait for login prompt
  313.     expect {
  314.         eof {
  315.             # Don't hammer on router if we're misconfigured
  316.             catch {close} err
  317.             sleep 10
  318.             puts "login-failed -"
  319.             puts "child died (2)"
  320.             puts "."
  321.  
  322.             # exit so acld will start a fresh expect session
  323.             exit
  324.         }
  325.         timeout {
  326.             catch {close} err
  327.             puts "login-failed -"
  328.             puts "login prompt timeout ($timeout seconds)"
  329.             puts "."
  330.  
  331.             # exit so acld will start a fresh expect session
  332.             exit
  333.         }
  334.         default {
  335.             catch {close} err
  336.             puts "login-failed -"
  337.             puts "unknown response (2): $expect_out(buffer)"
  338.             puts "."
  339.  
  340.             # exit so acld will start a fresh expect session
  341.             exit
  342.         }
  343.         "Login:"
  344.     }
  345.  
  346.     # We only use the enable username and passwords with the force 10
  347.     if { ![sendpass "enable" $euser $epass1 $epass2] } {
  348.         catch {close} err
  349.         return
  350.     }
  351.  
  352.     sendcmd "terminal length 0"
  353.     expect -re $cprompt
  354.  
  355.     set currentmode "enable"
  356.     puts "login -"
  357.     puts "child telnet pid is $pid"
  358.     puts "."
  359.     return
  360. }
  361.  
  362. proc logout {} {
  363.     global currentmode
  364.  
  365.     set err [entermode "enable" ""]
  366.     if { $err != "" } {
  367.         puts "logout-failed -"
  368.         puts "$err"
  369.         puts "."
  370.  
  371.         # exit so acld will start a fresh expect session
  372.         exit
  373.     }
  374.  
  375.     sendcmd "exit"
  376.     set currentmode "logout"
  377.     set timeout 10
  378.     expect {
  379.         -re "Connection.*closed by.*host" {
  380.             catch {close} err
  381.             puts "logout"
  382.             return
  383.         }
  384.         timeout {
  385.             puts "logout-failed -"
  386.             puts "timeout ($timeout seconds)"
  387.             puts "."
  388.  
  389.             # exit so acld will start a fresh expect session
  390.             exit
  391.         }
  392.         default {
  393.             puts "logout-failed -"
  394.             puts "logout already logged out"
  395.             puts "."
  396.  
  397.             # exit so acld will start a fresh expect session
  398.             exit
  399.         }
  400.     }
  401.     return
  402. }
  403.  
  404. proc nonullzero {addr} {
  405.  
  406.     nullzerocmd "nonullzero" $addr "no"
  407.     return
  408. }
  409.  
  410. proc nullzero {addr} {
  411.  
  412.     nullzerocmd "nullzero" $addr {}
  413.     return
  414. }
  415.  
  416. proc permitudpdsthostport {addr port acl seq} {
  417.  
  418.     aclcmd "permitudpdsthostport" $acl $seq "" \
  419.         "permit udp any host $addr eq $port"
  420.     return
  421. }
  422.  
  423. proc permittcpdsthostport {addr port acl seq} {
  424.  
  425.     aclcmd "permittcpdsthostport" $acl $seq "" \
  426.         "permit tcp any host $addr eq $port"
  427.     return
  428. }
  429.  
  430. proc restore {addr acl seq} {
  431.  
  432.     aclcmd "restore" $acl $seq "no" ""
  433.     return
  434. }
  435.  
  436. proc restorehosthost {addr1 addr2 acl seq} {
  437.  
  438.     set ip [acl2ip $acl]
  439.  
  440.     aclcmd "restorehosthost" $acl $seq "no" \
  441.         "deny $ip host $addr1 host $addr2"
  442.     return
  443. }
  444.  
  445. proc restoreudpport {port acl seq} {
  446.  
  447.     aclcmd "restoreudpport" $acl $seq "no" "deny udp any any eq $port"
  448.     return
  449. }
  450.  
  451. proc restoretcpport {port acl seq} {
  452.  
  453.     aclcmd "restoretcpport" $acl $seq "no" "deny tcp any any eq $port"
  454.     return
  455. }
  456.  
  457. proc restoretcpdsthostport {addr port acl seq} {
  458.  
  459.     aclcmd "restoretcpdsthostport" $acl $seq "no" ""
  460.     return
  461. }
  462.  
  463. proc sync {} {
  464.     global cprompt
  465.     global currentmode
  466.     global currentacl
  467.  
  468.     # Save these so we can change back when we're done
  469.     set oldmode $currentmode
  470.     set oldacl $currentacl
  471.  
  472.     set err [entermode "enable" ""]
  473.     if { $err != "" } {
  474.         puts "sync-failed -"
  475.         puts "$err"
  476.         puts "."
  477.         return
  478.     }
  479.     sendcmd "copy running-config startup-config"
  480.     set timeout 10
  481.     expect {
  482.         # Try to be compatible with old/new versions of this dialogue...
  483.         #
  484.         #    "Proceed with copy"
  485.         #    "Proceed to copy the file"
  486.         #
  487.         -re "Proceed \[^\r\n]* copy\[^:\r\n]*:" {
  488.             # done
  489.         }
  490.         "Connection closed by foreign host" {
  491.             puts "sync-failed -"
  492.             puts "telnet session ended"
  493.             puts "."
  494.  
  495.             # exit so acld will start a fresh expect session
  496.             exit
  497.         }
  498.         -re $cprompt {
  499.             # This action must be last
  500.             puts "sync"
  501.             return
  502.         }
  503.         timeout {
  504.             puts "sync-failed -"
  505.             puts "confirm timeout ($timeout seconds)"
  506.             puts "exiting"
  507.             puts "."
  508.  
  509.             # exit so acld will start a fresh expect session
  510.             exit
  511.         }
  512.     }
  513.     sendcmd "yes"
  514.     set timeout 90
  515.     expect {
  516.         -re "(% Error: \[^\r\n]*)\[\r\n]*\r\n" {
  517.             puts "sync-failed -"
  518.             puts "$expect_out(1,string)"
  519.             puts "."
  520.  
  521.             expect -re $cprompt
  522.             return
  523.         }
  524.         -re "bytes successfully copied\[\r\n]*\r\n" {
  525.             # done
  526.             expect -re $cprompt
  527.         }
  528.         "Connection closed by foreign host" {
  529.             puts "sync-failed -"
  530.             puts "telnet session ended"
  531.             puts "."
  532.  
  533.             # exit so acld will start a fresh expect session
  534.             exit
  535.         }
  536.         timeout {
  537.             puts "sync-failed -"
  538.             puts "copy timeout ($timeout seconds)"
  539.             puts "exiting"
  540.             puts "."
  541.  
  542.             # exit so acld will start a fresh expect session
  543.             exit
  544.         }
  545.     }
  546.  
  547.     set err [entermode $oldmode $oldacl]
  548.     if { $err != "" } {
  549.         puts "sync-failed -"
  550.         puts "$err"
  551.         puts "."
  552.         return
  553.     }
  554.  
  555.     puts "sync"
  556.     return
  557. }
  558.  
  559. proc unpermitudpdsthostport {addr port acl seq} {
  560.  
  561.     aclcmd "unpermitudpdsthostport" $acl $seq "no" ""
  562.     return
  563. }
  564.  
  565. proc unpermittcpdsthostport {addr port acl seq} {
  566.  
  567.     aclcmd "unpermittcpdsthostport" $acl $seq "no" ""
  568.     return
  569. }
  570.  
  571. # Local procedures
  572.  
  573. # Returns "ip" or "ipv6" based on the acl name
  574. proc acl2ip {acl} {
  575.     global isipv6
  576.  
  577.     if [catch { set ipv6 [set isipv6($acl)] } err] {
  578.         set ipv6 0
  579.     }
  580.  
  581.     if { $ipv6 } {
  582.         set ip "ipv6"
  583.     } else {
  584.         set ip "ip"
  585.     }
  586.  
  587.     return $ip
  588. }
  589.  
  590. # aclcmd "restore" $acl $seq "no" "deny host $addr"
  591. proc aclcmd {what acl seq pre cmd} {
  592.     global cprompt
  593.     global lastseq
  594.  
  595.     if { $seq != 0 } {
  596.         if { $seq > $lastseq } {
  597.             puts "$what-failed -"
  598.             puts "sequence too large ($seq > $lastseq)"
  599.             puts "."
  600.             return
  601.         }
  602.         set cmd "seq $seq $cmd"
  603.     }
  604.     if { [string length $pre] > 0 } {
  605.         set cmd "$pre $cmd"
  606.     }
  607.  
  608.     set err [entermode "acl" $acl]
  609.     if { $err != "" } {
  610.         puts "$what-failed -"
  611.         puts "$err"
  612.         puts "."
  613.         return
  614.     }
  615.     sendcmd "$cmd"
  616.     set timeout 10
  617.     expect {
  618.         -re "(% Error: IPv6 Access-list not supported on this CAM profile\.)\[\r\n]*\r\n" {
  619.             puts "$what-failed -"
  620.             puts "$expect_out(1,string)"
  621.             puts "."
  622.             return
  623.         }
  624.         -re "(% Error: \[^\r\n]*)\[\r\n]*\r\n" {
  625.             puts "$what-failed -"
  626.             puts "$expect_out(1,string)"
  627.             puts "exiting"
  628.             puts "."
  629.  
  630.             # exit so acld will start a fresh expect session
  631.             exit
  632.         }
  633.         -re "^\[^\r\n]*\[\r\n]*\r\n" {
  634.             exp_continue
  635.         }
  636.         -re $cprompt {
  637.             # success
  638.             puts "$what"
  639.             return
  640.         }
  641.         timeout {
  642.             puts "$what-failed -"
  643.             puts "aclcmd: timeout ($timeout seconds)"
  644.             puts "."
  645.  
  646.             # exit so acld will start a fresh expect session
  647.             exit
  648.         }
  649.         "Connection closed by foreign host" {
  650.             puts "$what-failed -"
  651.             puts "telnet session ended"
  652.             puts "."
  653.  
  654.             # exit so acld will start a fresh expect session
  655.             exit
  656.         }
  657.         default {
  658.             puts "$what-failed -"
  659.             puts "aclcmd: unknown problem"
  660.             puts "."
  661.             return
  662.         }
  663.     }
  664.     return
  665. }
  666.  
  667. # Fall back to this version when the ACL is not active
  668. proc listaclsimple {acl} {
  669.     global cprompt
  670.  
  671.     set err [entermode "acl" $acl]
  672.     if { $err != "" } {
  673.         puts "listacl-failed -"
  674.         puts "$err"
  675.         puts "."
  676.         return
  677.     }
  678.  
  679.     set ip [acl2ip $acl]
  680.     if { $ip == "ip" } {
  681.         set expr "ip access-list extended $acl\[\r\n]*\r\n"
  682.     } else {
  683.         set expr "ipv6 access-list $acl\[\r\n]*\r\n"
  684.     }
  685.  
  686.     sendcmd "show config"
  687.     set timeout 10
  688.     expect {
  689.         -re $expr {
  690.             # done
  691.         }
  692.         -re $cprompt {
  693.             # This action must be last
  694.             puts "listacl"
  695.             return
  696.         }
  697.         timeout {
  698.             puts "listacl-failed -"
  699.             puts "listaclsimple: timeout 1 ($timeout seconds)"
  700.             puts "."
  701.  
  702.             # exit so acld will start a fresh expect session
  703.             exit
  704.         }
  705.     }
  706.  
  707.     # List 'em out
  708.     puts "listacl -"
  709.     expect {
  710.         -re "^ *(\[^\r\n]*)\[\r\n]*\r\n" {
  711.             printacl $expect_out(1,string)
  712.             exp_continue
  713.         }
  714.         -re $cprompt {
  715.             # This action must be last
  716.             # done
  717.         }
  718.         timeout {
  719.             # We've already declared success
  720.             puts "listaclsimple: timeout 2 ($timeout seconds)"
  721.             puts "."
  722.  
  723.             # exit so acld will start a fresh expect session
  724.             exit
  725.         }
  726.     }
  727.     puts "."
  728.     return
  729. }
  730.  
  731. proc _listroute {ip} {
  732.     global cprompt
  733.  
  734.     sendcmd "show $ip route"
  735.     set timeout 10
  736.     expect {
  737.         -re " ----+\[\r\n]+" {
  738.             # ok (IPv4 or IPv6)
  739.         }
  740.         -re $cprompt {
  741.             # This action must be last
  742.             puts "# couldn't find routes"
  743.             return
  744.         }
  745.         timeout {
  746.             puts "# timeout ($timeout seconds)"
  747.             puts "."
  748.  
  749.             # exit so acld will start a fresh expect session
  750.             exit
  751.         }
  752.     }
  753.     set what ""
  754.     set src ""
  755.     set dst ""
  756.     expect {
  757.         -re "^ .(\[BCORS]) .. (\[^ \r\n]+) *via (\[^, \r\n]+).*\[\r\n]*\r\n" {
  758.             # IPv4
  759.             set what $expect_out(1,string)
  760.             set src $expect_out(2,string)
  761.             set dst $expect_out(3,string)
  762.             printroute $what $src $dst
  763.             exp_continue
  764.         }
  765.         -re "^ .(\[BCORS]) .. (\[^ \r\n]+) *Direct, (\[^ \r\n]+ \[^ \r\n]+) .*\[\r\n]*\r\n" {
  766.             # IPv4
  767.             set what $expect_out(1,string)
  768.             set src $expect_out(2,string)
  769.             set dst $expect_out(3,string)
  770.             printroute $what $src $dst
  771.             exp_continue
  772.         }
  773.         -re "^ .(\[BCORSL]) .. (\[^ \r\n]+) *\[[]\[0-9]+/\[0-9]+]\[\r\n]*\r\n" {
  774.             # IPv6: first line
  775.             set what $expect_out(1,string)
  776.             set src $expect_out(2,string)
  777.             exp_continue
  778.         }
  779.         -re "^ +via (\[^,\r\n]+), .*\[\r\n]*\r\n" {
  780.             set dst $expect_out(1,string)
  781.             printroute $what $src $dst
  782.             exp_continue
  783.         }
  784.         -re "^ +Direct, (\[^,\r\n]+), .*\[\r\n]*\r\n" {
  785.             # IPv6: second line
  786.             set dst $expect_out(1,string)
  787.             printroute $what $src $dst
  788.             exp_continue
  789.         }
  790.         -re "^\[\r\n]*\r\n" {
  791.             # eat blank lines
  792.             exp_continue
  793.         }
  794.         -re "^(.*)\[\r\n]*\r\n" {
  795.             # Echo stuff we don't understand
  796.             puts "# unknown $expect_out(1,string)"
  797.             exp_continue
  798.         }
  799.         -re $cprompt {
  800.             # This action must be last
  801.             # done
  802.         }
  803.         timeout {
  804.             puts "# timeout ($timeout seconds)"
  805.         }
  806.     }
  807.     return
  808. }
  809.  
  810. proc printacl {str} {
  811.  
  812.     # Break into a list
  813.     set av [split $str " "]
  814.     set an [llength $av]
  815.  
  816.     # XXX gag me: remove empty elements (caused by multiple blanks)
  817.     set n 0
  818.     while { $n < $an } {
  819.         if { [lindex $av $n] == "" } {
  820.             set av [concat [lrange $av 0 [expr $n - 1]] \
  821.                 [lrange $av [expr $n + 1] [expr $an - 1]]]
  822.             set an [expr $an - 1]
  823.         } else {
  824.             incr n
  825.         }
  826.     }
  827.  
  828.     if { $an < 3 } {
  829.         error "# printacl: not enough args \"$str\""
  830.     }
  831.  
  832.     if { [lindex $av 0] == "seq" } {
  833.         set seq [lindex $av 1]
  834.     } else {
  835.         set seq 0
  836.     }
  837.  
  838.     if { [lindex $av [expr $an - 3]] == "count" } {
  839.         set count [lindex $av [expr $an - 2]]
  840.         set count [string trimleft $count "("]
  841.  
  842.         # Remove from argument vector
  843.         set an [expr $an - 3]
  844.         set av [lrange $av 0 $an]
  845.     } else {
  846.         set count 0
  847.     }
  848.  
  849.     set which [lindex $av 2]
  850.     if { $which == "deny" } {
  851.         set which "block"
  852.     } elseif { $which != "permit" } {
  853.         error "# printacl: can't find permit/deny \"$av\""
  854.     }
  855.  
  856.     set proto [lindex $av 3]
  857.     set what "unknown # $str"
  858.     set append ""
  859.     if { $proto == "ip" || $proto == "icmp" } {
  860.         if { $proto == "icmp" } {
  861.             set protostr $proto
  862.         } else {
  863.             set protostr ""
  864.         }
  865.         if { $an == 7 &&
  866.             [lindex $av 4] == "host" &&
  867.             [lindex $av 6] == "any" } {
  868.             # "permithost/blockhost"
  869.             # seq 123 deny ip host 10.0.0.1 any
  870.             # 0   1   2    3  4    5        6
  871.             set what "[set which][set protostr]host"
  872.             append append [lindex $av 5]
  873.         } elseif { $an == 8 &&
  874.             [lindex $av 4] == "host" &&
  875.             [lindex $av 6] == "host" } {
  876.             # "permithosthost/blockhosthost"
  877.             # seq 666 deny ip host 1.2.3.4 host 4.5.6.7
  878.             # 0   1   2    3  4    5       6    7
  879.             set what "[set which][set protostr]hosthost"
  880.             append append "[lindex $av 5] [lindex $av 7]"
  881.         } elseif { $an == 6 &&
  882.             [string first "/" [lindex $av 4]] > 1 &&
  883.             [lindex $av 5] == "any" } {
  884.             # "permitnet/blocknet"
  885.             # "show ip accounting" style
  886.             #    (net and mask width one word)
  887.             # seq 123 permit ip 10.0.0.0/24 any
  888.             # 0   1   2      3  4           5
  889.             set what "[set which][set protostr]net"
  890.             append append [lindex $av 4]
  891.         } elseif { $an == 7 &&
  892.             [string first "/" [lindex $av 5]] == 0 &&
  893.             [lindex $av 6] == "any" } {
  894.             # "permitnet/blocknet"
  895.             # "show config" style
  896.             #    (blank between net and mask width)
  897.             # seq 123 permit ip 10.0.0.0 /24 any
  898.             # 0   1   2      3  4        5   6
  899.             set what "[set which][set protostr]net"
  900.             append append "[lindex $av 4][lindex $av 5]"
  901.         } elseif { $an == 6 &&
  902.             [lindex $av 4] == "any" &&
  903.             [string first "/" [lindex $av 5]] > 1 } {
  904.             # "permitdstnet/blockdstnet"
  905.             # "show ip accounting" style
  906.             #    (net and mask width one word)
  907.             # seq 123 permit ip any 10.0.0.0/24
  908.             # 0   1   2      3  4   5
  909.             set what "[set which][set protostr]dstnet"
  910.             append append [lindex $av 5]
  911.         } elseif { $an == 7 &&
  912.             [lindex $av 4] == "any" &&
  913.             [string first "/" [lindex $av 6]] == 0 } {
  914.             # "permitdstnet/blockdstnet"
  915.             # "show config" style
  916.             #    (blank between net and mask width)
  917.             # seq 123 permit ip any 10.0.0.0 /24
  918.             # 0   1   2      3  4   5        6
  919.             set what "[set which][set protostr]dstnet"
  920.             append append "[lindex $av 5][lindex $av 6]"
  921.         } elseif { $an == 6 && [lrange $av 4 5] == "any any" } {
  922.             # "permitany/blockany"
  923.             # seq 123 permit ip any any
  924.             # 0   1   2      3  4   5
  925.             set what "[set which][set protostr]any"
  926.         } elseif { $an == 7 &&
  927.             [string first "/" [lindex $av 4]] > 0 &&
  928.             [lindex $av 5] == "host" } {
  929.             # "permitnethost/blocknethost"
  930.             # "permiticmpnethost/blockicmpnethost"
  931.             # "show ip accounting" style
  932.             #    (net and mask width one word)
  933.             # XXX do we still need the split version?
  934.             # seq 6 permit ip 10.0.0.0/22 host 10.1.2.3
  935.             # 0   1 2      3  4           5    6
  936.  
  937.             set what "$which[set protostr]nethost"
  938.             append append "[lindex $av 4] [lindex $av 6]"
  939.         } elseif { $an == 7 &&
  940.             [lrange $av 4 5] == "any host" } {
  941.             # "permiticmpdsthost/blockicmpdsthost"
  942.             # seq 123 permit icmp any host 10.0.0.1
  943.             # 0   1   2      3    4   5    6
  944.             set what "$which[set protostr]dsthost"
  945.             append append "[lindex $av 6]"
  946.         }
  947.     } elseif { $proto == "udp" || $proto == "tcp" } {
  948.         if { $an == 8 &&
  949.             [lrange $av 4 6] == "any any eq" } {
  950.             # "permitudpport/blockudpport"
  951.             # "permittcpport/blocktcpport"
  952.             # seq 123 deny udp any any eq 666
  953.             # 0   1   2    3   4   5   6  7
  954.             set what "$which[set proto]port"
  955.             append append [lindex $av 7]
  956.         } elseif { $an == 9 &&
  957.             [lindex $av 4] == "host" &&
  958.             [lrange $av 6 7] == "any eq" } {
  959.             # "permitudphostport/blockudphostport"
  960.             # "permittcphostport/blocktcphostport"
  961.             # seq 123 permit udp host 10.0.0.1 any eq 666
  962.             # 0   1   2      3   4    5        6   7  8
  963.             set what "$which[set proto]hostport"
  964.             append append "[lindex $av 5] [lindex $av 8]"
  965.         } elseif { $an == 9 &&
  966.             [lrange $av 4 5] == "any host" &&
  967.             [lindex $av 7] == "eq" } {
  968.             # "permitudpdsthostport/blockudpdsthostport"
  969.             # "permittcpdsthostport/blocktcpdsthostport"
  970.             # seq 123 permit udp any host 10.0.0.1 eq 666
  971.             # 0   1   2      3   4   5    6        7  8
  972.  
  973.             set what "$which[set proto]dsthostport"
  974.             append append "[lindex $av 6] [lindex $av 8]"
  975.         } elseif { $an == 7 &&
  976.             [string first "/" [lindex $av 5]] > 0 &&
  977.             [lindex $av 4] == "any" &&
  978.             [lindex $av 6] == "eq" } {
  979.             # "permitudpdsthostport/blockudpdsthostport"
  980.             # "permittcpdsthostport/blocktcpdsthostport"
  981.             # seq 500 permit tcp any 131.243.1.6/31 eq 22
  982.             # 0   1   2      3   4   5              6  7
  983.  
  984.             set what "$which[set proto]dstnetport"
  985.             append append "[lindex $av 5] [lindex $av 7]"
  986.         } elseif { $an == 8 &&
  987.             [string first "/" [lindex $av 4]] > 0 &&
  988.             [lrange $av 5 6] == "any eq" } {
  989.             # "permitudpnetport/blockudpnetport"
  990.             # "permittcpnetport/blocktcpnetport"
  991.             # "show ip accounting" style
  992.             #     (net and mask width one word)
  993.             # seq 123 permit udp 10.0.0.0/8 any eq 666
  994.             # 0   1   2      3   4          5   6  7
  995.             set what "$which[set proto]netport"
  996.             append append "[lindex $av 4] [lindex $av 7]"
  997.         } elseif { $an == 9 &&
  998.             [string first "/" [lindex $av 5]] == 0 &&
  999.             [lrange $av 6 7] == "any eq" } {
  1000.             # "permitudpnetport/blockudpnetport"
  1001.             # "permittcpnetport/blocktcpnetport"
  1002.             # "show config" style
  1003.             #     (blank between net and mask width)
  1004.             # seq 123 permit udp 10.0.0.0 /8 any eq 666
  1005.             # 0   1   2      3   4        5  6   7  8
  1006.             set what "$which[set proto]netport"
  1007.             append append "[lindex $av 4][lindex $av 5]"
  1008.             append append " [lindex $av 8]"
  1009.         } elseif { $an == 9 &&
  1010.             [lindex $av 4] == "host" &&
  1011.             [lindex $av 6] == "eq" &&
  1012.             [lindex $av 8] == "any" } {
  1013.             # "permitudphostsrcport/blockudphostsrcport"
  1014.             # "permittcphostsrcport/blocktcphostsrcport"
  1015.             # seq 123 permit udp host 10.0.0.1 eq 666 any
  1016.             # 0   1   2      3   4    5        6  7   8
  1017.  
  1018.             set what "$which[set proto]hostsrcport"
  1019.             append append "[lindex $av 5] [lindex $av 7]"
  1020.         } elseif { $an == 10 &&
  1021.             [lindex $av 4] == "host" &&
  1022.             [lindex $av 6] == "host" &&
  1023.             [lindex $av 8] == "eq" } {
  1024.             # "permitudphostpairdstport/blockudphostpairdstport"
  1025.             # "permittcphostpairdstport/blocktcphostpairdstport"
  1026.             # seq 123 permit udp host 10.0.0.1 host 10.0.0.2 eq 666
  1027.             # 0   1   2      3   4    5        6    7        8  9
  1028.  
  1029.             set what "$which[set proto]hostpairdstport"
  1030.             append append "[lindex $av 5] [lindex $av 7]"
  1031.             append append " [lindex $av 9]"
  1032.         } elseif { $an == 9 &&
  1033.             [string first "/" [lindex $av 4]] > 0 &&
  1034.             [lindex $av 5] == "host" &&
  1035.             [lindex $av 7] == "eq" } {
  1036.             # "permitudpnethostport/blockudpnethostport"
  1037.             # "permittcpnethostport/blocktcpnethostport"
  1038.             # "show ip accounting" style
  1039.             #    (net and mask width one word)
  1040.             # XXX do we still need the split version?
  1041.             # seq 7 permit tcp 10.0.0.0/22 host 10.3.4.5 eq 5
  1042.             # 0   1 2      3   4           5    6        7  8
  1043.  
  1044.             set what "$which[set proto]nethostport"
  1045.             append append "[lindex $av 4] [lindex $av 6]"
  1046.             append append " [lindex $av 8]"
  1047.         } elseif { $an == 6 &&
  1048.             [string first "/" [lindex $av 5]] > 0 &&
  1049.             [lindex $av 4] == "any" } {
  1050.             # "permitudpdstnet/blockudpdstnet"
  1051.             # "permittcpdstnet/blocktcpdstnet"
  1052.             # "show ip accounting" style
  1053.             #    (net and mask width one word)
  1054.             # XXX2 do we still need the split version?
  1055.             # seq 4 deny tcp any 10.1.0.0/30
  1056.             # 0   1 2    3   4   5
  1057.  
  1058.             set what "$which[set proto]dstnet"
  1059.             append append "[lindex $av 5]"
  1060.         } elseif { $an == 7 &&
  1061.             [lrange $av 4 5] == "any host" } {
  1062.             # "permitudpdsthost/blockudpdsthost"
  1063.             # seq 123 permit udp any host 10.0.0.1
  1064.             # 0   1   2      3   4   5    6
  1065.  
  1066.             set what "$which[set proto]dsthost"
  1067.             append append "[lindex $av 6]"
  1068.         }
  1069.     }
  1070.  
  1071.     set msg "$seq $count $what"
  1072.     if { $append != "" } {
  1073.         append msg " $append"
  1074.     }
  1075.     puts $msg
  1076.     return
  1077. }
  1078.  
  1079. proc printroute {what src dst} {
  1080.  
  1081.     # Strip trailing /32 or /128 from host routes
  1082.     if { [string first "." $src] > 0 } {
  1083.         set w "32"
  1084.     } else {
  1085.         set w "128"
  1086.     }
  1087.     set i [string first "/$w" $src]
  1088.     if { $i > 1 } {
  1089.         set src [string range $src 0 [expr $i - 1]]
  1090.     }
  1091.  
  1092.     if { $what == "C" } {
  1093.         # interface
  1094.         puts "I $src"
  1095.     } elseif { $what == "O" || $what == "B" || $what == "R" } {
  1096.         # dynamic
  1097.         puts "D $src $dst"
  1098.     } elseif { $what == "S" || $what == "L" } {
  1099.         if { $dst == "Nu 0" } {
  1100.             # null zero
  1101.             puts "N $src"
  1102.         } else {
  1103.             # static
  1104.             puts "S $src $dst"
  1105.         }
  1106.     } else {
  1107.         puts "# unknown $what $src $dst"
  1108.     }
  1109.     return
  1110. }
  1111.  
  1112. proc nullzerocmd {what addr pre} {
  1113.     global cprompt
  1114.  
  1115.     set err [entermode "config" {}]
  1116.     if { $err != "" } {
  1117.         puts "$what-failed -"
  1118.         puts "$err"
  1119.         puts "."
  1120.         return
  1121.     }
  1122.  
  1123.     if { [string first "." $addr] > 0 } {
  1124.         set ip "ip"
  1125.         set w "32"
  1126.     } else {
  1127.         set ip "ipv6"
  1128.         set w "128"
  1129.     }
  1130.  
  1131.     if { [string first "/" $addr] > 0 } {
  1132.         # Network with mask
  1133.         set cmd "$ip route $addr null 0"
  1134.     } else {
  1135.         # Host address
  1136.         set cmd "$ip route $addr/$w null 0"
  1137.     }
  1138.     if { $pre != "" } {
  1139.         set cmd "$pre $cmd"
  1140.     }
  1141.     sendcmd $cmd
  1142.     set timeout 10
  1143.     expect {
  1144.         -re "(% Error: \[^\r\n]*)\[\r\n]*\r\n" {
  1145.             puts "$what-failed -"
  1146.             puts "$expect_out(1,string)"
  1147.             puts "exiting"
  1148.             puts "."
  1149.  
  1150.             # exit so acld will start a fresh expect session
  1151.             exit
  1152.         }
  1153.         -re "^\[^\r\n]*\[\r\n]*\r\n" {
  1154.             exp_continue
  1155.         }
  1156.         "Connection closed by foreign host" {
  1157.             puts "$what-failed -"
  1158.             puts "telnet session ended"
  1159.             puts "."
  1160.  
  1161.             # exit so acld will start a fresh expect session
  1162.             exit
  1163.         }
  1164.         -re $cprompt {
  1165.             # This action must be last
  1166.             # success
  1167.             puts "$what"
  1168.             return
  1169.         }
  1170.         timeout {
  1171.             puts "$what-failed -"
  1172.             puts "nullzerocmd: timeout ($timeout seconds)"
  1173.             puts "."
  1174.  
  1175.             # exit so acld will start a fresh expect session
  1176.             exit
  1177.         }
  1178.         default {
  1179.             puts "$what-failed -"
  1180.             puts "nullzerocmd: unknown problem"
  1181.             puts "."
  1182.             return
  1183.         }
  1184.     }
  1185.     return
  1186. }
  1187.  
  1188. proc sendcmd {cmd} {
  1189.     global spawn_id
  1190.  
  1191.     if [catch {send -- "$cmd\r"} err] {
  1192.         puts "sendcmd: $err"
  1193.         # exit so acld will start a fresh expect session
  1194.         exit
  1195.     }
  1196.     return
  1197. }
  1198.  
  1199. proc sendpass {what pass1 pass2} {
  1200.     global spawn_id
  1201.     global cprompt
  1202.  
  1203.     # Send first password
  1204.     sendcmd "$pass1"
  1205.  
  1206.     set timeout 10
  1207.     set which "first"
  1208.     expect {
  1209.         "Received disconnect" {
  1210.             puts "login-failed -"
  1211.             puts "all passwords failed"
  1212.             puts "."
  1213.             return 0
  1214.         }
  1215.         "password: " {
  1216.             if { $which == "second" } {
  1217.                 puts "login-failed -"
  1218.                 puts "first and second $what passwords failed"
  1219.                 puts "."
  1220.                 return 0
  1221.             }
  1222.  
  1223.             # Maybe we were only given one password
  1224.             if { $pass2 == "" } {
  1225.                 puts "login-failed -"
  1226.                 puts "$what password failed"
  1227.                 puts "."
  1228.                 return 0
  1229.             }
  1230.  
  1231.             # Send second password
  1232.             sendcmd "$pass2"
  1233.             set which "second"
  1234.             exp_continue
  1235.         }
  1236.         -re "^Permission denied.*\[\r\n]*\r\n" {
  1237.             exp_continue
  1238.         }
  1239.  
  1240.         -re $cprompt {
  1241.             # This action must be last
  1242.             # done
  1243.         }
  1244.         timeout {
  1245.             puts "login-failed -"
  1246.             puts "sendpass: timeout ($timeout seconds)"
  1247.             puts "."
  1248.             return 0
  1249.         }
  1250.     }
  1251.     return 1
  1252. }
  1253.  
  1254. #
  1255. # Modes we currently know about:
  1256. #
  1257. #    enable
  1258. #    config
  1259. #    acl
  1260. #
  1261. # This table tells entermode how to get from one mode to another
  1262. #
  1263. set modemoves(enable,enable)    { }
  1264. set modemoves(enable,config)    { "config" }
  1265. set modemoves(enable,acl)    { "config" "acl" }
  1266.  
  1267. set modemoves(config,enable)    { "exit" }
  1268. set modemoves(config,config)    { }
  1269. set modemoves(config,acl)    { "acl" }
  1270.  
  1271. set modemoves(acl,enable)    { "exit" "exit" }
  1272. set modemoves(acl,config)    { "exit" }
  1273. set modemoves(acl,acl)        { "acl" }
  1274.  
  1275. proc entermode {mode acl} {
  1276.     global cprompt
  1277.     global currentmode
  1278.     global currentacl
  1279.     global modemoves
  1280.  
  1281.     set timeout 10
  1282.     if [catch {set moves $modemoves($currentmode,$mode)} err] {
  1283.         puts "entermode: $err"
  1284.  
  1285.         # exit so acld will start a fresh expect session
  1286.         exit
  1287.     }
  1288.     set n [llength $moves]
  1289.     if { $n == 0 } {
  1290.         return ""
  1291.     }
  1292.  
  1293.     set ip [acl2ip $acl]
  1294.  
  1295.     set errstr ""
  1296.     for { set i 0 } { $i < $n } { incr i } {
  1297.         set move [lindex $moves $i]
  1298.         if { $move != "acl" } {
  1299.             set cmd "$move"
  1300.         } elseif { $currentmode != "acl" || $currentacl != $acl } {
  1301.             if { $ip == "ip" } {
  1302.                 set cmd "ip access-list extended $acl"
  1303.             } else {
  1304.                 set cmd "ipv6 access-list $acl"
  1305.             }
  1306.         } else {
  1307.             # already there
  1308.             continue
  1309.         }
  1310.  
  1311.         sendcmd "$cmd"
  1312.         expect {
  1313.             -re "(% Warning: The following users are currently configuring the system:)\[\r\n]*\r\n" {
  1314.                 # Ignore
  1315.                 exp_continue
  1316.             }
  1317.             -re "(User \"\[^\"\r\n]*\" on \[^\r\n]*)\[\r\n]*\r\n" {
  1318.                 # Ignore
  1319.                 exp_continue
  1320.             }
  1321.             -re "(% Error: Access-list was not applied on this interface\.)\[\r\n]*\r\n" {
  1322.                 set errstr "$expect_out(1,string)"
  1323.                 if { $currentmode != "enable" } {
  1324.                     set currentmode "config"
  1325.                 }
  1326.                 exp_continue
  1327.             }
  1328.             -re "(% Error: IPv6 Access-list not supported on this CAM profile\.)\[\r\n]*\r\n" {
  1329.                 set errstr "$expect_out(1,string)"
  1330.                 set currentmode "config"
  1331.                 exp_continue
  1332.             }
  1333.             -re "(% Error: \[^\r\n]*)\[\r\n]*\r\n" {
  1334.                 set errstr "$expect_out(1,string)"
  1335.                 exp_continue
  1336.             }
  1337.             "Connection closed by foreign host" {
  1338.                 puts "entermode: telnet session ended"
  1339.  
  1340.                 # exit so acld will start a fresh expect session
  1341.                 exit
  1342.             }
  1343.             -re $cprompt {
  1344.                 # This action must be last
  1345.                 # done
  1346.             }
  1347.             timeout {
  1348.                 puts "entermode: timeout ($timeout seconds)"
  1349.  
  1350.                 # exit so acld will start a fresh expect session
  1351.                 exit
  1352.             }
  1353.         }
  1354.  
  1355.         # Bail at the first sign of trouble
  1356.         if { $errstr != "" } {
  1357.             break
  1358.         }
  1359.  
  1360.         # Keep track of current mode in case we're making more than one
  1361.         if { $move == "config" } {
  1362.             set currentmode $move
  1363.         } else {
  1364.             set currentmode $mode
  1365.         }
  1366.         if { $move == "acl" } {
  1367.             set currentacl $acl
  1368.         }
  1369.     }
  1370.     return $errstr
  1371. }
  1372.  
  1373. # These are required to be at the end
  1374. log_user 0
  1375. interpreter
  1376.