Implements a Cisco IOS CLI emulator with four modes (user exec, privileged exec, global config, interface config), Cisco-style command abbreviation (e.g. sh run, conf t), enable password flow, and realistic show command output including running-config, interfaces, IP routes, and VLANs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
110 lines
2.8 KiB
Go
110 lines
2.8 KiB
Go
package cisco
|
|
|
|
import "fmt"
|
|
|
|
// iosMode represents the current CLI mode of the IOS state machine.
|
|
type iosMode int
|
|
|
|
const (
|
|
modeUserExec iosMode = iota // Router>
|
|
modePrivilegedExec // Router#
|
|
modeGlobalConfig // Router(config)#
|
|
modeInterfaceConfig // Router(config-if)#
|
|
)
|
|
|
|
// ifaceInfo holds interface metadata for show commands.
|
|
type ifaceInfo struct {
|
|
name string
|
|
ip string
|
|
mask string
|
|
status string
|
|
protocol string
|
|
mac string
|
|
bandwidth string
|
|
mtu int
|
|
rxPackets int
|
|
txPackets int
|
|
rxBytes int
|
|
txBytes int
|
|
shutdown bool
|
|
desc string
|
|
}
|
|
|
|
// iosState holds all mutable state for the Cisco IOS shell session.
|
|
type iosState struct {
|
|
mode iosMode
|
|
hostname string
|
|
model string
|
|
iosVersion string
|
|
serial string
|
|
enablePass string
|
|
interfaces []ifaceInfo
|
|
currentIf string
|
|
}
|
|
|
|
func newIOSState(hostname, model, iosVersion, enablePass string) *iosState {
|
|
return &iosState{
|
|
mode: modeUserExec,
|
|
hostname: hostname,
|
|
model: model,
|
|
iosVersion: iosVersion,
|
|
serial: "FTX1524Z0P3",
|
|
enablePass: enablePass,
|
|
interfaces: defaultInterfaces(),
|
|
}
|
|
}
|
|
|
|
func defaultInterfaces() []ifaceInfo {
|
|
return []ifaceInfo{
|
|
{
|
|
name: "GigabitEthernet0/0", ip: "192.168.1.1", mask: "255.255.255.0",
|
|
status: "up", protocol: "up", mac: "0050.7966.6800",
|
|
bandwidth: "1000000 Kbit", mtu: 1500,
|
|
rxPackets: 148253, txPackets: 93127, rxBytes: 19284732, txBytes: 8291043,
|
|
},
|
|
{
|
|
name: "GigabitEthernet0/1", ip: "10.0.0.1", mask: "255.255.255.252",
|
|
status: "up", protocol: "up", mac: "0050.7966.6801",
|
|
bandwidth: "1000000 Kbit", mtu: 1500,
|
|
rxPackets: 52104, txPackets: 48891, rxBytes: 4182934, txBytes: 3901284,
|
|
},
|
|
{
|
|
name: "GigabitEthernet0/2", ip: "unassigned", mask: "",
|
|
status: "administratively down", protocol: "down", mac: "0050.7966.6802",
|
|
bandwidth: "1000000 Kbit", mtu: 1500, shutdown: true,
|
|
},
|
|
{
|
|
name: "Vlan1", ip: "172.16.0.1", mask: "255.255.0.0",
|
|
status: "up", protocol: "up", mac: "0050.7966.6810",
|
|
bandwidth: "1000000 Kbit", mtu: 1500,
|
|
rxPackets: 8421, txPackets: 7103, rxBytes: 512384, txBytes: 423901,
|
|
},
|
|
}
|
|
}
|
|
|
|
// prompt returns the IOS prompt string for the current mode.
|
|
func (s *iosState) prompt() string {
|
|
switch s.mode {
|
|
case modeUserExec:
|
|
return fmt.Sprintf("%s>", s.hostname)
|
|
case modePrivilegedExec:
|
|
return fmt.Sprintf("%s#", s.hostname)
|
|
case modeGlobalConfig:
|
|
return fmt.Sprintf("%s(config)#", s.hostname)
|
|
case modeInterfaceConfig:
|
|
return fmt.Sprintf("%s(config-if)#", s.hostname)
|
|
default:
|
|
return fmt.Sprintf("%s>", s.hostname)
|
|
}
|
|
}
|
|
|
|
// findInterface returns a pointer to the interface with the given name, or nil.
|
|
func (s *iosState) findInterface(name string) *ifaceInfo {
|
|
for i := range s.interfaces {
|
|
if s.interfaces[i].name == name {
|
|
return &s.interfaces[i]
|
|
}
|
|
}
|
|
return nil
|
|
}
|