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 }