我想要在PHP中使用Telnet!
这篇文章是2015年NetOpsCoding圣诞日历的第23篇文章。
初次见面。我在某通信公司从事网络运营工作。我将给你讲一个关于在圣诞前夜与路由器交谈的令人伤感的故事。
首先在世界各地,NETCONF/YANG等技術正受到關注,但在一些老牌通信設備,如Cisco 7206VXR、Catalyst 2950等仍在現場穩定運行,且未來也將繼續使用Telnet進行命令行界面(CLI)控制。主流的程式語言,如Perl、Python、Ruby,都提供了專為Telnet設計的函式庫,但PHP卻沒有相應的支援。
在 Packagist 上有一个 Telnet 客户端库,但由于提示符的不同,无法登录到路由器等设备,因此这次我扩展了它,创建了一个可以通过 PHP 从 Telnet 登录到路由器的库,现在我将介绍给大家。
关于 Telnet 库
可以享受此优惠。
-
実行環境要件 :
-
- 実行環境要件 :
PHP 5.6以上(PHP 7.0対応)
Composer
対象ホスト :
Linux/UNIXサーバー全般
Cisco IOS, IOS-XE, IOS-XR ルーター・スイッチ
Juniper JUNOS ルーター・スイッチ
AlaxalA, HITACHI ルーター・スイッチ
开发/验证环境
-
PHP実行環境
- PHP実行環境
CentOS 7.2
Apache 2.4
PHP 7.0
テスト済み接続先
RHEL 5
RHEL 6
CentOS 7
Cisco 7206VXR (IOS 12.3 / 12.4)
Cisco Catalyst 2950 / 2960 / 3560 / 3750 (IOS 12.2)
Cisco 7604 / 7609 (IOS 12.2)
Cisco ASR 1001 / 1002 / 1006 (IOS-XE 15.1)
Cisco CRS-1 / CRS-3 (IOS-XR 4.0)
Juniper T640 / T1600 / T4000 (JUNOS 12.3)
Juniper E120 / E320 (JUNOS 12.3)
Juniper MX240 (JUNOS 12.3)
HITACHI GR4000 (ROUTE-OS 9)
AlaxalA AX7800R (OS-R 10.10)
请提供以下选项的来源。
-
GitHub : https://github.com/miyahan/Telnet
- GitHub : https://github.com/miyahan/Telnet
Packagist : https://packagist.org/packages/miyahan/telnet
安装步骤由于使用Composer,因此需要提前安装它。请访问https://getcomposer.org/进行安装。
首先创建 composer.json 文件,并按以下方式描述库。
{
"require": {
"miyahan/telnet": "dev-master"
}
}
创建 composer.json 文件后,执行 composer install 命令以安装库文件。
$ composer install
Loading composer repositories with package information
Installing dependencies (including require-dev)
- Installing miyahan/telnet (dev-master e1003c2)
Cloning e1003c27e422772962d849187c31f8ace38e8753
Writing lock file
Generating autoload files
安装库时,会同时创建自动加载器,以后需要使用时,请使用require访问。
使用方法:通过Telnet连接到Juniper JUNOS路由器并获取信息。
<?php
require 'vendor/autoload.php';
try {
$telnet = new \miyahan\network\Telnet('10.0.0.1');
$telnet->connect();
$telnet->login('root', 'hogehoge', 'junos');
$telnet->exec('set cli screen-length 0');
$telnet->setPrompt('root>');
$result = $telnet->exec('show system uptime');
echo $result;
} catch (Exception $e) {
echo $e->getMessage();
}
$ php telnet-juniper.php
show system uptime
scc-re0:
--------------------------------------------------------------------------
Current time: 2015-12-16 03:26:55 JST
System booted: 2011-06-21 14:00:44 JST (234w0d 13:26 ago)
Protocols started: 2011-06-21 15:04:17 JST (234w0d 12:22 ago)
Last configured: 2015-10-06 11:16:17 JST (10w0d 16:10 ago) by root
3:26AM up 1638 days, 13:26, 1 user, load averages: 0.04, 0.23, 0.21
lcc0-re0:
--------------------------------------------------------------------------
Current time: 2015-12-16 03:26:55 JST
System booted: 2011-06-21 14:01:09 JST (234w0d 13:25 ago)
Last configured: 2015-10-06 11:16:11 JST (10w0d 16:10 ago) by root
3:26AM up 1638 days, 13:26, 0 users, load averages: 0.00, 0.02, 0.06
/// snip ///
<?php
require 'vendor/autoload.php';
try {
$telnet = new \miyahan\network\Telnet('10.0.0.1');
$telnet->connect();
$telnet->login('root', 'hogehoge', 'junos');
$telnet->exec('set cli screen-length 0');
$telnet->setPrompt('root>');
$result = $telnet->exec('show system uptime');
echo $result;
} catch (Exception $e) {
echo $e->getMessage();
}
$ php telnet-juniper.php
show system uptime
scc-re0:
--------------------------------------------------------------------------
Current time: 2015-12-16 03:26:55 JST
System booted: 2011-06-21 14:00:44 JST (234w0d 13:26 ago)
Protocols started: 2011-06-21 15:04:17 JST (234w0d 12:22 ago)
Last configured: 2015-10-06 11:16:17 JST (10w0d 16:10 ago) by root
3:26AM up 1638 days, 13:26, 1 user, load averages: 0.04, 0.23, 0.21
lcc0-re0:
--------------------------------------------------------------------------
Current time: 2015-12-16 03:26:55 JST
System booted: 2011-06-21 14:01:09 JST (234w0d 13:25 ago)
Last configured: 2015-10-06 11:16:11 JST (10w0d 16:10 ago) by root
3:26AM up 1638 days, 13:26, 0 users, load averages: 0.00, 0.02, 0.06
/// snip ///
执行 set cli screen-length 0 命令以一次返回结果是关键。然后使用 preg_match 等字符操作函数来提取所需信息。
使用方法:Telnet到Cisco IOS路由器以获取信息
<?php
require 'vendor/autoload.php';
try {
$telnet = new \miyahan\network\Telnet('10.0.0.2');
$telnet->connect();
$telnet->login('root', 'hogehoge', 'ios');
$telnet->exec('terminal length 0');
$telnet->exec('enable'."\r\n".'hogehoge');
$telnet->setPrompt('router#');
$result = $telnet->exec('show environment all');
echo $result;
} catch (Exception $e) {
echo $e->getMessage();
}
$ php telnet-cisco.php
show environment all
Power Supplies:
Power Supply 1 is Zytek DC Power Supply. Unit is on.
Power Supply 2 is Zytek DC Power Supply. Unit is on.
Temperature readings:
chassis inlet measured at 28C/82F
chassis outlet 1 measured at 29C/84F
chassis outlet 2 measured at 31C/87F
chassis outlet 3 measured at 32C/89F
Voltage readings:
+3.45 V measured at +3.50 V
+5.15 V measured at +5.27 V
+12.15 V measured at +12.34 V
-11.95 V measured at -11.95 V
Envm stats saved 74822 time(s) since reload
<?php
require 'vendor/autoload.php';
try {
$telnet = new \miyahan\network\Telnet('10.0.0.2');
$telnet->connect();
$telnet->login('root', 'hogehoge', 'ios');
$telnet->exec('terminal length 0');
$telnet->exec('enable'."\r\n".'hogehoge');
$telnet->setPrompt('router#');
$result = $telnet->exec('show environment all');
echo $result;
} catch (Exception $e) {
echo $e->getMessage();
}
$ php telnet-cisco.php
show environment all
Power Supplies:
Power Supply 1 is Zytek DC Power Supply. Unit is on.
Power Supply 2 is Zytek DC Power Supply. Unit is on.
Temperature readings:
chassis inlet measured at 28C/82F
chassis outlet 1 measured at 29C/84F
chassis outlet 2 measured at 31C/87F
chassis outlet 3 measured at 32C/89F
Voltage readings:
+3.45 V measured at +3.50 V
+5.15 V measured at +5.27 V
+12.15 V measured at +12.34 V
-11.95 V measured at -11.95 V
Envm stats saved 74822 time(s) since reload
已经成功获得。在这边,事先发出终端长度为0的命令是关键。
故障解決
当从网上访问时,Telnet连接失败。当SELinux启用时,Telnet连接会失败。
$ curl http://localhost/telnet.php | more
Cannot connect to 10.0.0.1 on port 23
$ sudo tail /var/log/audit/audit.log
type=AVC msg=audit(1450217222.842:111): avc: denied { name_connect } for pid=2553 comm="httpd" dest=23 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:telnetd_port_t:s0 tclass=tcp_socket
$ curl http://localhost/telnet.php | more
Cannot connect to 10.0.0.1 on port 23
$ sudo tail /var/log/audit/audit.log
type=AVC msg=audit(1450217222.842:111): avc: denied { name_connect } for pid=2553 comm="httpd" dest=23 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:telnetd_port_t:s0 tclass=tcp_socket
在这种情况下,请禁用SELinux或使用下面的命令允许httpd对TCP套接字连接。
$ sudo setsebool -P httpd_can_network_connect 1
慢慢的命令超时了。默认情况下,如果等待提示超过10秒,就会发生超时。
$ php telnet.php
Couldn't find the requested : 'router#' within 10 seconds
$ php telnet.php
Couldn't find the requested : 'router#' within 10 seconds
如果要执行需要花费较长时间来响应的处理,比如show tech-support ,请在构造函数的第四个参数中指定一个较长的超时时间(以秒为单位)。
$telnet = new \miyahan\network\Telnet('10.10.10.10', 23, 10, 300.0);
最后尽管从PHP进行Telnet的内容并不受欢迎,但在我的公司里,我们利用使用PHP编写的Web应用程序来访问路由器和交换机,并能够将命令的响应结果整理并显示出来,这种可视化工具非常活跃。我希望将来能够介绍这个案例。
如果可以的话,请试用一下。也期待您的Pull Request。