Cisco IOS XE 隠しコマンドを楽しむ

# はじめに
この記事はシスコの有志による Cisco Systems Japan Advent Calendar 2018 の 9 日目として投稿しています。

- 2017年版: https://qiita.com/advent-calendar/2017/cisco
- 2018年版: https://qiita.com/advent-calendar/2018/cisco

# IOS XE 新機能 - 隠しコマンドアクセス

## コマンドラインとオプション
Cisco IOSやIOS XEは、コマンドラインを使った設定や操作が可能です。シスコのマニュアルにはコマンドの使い方が明記されており、それに従ってルータやスイッチを操作します。公式なコマンドは、タブキーによる補完や、クエスチョンマーク「？」によって一覧が確認できるなど便利です。

```cisco
Cat9300-01#show version ?
  installed    Show all installed platform software versions
  provisioned  Show all provisioned platform software versions
  running      Show all running platform software versions
  switch       Switch
  |            Output modifiers
  <cr>         <cr>
```

一方、公式にサポートされているコマンドとは別に、いわゆる「隠しコマンド」もそこそこ存在しており、開発者がテスト時に追加したまま消し忘れたコマンドや、トラブル時のサポート用として隠されているマニアックなコマンド、どうでもいいゴミ隠しコマンドなどなどが存在しています。実際にCCIEの勉強の際にも、知っていると理解が深まる隠しコマンドなどもあるようです。

ゲームと同じで隠しコマンドをたくさん知っていると、ちょっと他人に自慢したくなったりする、そんな人もいるかもしれません！ **隠しコマンドには夢があります。****隠しコマンドはモテます（無保証）。**

「Cisco IOS Hidden Command」で検索すると、様々なサイトが見つかります。

- https://www.ciscozine.com/undocumented-cisco-commands/
- https://ja.scribd.com/doc/228525468/Undocumented-and-Secret-Cisco-Ios-Commands-IPexpert-ir
- https://ciscotips.wordpress.com/2009/08/07/undocumented-ios-commands/

## 隠しコマンドとセキュリティ

時代は変わり、隠しコマンドはセキュリティリスクと考えられるようになりました。実際に、隠しコマンドを利用したいたずらを行う人が現れるなど、隠れているが故のリスクの方が注視され、シスコは対策を取り始めたようです。

IOS XEバージョン16.8.1以降で、「Accessing Hidden Commands」なる新機能（？）が登場しました。隠しコマンドへのアクセス方法が、公式マニュアルに登場して、もはや隠しコマンドかどうかも謎ですが、ともかく、ヘルプを出すようにしたり、隠しコマンドを実行した際に、Syslogを出力させたりと、セキュリティリスクを低減させる取り組みのようです。

