Fix: 修正H3C LLDP邻居解析,使用ARP表映射MAC到IP
- 根据实际输出格式重写解析器 - 添加display arp命令获取MAC-IP映射 - 通过ChassisID(MAC)在ARP表中查找对应IP - 正确提取本地接口和远程接口信息 - 实现MAC地址到IP地址的自动关联
Esse commit está contido em:
+112
-47
@@ -20,18 +20,24 @@ func (p *H3CParser) GetCommands() []string {
|
|||||||
"display interface",
|
"display interface",
|
||||||
"display ip interface brief",
|
"display ip interface brief",
|
||||||
"display lldp neighbor-information",
|
"display lldp neighbor-information",
|
||||||
|
"display arp", // 添加ARP表用于MAC到IP的映射
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse 解析H3C设备输出
|
// Parse 解析H3C设备输出
|
||||||
func (p *H3CParser) Parse(device *models.Device, outputs []string) error {
|
func (p *H3CParser) Parse(device *models.Device, outputs []string) error {
|
||||||
if len(outputs) < 4 {
|
if len(outputs) < 5 {
|
||||||
return fmt.Errorf("insufficient command outputs")
|
return fmt.Errorf("insufficient command outputs")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.parseVersion(device, outputs[0])
|
p.parseVersion(device, outputs[0])
|
||||||
device.Interfaces = p.parseInterfaces(outputs[1], outputs[2])
|
device.Interfaces = p.parseInterfaces(outputs[1], outputs[2])
|
||||||
device.Neighbors = p.parseNeighbors(outputs[3])
|
|
||||||
|
// 解析ARP表用于MAC到IP映射
|
||||||
|
arpTable := p.parseARPTable(outputs[4])
|
||||||
|
|
||||||
|
// 解析LLDP邻居,使用ARP表进行MAC到IP的映射
|
||||||
|
device.Neighbors = p.parseNeighbors(outputs[3], arpTable)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -112,6 +118,36 @@ func (p *H3CParser) parseInterfaces(interfaceOutput, briefOutput string) []model
|
|||||||
return interfaces
|
return interfaces
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseARPTable 解析ARP表,建立MAC到IP的映射
|
||||||
|
func (p *H3CParser) parseARPTable(output string) map[string]string {
|
||||||
|
macToIP := make(map[string]string)
|
||||||
|
lines := strings.Split(output, "\n")
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
// 跳过空行和标题行
|
||||||
|
if strings.TrimSpace(line) == "" ||
|
||||||
|
strings.Contains(line, "Type") ||
|
||||||
|
strings.Contains(line, "------") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// ARP表格式: IP Address MAC Address Interface/Vlan
|
||||||
|
// 例: 172.16.12.1 a4bb-6de2-62cd GE1/0/1
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
if len(fields) >= 2 {
|
||||||
|
ip := fields[0]
|
||||||
|
mac := strings.ToLower(fields[1])
|
||||||
|
|
||||||
|
// 验证是有效的IP和MAC
|
||||||
|
if isValidIP(ip) && isValidMAC(mac) {
|
||||||
|
macToIP[mac] = ip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return macToIP
|
||||||
|
}
|
||||||
|
|
||||||
func (p *H3CParser) parseInterfaceBrief(output string) map[string]models.Interface {
|
func (p *H3CParser) parseInterfaceBrief(output string) map[string]models.Interface {
|
||||||
interfaces := make(map[string]models.Interface)
|
interfaces := make(map[string]models.Interface)
|
||||||
lines := strings.Split(output, "\n")
|
lines := strings.Split(output, "\n")
|
||||||
@@ -131,78 +167,107 @@ func (p *H3CParser) parseInterfaceBrief(output string) map[string]models.Interfa
|
|||||||
return interfaces
|
return interfaces
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *H3CParser) parseNeighbors(output string) []models.Neighbor {
|
func (p *H3CParser) parseNeighbors(output string, arpTable map[string]string) []models.Neighbor {
|
||||||
var neighbors []models.Neighbor
|
var neighbors []models.Neighbor
|
||||||
scanner := bufio.NewScanner(strings.NewReader(output))
|
scanner := bufio.NewScanner(strings.NewReader(output))
|
||||||
|
|
||||||
var currentNeighbor *models.Neighbor
|
var currentNeighbor *models.Neighbor
|
||||||
|
var localInterface string
|
||||||
|
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
|
|
||||||
// 跳过空行和标题行
|
// 匹配本地接口行: LLDP neighbor-information of port 20[GigabitEthernet1/0/20]:
|
||||||
if strings.TrimSpace(line) == "" ||
|
if portRegex := regexp.MustCompile(`LLDP neighbor-information of port \d+\[([^\]]+)\]:`); portRegex.MatchString(line) {
|
||||||
strings.Contains(line, "LLDP neighbor information") ||
|
// 保存前一个邻居
|
||||||
strings.Contains(line, "------") {
|
if currentNeighbor != nil && currentNeighbor.RemoteInterface != "" {
|
||||||
|
neighbors = append(neighbors, *currentNeighbor)
|
||||||
|
}
|
||||||
|
|
||||||
|
matches := portRegex.FindStringSubmatch(line)
|
||||||
|
localInterface = matches[1]
|
||||||
|
currentNeighbor = &models.Neighbor{
|
||||||
|
LocalInterface: localInterface,
|
||||||
|
Protocol: "LLDP",
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// 匹配邻居设备信息 - display lldp neighbor-information 输出格式:
|
|
||||||
// NeighborIndex : 1
|
|
||||||
// ChassisID : 00e0-fc12-3456
|
|
||||||
// PortID : GigabitEthernet1/0/1
|
|
||||||
// SystemName : Switch-02
|
|
||||||
// ManagementAddress : 172.16.12.2
|
|
||||||
// LocalInterface : GigabitEthernet1/0/1
|
|
||||||
|
|
||||||
if strings.Contains(line, "NeighborIndex") {
|
|
||||||
if currentNeighbor != nil && currentNeighbor.RemoteDevice != "" {
|
|
||||||
neighbors = append(neighbors, *currentNeighbor)
|
|
||||||
}
|
|
||||||
currentNeighbor = &models.Neighbor{
|
|
||||||
Protocol: "LLDP",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if currentNeighbor != nil {
|
if currentNeighbor != nil {
|
||||||
// 提取设备名称
|
// 提取 ChassisID (MAC地址)
|
||||||
if strings.Contains(line, "SystemName") {
|
if strings.Contains(line, "ChassisID/subtype") {
|
||||||
parts := strings.SplitN(line, ":", 2)
|
parts := strings.SplitN(line, ":", 2)
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
currentNeighbor.RemoteDevice = strings.TrimSpace(parts[1])
|
value := strings.TrimSpace(parts[1])
|
||||||
|
// 格式: a4bb-6de2-62cd/MAC address
|
||||||
|
if macParts := strings.Split(value, "/"); len(macParts) > 0 {
|
||||||
|
mac := strings.TrimSpace(strings.ToLower(macParts[0]))
|
||||||
|
// 通过ARP表查找IP
|
||||||
|
if ip, ok := arpTable[mac]; ok {
|
||||||
|
currentNeighbor.RemoteIP = ip
|
||||||
|
currentNeighbor.RemoteDevice = ip // 暂时用IP作为设备名
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取管理IP地址
|
// 提取 PortID (远程接口)
|
||||||
if strings.Contains(line, "ManagementAddress") {
|
if strings.Contains(line, "PortID/subtype") {
|
||||||
parts := strings.SplitN(line, ":", 2)
|
parts := strings.SplitN(line, ":", 2)
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
currentNeighbor.RemoteIP = strings.TrimSpace(parts[1])
|
value := strings.TrimSpace(parts[1])
|
||||||
}
|
// 格式: GigabitEthernet0/0/1/Interface name
|
||||||
}
|
if portParts := strings.Split(value, "/"); len(portParts) >= 3 {
|
||||||
|
// 取前3部分作为接口名: GigabitEthernet0/0/1
|
||||||
// 提取远程接口
|
currentNeighbor.RemoteInterface = strings.Join(portParts[:3], "/")
|
||||||
if strings.Contains(line, "PortID") {
|
}
|
||||||
parts := strings.SplitN(line, ":", 2)
|
|
||||||
if len(parts) == 2 {
|
|
||||||
currentNeighbor.RemoteInterface = strings.TrimSpace(parts[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提取本地接口
|
|
||||||
if strings.Contains(line, "LocalInterface") {
|
|
||||||
parts := strings.SplitN(line, ":", 2)
|
|
||||||
if len(parts) == 2 {
|
|
||||||
currentNeighbor.LocalInterface = strings.TrimSpace(parts[1])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加最后一个邻居
|
// 添加最后一个邻居
|
||||||
if currentNeighbor != nil && currentNeighbor.RemoteDevice != "" {
|
if currentNeighbor != nil && currentNeighbor.RemoteInterface != "" {
|
||||||
neighbors = append(neighbors, *currentNeighbor)
|
neighbors = append(neighbors, *currentNeighbor)
|
||||||
}
|
}
|
||||||
|
|
||||||
return neighbors
|
return neighbors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isValidIP 简单验证IP地址
|
||||||
|
func isValidIP(ip string) bool {
|
||||||
|
parts := strings.Split(ip, ".")
|
||||||
|
if len(parts) != 4 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, part := range parts {
|
||||||
|
if len(part) == 0 || len(part) > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, c := range part {
|
||||||
|
if c < '0' || c > '9' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// isValidMAC 简单验证MAC地址
|
||||||
|
func isValidMAC(mac string) bool {
|
||||||
|
parts := strings.Split(mac, "-")
|
||||||
|
if len(parts) != 3 && len(parts) != 6 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, part := range parts {
|
||||||
|
if len(part) != 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, c := range part {
|
||||||
|
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
Referência em uma Nova Issue
Bloquear um usuário