| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- package device
- import (
- "bufio"
- "fmt"
- "net"
- "network-topology-discovery/pkg/models"
- "regexp"
- "strings"
- )
- // CiscoParser Cisco设备解析器
- type CiscoParser struct {
- BaseParser
- }
- // GetCommands 获取Cisco设备命令列表
- func (p *CiscoParser) GetCommands() []string {
- return []string{
- "show version",
- "show interface",
- "show ip interface brief",
- "show cdp neighbors detail",
- "show lldp neighbors detail",
- }
- }
- // Parse 解析Cisco设备输出
- func (p *CiscoParser) Parse(device *models.Device, outputs []string) error {
- if len(outputs) < 5 {
- return fmt.Errorf("insufficient command outputs")
- }
- // 解析设备基本信息
- p.parseVersion(device, outputs[0])
- // 解析接口信息
- interfaces := p.parseInterfaces(outputs[1], outputs[2])
- device.Interfaces = interfaces
- // 解析邻居信息
- neighbors := p.parseNeighbors(outputs[3], outputs[4])
- device.Neighbors = neighbors
- return nil
- }
- // parseVersion 解析版本信息
- func (p *CiscoParser) parseVersion(device *models.Device, output string) {
- // 提取主机名
- hostnameRegex := regexp.MustCompile(`^(\S+)\s+#`)
- lines := strings.Split(output, "\n")
- for _, line := range lines {
- if matches := hostnameRegex.FindStringSubmatch(line); len(matches) > 1 {
- device.Hostname = matches[1]
- break
- }
- }
- // 提取系统版本
- versionRegex := regexp.MustCompile(`Cisco IOS Software,?\s+(?:\S+\s+)?(?:\S+\s+)?Version\s+(\S+)`)
- if matches := versionRegex.FindStringSubmatch(output); len(matches) > 1 {
- device.OSVersion = matches[1]
- }
- // 提取运行时间
- uptimeRegex := regexp.MustCompile(`uptime is\s+(.+)`)
- if matches := uptimeRegex.FindStringSubmatch(output); len(matches) > 1 {
- device.Uptime = strings.TrimSpace(matches[1])
- }
- }
- // parseInterfaces 解析接口信息
- func (p *CiscoParser) parseInterfaces(interfaceOutput, briefOutput string) []models.Interface {
- var interfaces []models.Interface
- // 从brief输出解析接口状态
- briefMap := p.parseInterfaceBrief(briefOutput)
- // 从详细输出解析接口详情
- scanner := bufio.NewScanner(strings.NewReader(interfaceOutput))
- var currentInterface *models.Interface
- for scanner.Scan() {
- line := scanner.Text()
- // 匹配接口名称
- if nameRegex := regexp.MustCompile(`^(\S+)\s+is\s+(up|down|administratively down)`); nameRegex.MatchString(line) {
- // 保存前一个接口
- if currentInterface != nil {
- interfaces = append(interfaces, *currentInterface)
- }
- matches := nameRegex.FindStringSubmatch(line)
- currentInterface = &models.Interface{
- Name: matches[1],
- Status: matches[2],
- }
- // 填充brief信息
- if brief, ok := briefMap[currentInterface.Name]; ok {
- currentInterface.IP = brief.IP
- currentInterface.Status = brief.Status
- }
- }
- if currentInterface != nil {
- // 提取描述
- if descRegex := regexp.MustCompile(`Description:\s+(.+)`); descRegex.MatchString(line) {
- matches := descRegex.FindStringSubmatch(line)
- currentInterface.Description = matches[1]
- }
- // 提取MAC地址
- if macRegex := regexp.MustCompile(`Hardware is\s+\S+,\s+address is\s+(\S+)`); macRegex.MatchString(line) {
- matches := macRegex.FindStringSubmatch(line)
- currentInterface.MAC = matches[1]
- }
- // 提取IP地址
- if ipRegex := regexp.MustCompile(`Internet address is\s+(\d+\.\d+\.\d+\.\d+/\d+)`); ipRegex.MatchString(line) {
- matches := ipRegex.FindStringSubmatch(line)
- ipParts := strings.Split(matches[1], "/")
- if len(ipParts) == 2 {
- currentInterface.IP = ipParts[0]
- currentInterface.Mask = ipParts[1]
- }
- }
- // 提取带宽
- if speedRegex := regexp.MustCompile(`(\d+)\s+(Kbit|Mbit|Gbit)`); speedRegex.MatchString(line) {
- matches := speedRegex.FindStringSubmatch(line)
- currentInterface.Speed = matches[1] + " " + matches[2]
- }
- }
- }
- // 保存最后一个接口
- if currentInterface != nil {
- interfaces = append(interfaces, *currentInterface)
- }
- return interfaces
- }
- // parseInterfaceBrief 解析接口简要信息
- func (p *CiscoParser) parseInterfaceBrief(output string) map[string]models.Interface {
- interfaces := make(map[string]models.Interface)
- lines := strings.Split(output, "\n")
- for _, line := range lines {
- // 匹配: Interface IP-Address OK? Method Status Protocol
- fields := strings.Fields(line)
- if len(fields) >= 4 {
- iface := models.Interface{
- Name: fields[0],
- }
- // 检查是否是IP地址
- if net.ParseIP(fields[1]) != nil {
- iface.IP = fields[1]
- }
- // 状态
- if len(fields) >= 3 {
- iface.Status = strings.ToLower(fields[2])
- }
- interfaces[iface.Name] = iface
- }
- }
- return interfaces
- }
- // parseNeighbors 解析邻居信息
- func (p *CiscoParser) parseNeighbors(cdpOutput, lldpOutput string) []models.Neighbor {
- var neighbors []models.Neighbor
- // 解析CDP邻居
- cdpNeighbors := p.parseCDPNeighbors(cdpOutput)
- neighbors = append(neighbors, cdpNeighbors...)
- // 解析LLDP邻居
- lldpNeighbors := p.parseLLDPNeighbors(lldpOutput)
- neighbors = append(neighbors, lldpNeighbors...)
- return neighbors
- }
- // parseCDPNeighbors 解析CDP邻居
- func (p *CiscoParser) parseCDPNeighbors(output string) []models.Neighbor {
- var neighbors []models.Neighbor
- scanner := bufio.NewScanner(strings.NewReader(output))
- var currentNeighbor *models.Neighbor
- for scanner.Scan() {
- line := scanner.Text()
- // 设备ID
- if deviceRegex := regexp.MustCompile(`Device ID:\s+(\S+)`); deviceRegex.MatchString(line) {
- if currentNeighbor != nil {
- neighbors = append(neighbors, *currentNeighbor)
- }
- matches := deviceRegex.FindStringSubmatch(line)
- currentNeighbor = &models.Neighbor{
- RemoteDevice: matches[1],
- Protocol: "CDP",
- }
- }
- if currentNeighbor != nil {
- // 本地接口
- if localRegex := regexp.MustCompile(`Interface:\s+(\S+),\s+Port ID \(outgoing port\):\s+(\S+)`); localRegex.MatchString(line) {
- matches := localRegex.FindStringSubmatch(line)
- currentNeighbor.LocalInterface = matches[1]
- currentNeighbor.RemoteInterface = matches[2]
- }
- // IP地址
- if ipRegex := regexp.MustCompile(`IP address:\s+(\d+\.\d+\.\d+\.\d+)`); ipRegex.MatchString(line) {
- matches := ipRegex.FindStringSubmatch(line)
- currentNeighbor.RemoteIP = matches[1]
- }
- }
- }
- if currentNeighbor != nil {
- neighbors = append(neighbors, *currentNeighbor)
- }
- return neighbors
- }
- // parseLLDPNeighbors 解析LLDP邻居
- func (p *CiscoParser) parseLLDPNeighbors(output string) []models.Neighbor {
- var neighbors []models.Neighbor
- scanner := bufio.NewScanner(strings.NewReader(output))
- var currentNeighbor *models.Neighbor
- for scanner.Scan() {
- line := scanner.Text()
- // 邻居设备
- if deviceRegex := regexp.MustCompile(`Chassis id:\s+(\S+)`); deviceRegex.MatchString(line) {
- if currentNeighbor != nil && currentNeighbor.RemoteDevice != "" {
- neighbors = append(neighbors, *currentNeighbor)
- }
- matches := deviceRegex.FindStringSubmatch(line)
- currentNeighbor = &models.Neighbor{
- RemoteDevice: matches[1],
- Protocol: "LLDP",
- }
- }
- if currentNeighbor != nil {
- // 本地接口
- if localRegex := regexp.MustCompile(`Local Int:\s+(\S+)`); localRegex.MatchString(line) {
- matches := localRegex.FindStringSubmatch(line)
- currentNeighbor.LocalInterface = matches[1]
- }
- // 远程接口
- if remoteRegex := regexp.MustCompile(`Port ID:\s+(\S+)`); remoteRegex.MatchString(line) {
- matches := remoteRegex.FindStringSubmatch(line)
- currentNeighbor.RemoteInterface = matches[1]
- }
- // IP地址
- if ipRegex := regexp.MustCompile(`Management address:\s+(\d+\.\d+\.\d+\.\d+)`); ipRegex.MatchString(line) {
- matches := ipRegex.FindStringSubmatch(line)
- currentNeighbor.RemoteIP = matches[1]
- }
- }
- }
- if currentNeighbor != nil && currentNeighbor.RemoteDevice != "" {
- neighbors = append(neighbors, *currentNeighbor)
- }
- return neighbors
- }
|