我想要在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実行環境

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

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 ///

执行 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

已经成功获得。在这边,事先发出终端长度为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

在这种情况下,请禁用SELinux或使用下面的命令允许httpd对TCP套接字连接。

$ sudo setsebool -P httpd_can_network_connect 1

慢慢的命令超时了。默认情况下,如果等待提示超过10秒,就会发生超时。

$ 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。

bannerAds