Initial commit: 网络拓扑发现系统
- 支持Cisco、华为、H3C、ASA、Linux、Windows设备 - SSH远程采集设备信息 - 自动发现网络拓扑(LLDP/CDP) - Web可视化界面 - 支持旧版SSH加密算法兼容
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
package device
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"network-topology-discovery/pkg/models"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// WindowsParser Windows Server解析器
|
||||
type WindowsParser struct {
|
||||
BaseParser
|
||||
}
|
||||
|
||||
// GetCommands 获取Windows命令列表
|
||||
func (p *WindowsParser) GetCommands() []string {
|
||||
return []string{
|
||||
"hostname",
|
||||
"systeminfo | findstr /B /C:\"OS Name\" /C:\"OS Version\"",
|
||||
"Get-NetAdapter | Select-Object Name, InterfaceDescription, Status, MacAddress, LinkSpeed | Format-List",
|
||||
"Get-NetIPAddress | Where-Object AddressFamily -eq IPv4 | Select-Object InterfaceAlias, IPAddress, PrefixLength | Format-List",
|
||||
"systeminfo | findstr /B /C:\"System Boot Time\"",
|
||||
}
|
||||
}
|
||||
|
||||
// Parse 解析Windows输出
|
||||
func (p *WindowsParser) Parse(device *models.Device, outputs []string) error {
|
||||
if len(outputs) < 5 {
|
||||
return fmt.Errorf("insufficient command outputs")
|
||||
}
|
||||
|
||||
device.Hostname = strings.TrimSpace(outputs[0])
|
||||
device.OSVersion = p.parseOSVersion(outputs[1])
|
||||
device.Uptime = p.parseUptime(outputs[4])
|
||||
device.Interfaces = p.parseInterfaces(outputs[2], outputs[3])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *WindowsParser) parseOSVersion(output string) string {
|
||||
lines := strings.Split(output, "\n")
|
||||
var osInfo []string
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "OS Name") || strings.Contains(line, "OS Version") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
osInfo = append(osInfo, strings.TrimSpace(parts[1]))
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(osInfo, ", ")
|
||||
}
|
||||
|
||||
func (p *WindowsParser) parseUptime(output string) string {
|
||||
if strings.Contains(output, "System Boot Time") {
|
||||
parts := strings.SplitN(output, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
return strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func (p *WindowsParser) parseInterfaces(adapterOutput, ipOutput string) []models.Interface {
|
||||
var interfaces []models.Interface
|
||||
|
||||
// 解析网卡信息
|
||||
adapters := p.parseNetAdapters(adapterOutput)
|
||||
|
||||
// 解析IP信息
|
||||
ipMap := p.parseIPAddresses(ipOutput)
|
||||
|
||||
// 合并信息
|
||||
for _, adapter := range adapters {
|
||||
iface := adapter
|
||||
if ipInfo, ok := ipMap[adapter.Name]; ok {
|
||||
iface.IP = ipInfo.IP
|
||||
iface.Mask = ipInfo.Mask
|
||||
}
|
||||
interfaces = append(interfaces, iface)
|
||||
}
|
||||
|
||||
return interfaces
|
||||
}
|
||||
|
||||
func (p *WindowsParser) parseNetAdapters(output string) []models.Interface {
|
||||
var interfaces []models.Interface
|
||||
var currentInterface *models.Interface
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.Contains(line, "Name") && strings.Contains(line, ":") {
|
||||
if currentInterface != nil {
|
||||
interfaces = append(interfaces, *currentInterface)
|
||||
}
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
currentInterface = &models.Interface{
|
||||
Name: strings.TrimSpace(parts[1]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if currentInterface != nil {
|
||||
if strings.Contains(line, "InterfaceDescription") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
currentInterface.Description = strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(line, "Status") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
status := strings.TrimSpace(parts[1])
|
||||
if status == "Up" {
|
||||
currentInterface.Status = "up"
|
||||
} else {
|
||||
currentInterface.Status = "down"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(line, "MacAddress") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
currentInterface.MAC = strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(line, "LinkSpeed") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
currentInterface.Speed = strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if currentInterface != nil {
|
||||
interfaces = append(interfaces, *currentInterface)
|
||||
}
|
||||
|
||||
return interfaces
|
||||
}
|
||||
|
||||
type ipInfo struct {
|
||||
IP string
|
||||
Mask string
|
||||
}
|
||||
|
||||
func (p *WindowsParser) parseIPAddresses(output string) map[string]ipInfo {
|
||||
ipMap := make(map[string]ipInfo)
|
||||
var currentAlias string
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.Contains(line, "InterfaceAlias") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
currentAlias = strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(line, "IPAddress") && currentAlias != "" {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
if _, ok := ipMap[currentAlias]; !ok {
|
||||
ipMap[currentAlias] = ipInfo{}
|
||||
}
|
||||
info := ipMap[currentAlias]
|
||||
info.IP = strings.TrimSpace(parts[1])
|
||||
ipMap[currentAlias] = info
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(line, "PrefixLength") && currentAlias != "" {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
if _, ok := ipMap[currentAlias]; !ok {
|
||||
ipMap[currentAlias] = ipInfo{}
|
||||
}
|
||||
info := ipMap[currentAlias]
|
||||
info.Mask = strings.TrimSpace(parts[1])
|
||||
ipMap[currentAlias] = info
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ipMap
|
||||
}
|
||||
Reference in New Issue
Block a user