LoginSignup
17
15

More than 5 years have passed since last update.

PHPでもTelnetがしたい!

Last updated at Posted at 2015-12-22

本記事は NetOpsCoding Advent Calendar 2015、23日目の記事です。

はじめまして。とある通信会社でネットワークの運用業務をしています。クリスマス・イヴイヴに「ルーターとお喋りする」という悲しいお話をします。

はじめに

世間では NETCONF/YANG などが話題ですが、Cisco 7206VXR、Catalyst 2950 といった生きた化石 歴史ある通信機器が現役な現場では未だ(そしてこれからも) Telnet によるCLI制御が主役です。Perl、Python、Ruby などの主要なLL言語では 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)

ソース

インストール方法

Composer を使いますので、予めインストールしておきます → https://getcomposer.org/

まず composer.json を作り、以下のようにライブラリを記述します。

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 して使います。

使い方:Juniper JUNOS ルータにTelnetし情報を取得する

telnet-junos.php
<?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();
}
(result)
$ 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 などの文字操作関数を使ってよしなに情報を抽出します。

使い方:Cisco IOS ルータにTelnetし情報を取得する

telnet-cisco.php
<?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();
}
(result)
$ 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

取得できました。こちらでも予め terminal length 0 コマンドを発行しておくことがポイントです。

トラブルシュート

Webからアクセスすると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 など、応答に時間がかかる処理を実行する場合は、コンストラクタの第4引数にタイムアウト時間(秒)を長めに指定してください。

telnet-longtime.php
$telnet = new \miyahan\network\Telnet('10.10.10.10', 23, 10, 300.0);

おわりに

PHP から Telnet するという誰得な内容でしたが、私の会社では PHP で書かれたWebアプリからルーターやスイッチにアクセスし、コマンドの応答結果を整形して表示するといった見える化系ツールで活躍しています。その事例も今後紹介できればなと思っています。

よろしければ使ってみてください。プルリクもお待ちしています。

17
15
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
15