/netd

NetD makes network device operations easy

Primary LanguageGoGNU General Public License v3.0GPL-3.0

NetD

Build Status

NetD 是深圳天元云科技开源的一款针对网络运维领域的命令执行器, 已成功对接十多种不同品牌版本的防火墙。

特性

  • 基于配置: 无需修改和重新编译源码即可支持一种新的品牌或版本的硬件
  • 多协议: 支持以 ssh, telnet 的方式连接设备
  • 支持模式: 可以在指定模式下执行指定命令, 以 Juniper 为例, 可以在普通模式下执行 show running-config, 在 configure 模式下执行 set xxx 等命令
  • 自动切换模式: 无需手动执行 configure, exit 等模式切换命令
  • 自动取消分页: 可以在配置中设置取消分页的命令, 如不指定,将使用各品牌默认的命令来取消
  • 自动翻页: 当出现 --More-- 时, 自动进行翻页获取完整配置
  • 多形式接口: 支持 jrpc, grpc
  • 单连接: 每台设备保持 1 个 ssh/telnet 连接, 并且做了并发控制,多个请求按顺序执行
  • 文件下载: netd 通过模拟 zmodem 协议,支持命令形式的文件下载, 如网御星云防火墙的配置下载命令 new export config.log encrypt off

如何运行

加载默认配置


go build .
# 以默认配置启动
./netd

加载指定配置


go build .
./netd --cfg /path/to/cfg.ini

基础知识

在修改 ini 配置之前,请确保熟悉 ini 的配置格式,并且遵守以下规则:

  1. 禁止使用行尾注释
行尾注释会被认为是 value 的一部分
host = 192.168.1.1 # ip addr
上述配置的 value 会被解析为 `192.168.1.1 # ip addr` , 而不是 `192.168.1.1`

如何添加一个新的设备支持

NetD 使用 ini 格式的配置文本, 以 Cisco 为例, 需要添加以下内容:

; --- asa ---

; (Required) 添加一个新的 section, section name 为匹配设备的厂商.型号.版本的正则表达式
[(?i)cisco\.asa[a-z]{0,}\.(9|[0-9]{1,})\..*]

; linebreak, default is unix
; (Optional) 指定换行符
linebreak = windows

; prompts
; (Required) 提供用于匹配 prompt 的正则表达式, prompt. 的前缀是固定的,后面的名称可以自定义
prompt.login = "[[:alnum:]]{1,}(-[[:alnum:]]+){0,}> $"
prompt.login_enable = [[:alnum:]]{1,}(-[[:alnum:]]+){0,}# $
prompt.configure_terminal = "[[:alnum:]]{1,}(-[[:alnum:]]+){0,}\(config\)# $"

; modes
; (Optonal) 指定登陆设备后的起始模式, 因为设备差异和用户配置上的差异,不同设备登陆之后的默认模式是不同的
; 未来代码优化后可支持自动识别登陆之后的模式
start = "login"
; (Required) 指定各个模式所使用的 prompt 规则, mode. 前缀固定
mode.login_or_login_enable = prompt.login, prompt.login_enable
mode.login = prompt.login
mode.login_enable = prompt.login_enable
mode.configure_terminal = prompt.configure_terminal

; transtions
; (Optional) 如果有多个模式,则必须指定, 提供模式之间切换时所执行的命令
transition.login_enable.configure_terminal = "configure terminal"
transition.configure_terminal.login_enable = "exit"

; error pattern
; (Required) 提供匹配命令执行错误的匹配规则
errs = "^ERROR: .*$"

; cancel more
; (Optional) 提供取消分页的命令及执行此命令所在的模式
cancel.login = "terminal pager 0", "terminal pager lines 0"

; debugging
; (Optional) 是否将命令的输出写入到文件
debug.cfg = false
; (Optional) 命令输出写入到文件的存放目录
debug.cfg_dir = /var/log/netd/cfgs

如何调用

    // go jrpc example
	client, err := net.Dial("tcp", "localhost:8188")
	// Synchronous call
	args := &protocol.CliRequest{
		Device:  "juniper-test",
		Vendor:  "juniper",
		Type:    "srx",
		Version: "6.0",
		Address: "192.168.1.252:22",
		Auth: protocol.Auth{
			Username: "xxx",
			Password: "xxx",
		},
		Commands: []string{"set security address-book global address WS-100.2.2.46_32 wildcard-address 100.2.2.46/255.255.255.255", "commit"},
		Protocol: "ssh",
		Mode:     "configure_private",
		Timeout:  30, // seconds
	}
	var reply protocol.CliResponse
	c := jsonrpc.NewClient(client)
	err = c.Call("CliHandler.Handle", args, &reply)

check jrpc test file for more details

常见问题

  1. 命令执行错误,接口却没报错

错误输出没有被 NetD 捕捉到,可以在配置文件中的 errs key 里添加适当的正则匹配错误信息。

  1. 命令执行超时

错误信息里有 timeout 字样

NetD 的基本原理是模拟人的操作行为,我们手动操作命令行时,是通过 prompt 的出现来确认命令的执行已经结束,NetD 是一样的。 解决思路: 将 log 的 level 设置为 DEBUG , 复现问题,如果观察到日志在打印完如 [huawei_USG] 这类 prompt 之后没有其它输出,直到超时日志出现,则一般是 prompt 的匹配有问题,可以通过添加新的 prompt 或者修改已有的 prompt 来解决,最快速的解决方式是将整个 prompt 复制, 作为正则并放进配置里。

netd: handle req timeout

接口返回的内容是上述字样 , 没有其它的内容。没有其它内容,说明 netd 可能卡在连接设备那里了。一般是网络问题,设备本身就连不上,可以在 netd 所在的宿主机去手动连接网络设备,确认能够正常登陆

  1. 命令不支持

不同型号版本的硬件所使用的命令差异较大,即使是同一品牌,同一型号的硬件,在不同系统版本里所使用的命令也有差异。直接在配置文件里修改原有命令,或者新增一个只对指定类型/版本设备生效的 section 来解决。

  1. 修改配置后没生效

重启 NetD. NetD 不支持动态修改配置,需要手动重启完成配置的更新。注意,重启会导致正在执行的命令中断,所以传入 NetD 的命令必须是可重复执行的。

  1. 命令还未执行完成就返回了

如果 prompt 的正则写的并不严谨,则可能会将正常输出识别为 prompt, 让程序错误地认为命令执行已经结束了,因而结束执行返回结果。解决的方法是使用更严谨的正则,甚至直接使用原文本来匹配 prompt, 也可以在 excludes key 里添加用于排除的正则,比如, [huawei_USG-object-address-set-demo_10.1.1.3] 被错误识别成了 prompt, 可以在 excludes 里添加一个正则 -object-address-set- 来把这种文本排除。

  1. 加密算法协商错误

在 ssh 连接阶段,client/server 会先协商加密算法,当有一方不支持对方提供的算法时就会出现错误。可以在 server 端解决,也可以在 client 端解决。倾向于在 client 端添加对应的算法来解决,具体方式是在配置文件的 ssh section 中的 ciphersexchanges key 中添加。

  1. 连接失败

dial 19.168.1.127:22 error: dial tcp 19.168.1.127:22: i/o timeout

检查 IP 是否写错;检查 telnet 设备的 22 端口是否连通

no route to host

检查设备能否 ping 通

ssh: handshake failed: ssh: unable to authenticate, attempted methods [none password], no supported methods remain

一般是用户名或者密码不对!

Roadmap

  • 添加 prometheus metrics
  • [] 支持集群