使用Python管理网络设备( 四 )


4.2 在Python中使用Telnet协议Telnet是TCP/IP协议栈中最早可用的协议之一,主要用来在服务器和客户端之间建立连接、交换数据 。服务器端监听TCP端口23,等待客户端的连接请求 。
在下面的例子中,我们将创建一个Python脚本作为Telnet客户端,拓扑中的其他路由器和交换机则作为Telnet服务器 。Python原生的telnetlib库已经支持Telnet,所以不需要另外安装 。
客户端对象可以通过telnetlib模块中的Telnet()类实例化创建 。通过这个对象,我们能够使用telnetlib中的两个重要函数——read_until()(用于读取输出结果)和write()(用于向远程设备写入内容) 。这两个函数用来和Telnet连接交互,从Telnet连接读取或向Telnet连接写入数据 。
还有一点非常关键,使用read_until()读取Telnet连接的内容之后缓冲区会被清空,无法再次读取 。因此,如果在后面的处理中还会用到之前读取的重要数据,需要在脚本里将其另存为变量 。


Telnet数据以明文形式发送,因此通过“中间人攻击”可以捕获并查看到Telnet数据,如用户信息和密码 。即便如此,一些服务提供商和企业仍然在使用它,只是他们会集成VPN和radius/tacacs协议,以提供轻量级和安全的访问方式 。
让我们一步步分析这个脚本 。
(1)在Python脚本中导入telnetlib模块,在变量中定义用户名和密码 。代码如下 。
import telnetlibusername = "admin"password = "access123"enable_password = "access123"(2)定义一个变量,用来和远程主机建立连接 。注意,只需要提供远程主机的IP地址,不用在连接建立过程中提供用户名或密码 。
cnx = telnetlib.Telnet(host="10.10.88.110") #here we're telnet toGateway(3)通过读取Telnet连接返回的输出并搜索“Username:”关键字来提供Telnet连接的用户名 。然后写入管理员用户名 。如果需要,用同样的方法输入Telnet密码 。
cnx.read_until("Username:")cnx.write(username + "n")cnx.read_until("Password:")cnx.write(password + "n")cnx.read_until(">")cnx.write("en" + "n")cnx.read_until("Password:")cnx.write(enable_password + "n")

Telnet连接建好之后,在脚本中加上控制台提示符非常重要;否则,连接将陷入死循环 。接着Python脚本就会超时并出现错误 。
(4)向Telnet连接写入show ip interface brief命令并开始读取返回内容,直到出现路由器提示符(#)为止 。通过以下命令可以得到路由器的接口配置 。
cnx.read_until("#")cnx.write("show ip int b" + "n")output = cnx.read_until("#")print output完整的脚本如下所示 。
使用Python管理网络设备

文章插图
 
脚本运行结果如下所示 。
使用Python管理网络设备

文章插图
 
注意,在输出中包含了执行的命令show ip int b,并且在stdout中输出和返回了路由器提示符"R1#" 。可以使用内置的字符串函数(如replace())从输出中清除它们 。
cleaned_output = output.replace("show ip int b","").replace("R1#","")print cleaned_output
使用Python管理网络设备

文章插图
 
你可能已经注意到脚本中使用了密码并将密码以明文形式写下来,这样做显然是不安全的 。同时,在Python脚本中使用硬编码也不是好习惯 。在下一节中,我们将学习如何隐藏密码并设计一种机制,从而在脚本运行时要求用户输入密码 。
此外,如果要执行那些输出结果可能跨越多个页面的命令(如show running config),则需要在连接到设备之后和发送命令之前,先通过发送termindl length 0来禁用分页 。
使用telnetlib推送配置在上一节中,我们通过执行show ip int brief简单介绍了telnetlib的操作过程 。现在我们要用telnetlib将VLAN配置推送到实验室网络拓扑中的4台交换机 。使用Python的range()函数创建一个VLAN列表,遍历列表将VLAN ID推送到当前交换机 。注意,我们将交换机的IP地址放到了另一个列表中,使用外部for循环来遍历这个列表 。同时使用内置模块getpass隐藏控制台中的密码,在脚本运行时提示用户输入密码 。
#!/usr/bin/pythonimport telnetlibimport getpassimport timeswitch_ips = ["10.10.88.111", "10.10.88.112", "10.10.88.113","10.10.88.114"]username = raw_input("Please Enter your username:")password = getpass.getpass("Please Enter your Password:")enable_password = getpass.getpass("Please Enter your Enable Password:")for sw_ip in switch_ips:print "n#################### Working on Device " + sw_ip + "####################"connection = telnetlib.Telnet(host=sw_ip.strip())connection.read_until("Username:")connection.write(username + "n")connection.read_until("Password:")connection.write(password + "n")connection.read_until(">")connection.write("enable" + "n")connection.read_until("Password:")connection.write(enable_password + "n")connection.read_until("#")connection.write("config terminal" + "n") # now i'm in config modevlans = range(300,400)for vlan_id in vlans:print "n********* Adding VLAN " + str(vlan_id) + "**********"connection.read_until("#")connection.write("vlan " + str(vlan_id) + "n")time.sleep(1)connection.write("exit" + "n")connection.read_until("#")connection.close()


推荐阅读