cisco.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. package device
  2. import (
  3. "bufio"
  4. "fmt"
  5. "net"
  6. "network-topology-discovery/pkg/models"
  7. "regexp"
  8. "strings"
  9. )
  10. // CiscoParser Cisco设备解析器
  11. type CiscoParser struct {
  12. BaseParser
  13. }
  14. // GetCommands 获取Cisco设备命令列表
  15. func (p *CiscoParser) GetCommands() []string {
  16. return []string{
  17. "show version",
  18. "show interface",
  19. "show ip interface brief",
  20. "show cdp neighbors detail",
  21. "show lldp neighbors detail",
  22. }
  23. }
  24. // Parse 解析Cisco设备输出
  25. func (p *CiscoParser) Parse(device *models.Device, outputs []string) error {
  26. if len(outputs) < 5 {
  27. return fmt.Errorf("insufficient command outputs")
  28. }
  29. // 解析设备基本信息
  30. p.parseVersion(device, outputs[0])
  31. // 解析接口信息
  32. interfaces := p.parseInterfaces(outputs[1], outputs[2])
  33. device.Interfaces = interfaces
  34. // 解析邻居信息
  35. neighbors := p.parseNeighbors(outputs[3], outputs[4])
  36. device.Neighbors = neighbors
  37. return nil
  38. }
  39. // parseVersion 解析版本信息
  40. func (p *CiscoParser) parseVersion(device *models.Device, output string) {
  41. // 提取主机名
  42. hostnameRegex := regexp.MustCompile(`^(\S+)\s+#`)
  43. lines := strings.Split(output, "\n")
  44. for _, line := range lines {
  45. if matches := hostnameRegex.FindStringSubmatch(line); len(matches) > 1 {
  46. device.Hostname = matches[1]
  47. break
  48. }
  49. }
  50. // 提取系统版本
  51. versionRegex := regexp.MustCompile(`Cisco IOS Software,?\s+(?:\S+\s+)?(?:\S+\s+)?Version\s+(\S+)`)
  52. if matches := versionRegex.FindStringSubmatch(output); len(matches) > 1 {
  53. device.OSVersion = matches[1]
  54. }
  55. // 提取运行时间
  56. uptimeRegex := regexp.MustCompile(`uptime is\s+(.+)`)
  57. if matches := uptimeRegex.FindStringSubmatch(output); len(matches) > 1 {
  58. device.Uptime = strings.TrimSpace(matches[1])
  59. }
  60. }
  61. // parseInterfaces 解析接口信息
  62. func (p *CiscoParser) parseInterfaces(interfaceOutput, briefOutput string) []models.Interface {
  63. var interfaces []models.Interface
  64. // 从brief输出解析接口状态
  65. briefMap := p.parseInterfaceBrief(briefOutput)
  66. // 从详细输出解析接口详情
  67. scanner := bufio.NewScanner(strings.NewReader(interfaceOutput))
  68. var currentInterface *models.Interface
  69. for scanner.Scan() {
  70. line := scanner.Text()
  71. // 匹配接口名称
  72. if nameRegex := regexp.MustCompile(`^(\S+)\s+is\s+(up|down|administratively down)`); nameRegex.MatchString(line) {
  73. // 保存前一个接口
  74. if currentInterface != nil {
  75. interfaces = append(interfaces, *currentInterface)
  76. }
  77. matches := nameRegex.FindStringSubmatch(line)
  78. currentInterface = &models.Interface{
  79. Name: matches[1],
  80. Status: matches[2],
  81. }
  82. // 填充brief信息
  83. if brief, ok := briefMap[currentInterface.Name]; ok {
  84. currentInterface.IP = brief.IP
  85. currentInterface.Status = brief.Status
  86. }
  87. }
  88. if currentInterface != nil {
  89. // 提取描述
  90. if descRegex := regexp.MustCompile(`Description:\s+(.+)`); descRegex.MatchString(line) {
  91. matches := descRegex.FindStringSubmatch(line)
  92. currentInterface.Description = matches[1]
  93. }
  94. // 提取MAC地址
  95. if macRegex := regexp.MustCompile(`Hardware is\s+\S+,\s+address is\s+(\S+)`); macRegex.MatchString(line) {
  96. matches := macRegex.FindStringSubmatch(line)
  97. currentInterface.MAC = matches[1]
  98. }
  99. // 提取IP地址
  100. if ipRegex := regexp.MustCompile(`Internet address is\s+(\d+\.\d+\.\d+\.\d+/\d+)`); ipRegex.MatchString(line) {
  101. matches := ipRegex.FindStringSubmatch(line)
  102. ipParts := strings.Split(matches[1], "/")
  103. if len(ipParts) == 2 {
  104. currentInterface.IP = ipParts[0]
  105. currentInterface.Mask = ipParts[1]
  106. }
  107. }
  108. // 提取带宽
  109. if speedRegex := regexp.MustCompile(`(\d+)\s+(Kbit|Mbit|Gbit)`); speedRegex.MatchString(line) {
  110. matches := speedRegex.FindStringSubmatch(line)
  111. currentInterface.Speed = matches[1] + " " + matches[2]
  112. }
  113. }
  114. }
  115. // 保存最后一个接口
  116. if currentInterface != nil {
  117. interfaces = append(interfaces, *currentInterface)
  118. }
  119. return interfaces
  120. }
  121. // parseInterfaceBrief 解析接口简要信息
  122. func (p *CiscoParser) parseInterfaceBrief(output string) map[string]models.Interface {
  123. interfaces := make(map[string]models.Interface)
  124. lines := strings.Split(output, "\n")
  125. for _, line := range lines {
  126. // 匹配: Interface IP-Address OK? Method Status Protocol
  127. fields := strings.Fields(line)
  128. if len(fields) >= 4 {
  129. iface := models.Interface{
  130. Name: fields[0],
  131. }
  132. // 检查是否是IP地址
  133. if net.ParseIP(fields[1]) != nil {
  134. iface.IP = fields[1]
  135. }
  136. // 状态
  137. if len(fields) >= 3 {
  138. iface.Status = strings.ToLower(fields[2])
  139. }
  140. interfaces[iface.Name] = iface
  141. }
  142. }
  143. return interfaces
  144. }
  145. // parseNeighbors 解析邻居信息
  146. func (p *CiscoParser) parseNeighbors(cdpOutput, lldpOutput string) []models.Neighbor {
  147. var neighbors []models.Neighbor
  148. // 解析CDP邻居
  149. cdpNeighbors := p.parseCDPNeighbors(cdpOutput)
  150. neighbors = append(neighbors, cdpNeighbors...)
  151. // 解析LLDP邻居
  152. lldpNeighbors := p.parseLLDPNeighbors(lldpOutput)
  153. neighbors = append(neighbors, lldpNeighbors...)
  154. return neighbors
  155. }
  156. // parseCDPNeighbors 解析CDP邻居
  157. func (p *CiscoParser) parseCDPNeighbors(output string) []models.Neighbor {
  158. var neighbors []models.Neighbor
  159. scanner := bufio.NewScanner(strings.NewReader(output))
  160. var currentNeighbor *models.Neighbor
  161. for scanner.Scan() {
  162. line := scanner.Text()
  163. // 设备ID
  164. if deviceRegex := regexp.MustCompile(`Device ID:\s+(\S+)`); deviceRegex.MatchString(line) {
  165. if currentNeighbor != nil {
  166. neighbors = append(neighbors, *currentNeighbor)
  167. }
  168. matches := deviceRegex.FindStringSubmatch(line)
  169. currentNeighbor = &models.Neighbor{
  170. RemoteDevice: matches[1],
  171. Protocol: "CDP",
  172. }
  173. }
  174. if currentNeighbor != nil {
  175. // 本地接口
  176. if localRegex := regexp.MustCompile(`Interface:\s+(\S+),\s+Port ID \(outgoing port\):\s+(\S+)`); localRegex.MatchString(line) {
  177. matches := localRegex.FindStringSubmatch(line)
  178. currentNeighbor.LocalInterface = matches[1]
  179. currentNeighbor.RemoteInterface = matches[2]
  180. }
  181. // IP地址
  182. if ipRegex := regexp.MustCompile(`IP address:\s+(\d+\.\d+\.\d+\.\d+)`); ipRegex.MatchString(line) {
  183. matches := ipRegex.FindStringSubmatch(line)
  184. currentNeighbor.RemoteIP = matches[1]
  185. }
  186. }
  187. }
  188. if currentNeighbor != nil {
  189. neighbors = append(neighbors, *currentNeighbor)
  190. }
  191. return neighbors
  192. }
  193. // parseLLDPNeighbors 解析LLDP邻居
  194. func (p *CiscoParser) parseLLDPNeighbors(output string) []models.Neighbor {
  195. var neighbors []models.Neighbor
  196. scanner := bufio.NewScanner(strings.NewReader(output))
  197. var currentNeighbor *models.Neighbor
  198. for scanner.Scan() {
  199. line := scanner.Text()
  200. // 邻居设备
  201. if deviceRegex := regexp.MustCompile(`Chassis id:\s+(\S+)`); deviceRegex.MatchString(line) {
  202. if currentNeighbor != nil && currentNeighbor.RemoteDevice != "" {
  203. neighbors = append(neighbors, *currentNeighbor)
  204. }
  205. matches := deviceRegex.FindStringSubmatch(line)
  206. currentNeighbor = &models.Neighbor{
  207. RemoteDevice: matches[1],
  208. Protocol: "LLDP",
  209. }
  210. }
  211. if currentNeighbor != nil {
  212. // 本地接口
  213. if localRegex := regexp.MustCompile(`Local Int:\s+(\S+)`); localRegex.MatchString(line) {
  214. matches := localRegex.FindStringSubmatch(line)
  215. currentNeighbor.LocalInterface = matches[1]
  216. }
  217. // 远程接口
  218. if remoteRegex := regexp.MustCompile(`Port ID:\s+(\S+)`); remoteRegex.MatchString(line) {
  219. matches := remoteRegex.FindStringSubmatch(line)
  220. currentNeighbor.RemoteInterface = matches[1]
  221. }
  222. // IP地址
  223. if ipRegex := regexp.MustCompile(`Management address:\s+(\d+\.\d+\.\d+\.\d+)`); ipRegex.MatchString(line) {
  224. matches := ipRegex.FindStringSubmatch(line)
  225. currentNeighbor.RemoteIP = matches[1]
  226. }
  227. }
  228. }
  229. if currentNeighbor != nil && currentNeighbor.RemoteDevice != "" {
  230. neighbors = append(neighbors, *currentNeighbor)
  231. }
  232. return neighbors
  233. }