[Release Notes for Cisco Catalyst 9300 Series Switches, Cisco IOS XE Fuji 16.8.x](
https://www.cisco.com/c/en/us/td/docs/switches/lan/catalyst9300/software/release/16-8/release_notes/ol-16-8-9300.html#id_65400)

> Starting with Cisco IOS XE Fuji 16.8.1a, hidden commands are available under:
>
Category 1—Hidden commands in privileged or User EXEC mode. Begin by entering the service internal command to access these commands.
>
Category 2—Hidden commands in one of the configuration modes (global, interface and so on). These commands do not require the service internal command.
>
Further, the following applies to hidden commands under Category 1 and 2:
>The commands have CLI help. Entering enter a question mark (?) at the system prompt displays the list of available commands.
>
The system generates a %PARSER-5-HIDDEN syslog message when the command is used. For example:
*Feb 14 10:44:37.917: %PARSER-5-HIDDEN: Warning!!! 'show processes memory old-header ' is a hidden command. 
Use of this command is not recommended/supported and will be removed in future.

showコマンドや、testコマンドは、EXECモードで実行するのが基本ですが、EXECモードでの隠しオプションについては、**service internal**を設定することで、露出できるようになったとのことです。

## 実行例 - ヘルプを出す

実際に確認してみます。show processes コマンドの例では、公式なオプションは、7つあります。

```cisco:通常
Cat9300-01#show processes ?
  <1-2147483647>  IOS(d) Process Number
  cpu             Show CPU usage per IOS(d) process
  heapcheck       Show IOS(d) scheduler heapcheck configuration
  history         Show ordered IOS(d) process history
  memory          Show memory usage per IOS(d) process
  platform        Show information per IOS-XE process
  timercheck      Show IOS(d) processes configured for timercheck
  |               Output modifiers
  <cr>            <cr>
```

「Accessing Hidden Commands」のために、**service internal**を設定

```
Cat9300-01(config)#service internal
```

隠しオプションが、表示されました＼(^O^)／
オプションが、11個確認できます。したがって、4つが隠しオプションということですね。

```cisco:隠しコマンド含んだ出力
Cat9300-01#show processes ?
  <1-2147483647>  IOS(d) Process Number
  all-events      Show all notifications
  bootup-init     Show system init time
  bootup-time     Show system bootup time
  cpu             Show CPU usage per IOS(d) process
  events          Show events for which IOS(d) processes want notification
  heapcheck       Show IOS(d) scheduler heapcheck configuration
  history         Show ordered IOS(d) process history
  memory          Show memory usage per IOS(d) process
  platform        Show information per IOS-XE process
  timercheck      Show IOS(d) processes configured for timercheck
  |               Output modifiers
  <cr>            <cr>
```

## もっと知りたい

さて、とりあえずservice internalを設定した状態と、設定していない状態（no service internal）で、様々なshowコマンドとクエスチョンマークをうちまくって、目でDiffをしながらニヤニヤするのは普通だと思いますが、10分くらいするとイライラしてきます。もっと楽して隠しコマンドオプションが知りたい... 使うことはほぼないけど... とりあえず知りたい... 

そこで、[IOS XEのGuest shell](https://qiita.com/kikuta1978/items/1739d7d7063a20b1736f)を使って隠しコマンドオプションを調べるスクリプトを作ってみました。（暇やな〜）

手元にあったCatalyst 9300は、IOS XE16.8.1aで動いていたので、このまま利用しました。余談ですが、[Catalyst 9300](https://www.cisco.com/c/ja_jp/products/collateral/switches/catalyst-9300-series-switches/datasheet-c78-738977.html)は、[Catalyst 3850](https://www.cisco.com/c/ja_jp/products/collateral/switches/catalyst-3850-series-switches/data_sheet_c78-720918.html)の後継の固定構成型L3 スイッチです。ゲストシェルの設定や使い方は、別の記事を参照ください。日本語のマニュアルもあるようです。

- [Programmability Configuration Guide, Cisco IOS XE Gibraltar 16.10.x Chapter: Guest Shell](https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/1610/b_1610_programmability_cg/guest_shell.html)
- [Cisco IOS XE Everest 16.6.x プログラマビリティ コンフィギュレーション ガイド
](https://www.cisco.com/c/ja_jp/td/docs/ios-xml/ios/prog/configuration/166/b_166_programmability_cg/b_166_programmability_cg_chapter_00.html)
- [IOS/IOS-XE 運用管理機能アップデート](https://www.slideshare.net/CiscoJapan/iosiosxe)

```
Cat9300-01#sh ver | i IOSXE  
Cisco IOS Software [Fuji], Catalyst L3 Switch Software (CAT9K_IOSXE), Version 16.8.1a, RELEASE SOFTWARE (fc1)
*    1 40    C9300-24P          16.8.1a           CAT9K_IOSXE           INSTALL
Cat9300-01#
Cat9300-01#guestshell run bash
[guestshell@guestshell ~]$
[guestshell@guestshell ~]$ uname -a
Linux guestshell 4.4.111 #1 SMP Wed Feb 14 20:30:50 PST 2018 x86_64 x86_64 x86_64 GNU/Linux
[guestshell@guestshell ~]$
[guestshell@guestshell ~]$ python -V
Python 2.7.5
[guestshell@guestshell ~]$ cd /flash/kikuta
[guestshell@guestshell kikuta]$
[guestshell@guestshell kikuta]$ ls
hiddenop.py
```

# On-box python を活用した IOS XE CLI 隠しオプションの調査

## スクリプトのポイント

- IOS XE on-box python で IOS XE コマンドを利用できる cli モジュールを利用
- **service internal** の設定あり・なし時のオプションをそれぞれリスト化し、比較
- もともと入っていたpython2.7.5を利用

```python:hiddenop.py

import cli

service_internal = ["service internal"]
no_service_internal = ["no service internal"]
hiddencli_list = []
cli_list = []

x = raw_input('Please input exec command with ? >')
print "\n\n *** Hidden CLI Information - ### ", x  ," ### *** \n\n"

cli.configure(service_internal)
output_hidden = cli.execute(x)

for hidden in output_hidden.split("\n"):
    hiddencli_list.append(hidden.split(' ')[2])

cli.configure(no_service_internal)
output = cli.execute(x)

for cli in output.split("\n"):
    cli_list.append(cli.split(' ')[2])

hidden_option = list(set(hiddencli_list) - set(cli_list))

for ho in sorted(hidden_option):
    print ho

print "\n\n *************** \n\n" 
print "Number of Hidden Command in exec mode is :", len(hidden_option) 
print "\n\n *************** \n\n"
```

Catalyst 9300の GuestShell上で、先のスクリプトを実行します。デフォルトでvimが使えるので、直接作成できます。

## 実行例

「show ip route ?」 の隠しオプションは6つあるようです。

```

[guestshell@guestshell kikuta]$ python hiddenop.py 
Please input exec command with ? >show ip route ?

 *** Hidden CLI Information - ###  show ip route ?  ### *** 

all-rdbs
cidr
majornets-only
replicate
static-table
tree

 *************** 
Number of Hidden Command in exec mode is : 6
 *************** 
[guestshell@guestshell kikuta]$ 
```

「show ip ospf ?」 の隠しオプションは5つあるようです。

```
[guestshell@guestshell kikuta]$ python hiddenop.py 
Please input exec command with ? >show ip ospf ?    

 *** Hidden CLI Information - ###  show ip ospf ?  ### *** 

bad-checksum
delete-list
internal
maxage-list
route-list

 *************** 
Number of Hidden Command in exec mode is : 5
 *************** 
[guestshell@guestshell kikuta]$ 
```

「show ip sla ?」 の隠しオプションは4つあるようです。

```
[guestshell@guestshell kikuta]$ python hiddenop.py 
Please input exec command with ? >show ip sla ?

 *** Hidden CLI Information - ###  show ip sla ?  ### *** 

collection-statistics
distribution-statistics
operational-state
totals-statistics

 *************** 
Number of Hidden Command in exec mode is : 4
 *************** 
[guestshell@guestshell kikuta]$ 
```


隠しテストコマンドは、52個あるようです。

```
[guestshell@guestshell kikuta]$ python hiddenop.py 
Please input exec command with ? >test ?

 *** Hidden CLI Information - ###  test ?  ### *** 

atom
autonomic
bridge-domain
buffer
cce
cef
coap
cops
data-descriptor
dhcp
dummy
eci
eigrp
event
frontend-controller
frr-manager
ipam
ipc
ipv6
l2vpn
license
lim
logging
mac-table-mibs
mdns
memory
mgd-timer
mka
mrib
ngdns
nhrp
odb
onep
parser
platform-aaa
policy-manager
ppp
rfd
rmon
rtty
scheduler
sdb
segment-routing
service-overlay
service-routing
srvc
stack-power
subscriber
tcp
timer-wheel
vrrs
wccp

 *************** 
Number of Hidden Command in exec mode is : 52
 *************** 
[guestshell@guestshell kikuta]$ 
```
いい感じです（謎

# IOS CLI を実行するための Python モジュール

On-box pythonから、CLIライブラリを使ったコマンドアクセスについて調べてみると、意外と便利に使えるものもありそうです。特に、cli.configure() と cli.configurep() については、実行コマンドとその結果を、複数行設定しようとした場合にはそれぞれに対し、実行結果と失敗した場合にはその理由をタプルまたは標準出力の形で表示してくれます。

CLIのデメリットの一つは、自動化の観点では大量の設定行を投入した場合にそれぞれの行の実行結果や失敗した場合の理由が構造データとして取得できないことがありましたが、これを使えば旧来のコマンドによる自動化を行いつつ、細かなエラー制御を入れるといった折衷案も実現できそうです。

もちろん、On-boxであっても、内部からCLIをぶん回すよりも、ncclient等を使ってモデルドリブンなnetconf/yangで自動化してしまうのが一番かっこいいのは言うまでもありません。しかし一方で、コマンドの方が多機能な場合が多いことも現実です。

- cli.cli(command) ... 複数コマンドを実行して、結果をリターン（変数に入れて処理するなど）
- cli.clip(command) ... 複数コマンドを実行して、結果を標準出力（stdout）
- cli.execute(command) ... 一つのEXECコマンドを実行し、結果をリターン（変数に入れて処理するなど）
- cli.executep(command) ... 一つのEXECコマンドを実行し、結果を標準出力（stdout）
- cli.configure(command) ... コンフィグモードから設定を行い、設定コマンドと結果をタプルで返す
- cli.configurep(command) ... コンフィグモードから設定を行い、設定コマンドと結果を標準出力（stdout）

詳細は、以下のマニュアルに記載があります。
[Programmability Configuration Guide, Cisco IOS XE Gibraltar 16.10.x Chapter: Python API](https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/1610/b_1610_programmability_cg/python_api.html)

以下、いくつか実行例です。

ホスト名変更の設定投入時に、投入コマンドと結果がタプルでリターンしています。

```
[guestshell@guestshell ~]$ python
Python 2.7.5 (default, Jun 17 2014, 18:11:42) 
[GCC 4.8.2 20140120 (Red Hat 4.8.2-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import cli
>>> cli.configure(["hostname Cat9300-Demo","end"])
[ConfigResult(success=True, command='hostname Cat9300-Demo', line=1, output='', notes=None), ConfigResult(success=True, command='end', line=2, output='', notes=None)]
```

ホスト名変更の設定投入時に、投入コマンドと結果が標準出力されています。

```
>>> cli.configurep(["hostname Cat9300-Demo2","end"])
Line 1 SUCCESS: hostname Cat9300-Demo2
Line 2 SUCCESS: end
```

無効なコマンドを含む複数のコマンドを投入時に、エラーのコマンドとその理由が標準出力されています。

```
>>> cli.configurep(["interface gi 1/0/2", "aa", "end"])
ConfigError: There was a problem with 1 commands while configuring the device.
Line 1 SUCCESS: interface gi 1/0/2
Line 2 FAILURE: aa (PARSE_ERROR_NOMATCH)
**CLI Line # 2: aa
**CLI Line # 2:   ^
**CLI Line # 2: % Invalid input detected at '^' marker.

Line 3 SUCCESS: end
>>>
```

# 感想
API中心のトレンドは疑う余地はありませんが、コマンド自体が無くなるわけではありません。装置を起点にした、より詳しい調査や状況把握には、コマンドが最も有益で、今後も使われていくでしょう。ただし、あらゆる人にとってコマンドが最初の入り口ではなくなってくるのは確実で、GUIやAPIが多くの人にとって便利で扱いやすいインターフェースとして使われ、コマンドは、一部のマニアのものになっていくのかもしれません。

だからこそ、コマンドを楽しむゆとりが味わい深いともいえます！

# おまけ
ここまで読んで頂いてどうもありがとうございました。マニアな方は、上のサンプルで既に気づかれた方もいるかもしれませんが、 **service internal** を投入しても、有名な（？）テストコマンドである **test crash** が出力されてません。「Accessing Hidden Commands」の項をよく読むと、必ずしもすべての隠しコマンドが出力されるわけではないそうです。残念！

ということで、隠しコマンドのさらなる隠しコマンドはどの程度あるんだろうか...と、しょうもないことを考えてしまいました。お粗末様でしたm(__)m

※くれぐれも、隠しコマンドでいたずらしないでくださいね！

```
Cat9300-Demo2#test crash  

WARNING: Command selections marked with '(crash router)' will crash
         router when issued. However a selection 'C' will need to
         be issued IMMEDIATELY before these selections to enable them.


Type the number for the selected crash:
--------------------------------------
 1  (crash router) Bus Error, due to invalid address access
 2  (crash router) Bus Error, due to parity error in Main memory
 3  (crash router) Bus Error, due to parity error in I/O memory
 4  (crash router) Address Error, due to fetching code from odd address
 5  (crash router) Jump to zero
 6  (crash router) Software forced crash
 7  (crash router) Illegal read of address zero
 8  (crash router) Divide by zero
 9  (crash router) Corrupt memory
 A  (crash router) Test assert() failure
 C  Enable crash router selection marked with (crash router)
 D  (crash router) Via duplicate free()
 P  (crash router) Test assert_production() failure
 R  (crash router) User enter read bus error address
 U  (crash router) User enter write bus error address
 W  (crash router) Software watchdog timeout (*** Watch Dog Timeout ***)
 w  (crash router) Process watchdog timeout (SYS-2-WATCHDOG)
 d  Disable crashinfo collection
 e  Enable crashinfo collection
 i  Display contents of current crashinfo flash file
 m  Write crashinfo on crashinfo RAM
 n  Change crashinfo flash file name
 q  Exit crash menu
 s  Save crashinfo to current crashinfo flash file
 c  Close current crashinfo flash file
 t  Write crashinfo on console TTY
 N  Register/deregister from crashinfo interesting addr notification service
 I  (crash router) Cause exception, while refering to data for interesting address notify
 X  (crash router) Execute bit checks
 x  Exit crash menu
? 
Dec  8 08:29:01.860 UTC: %PARSER-5-HIDDEN: Warning!!! ' test crash ' is a hidden command. Use of this command is not recommended/supported and will be removed in future. 
```
Hiddenコマンドを実行したやろｺﾞﾙｧというSyslog（上の実行例の最後の行）も、出力されるようになりました。これも新機能だそうです。

# 免責事項

本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、シスコの意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、シスコや他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任からシスコを免責することに同意したものとします。