Edited at

SMS で LTE 付き Cisco ルータを操作する

More than 1 year has passed since last update.


これは何?

Cisco 1100 LTE のSMS と IOS-XE EEMで遊ぶの続編です。前回はSIMのセットアップと、EEMと組み合わせた簡単な動作確認を行い、以下のようにまとめました。


今回は、SMSのメッセージに応じて動作を振り分けるところまでやってませんが、「SyslogでSMS受信」-> 「SMSの内容を確認」-> 「EEMのアクションを分岐」といった流れも、比較的簡単に実装できそうです。ルータに送るSMSのメッセージに応じて、ルータ内部の動作をカスタムで実行したり、ルータに調査して応答させるコマンドをSMSで分けたり、トラブルシュートのパターンを操作したり、といったわりと実用的な使い方も考えられそうです。時間ができたら、やってみたいと思います!


今回は、EEMとTclスクリプトを使って、色々動作させてみました。

*クリックするとYoutubeが開きます

Ask Alexa to open & close my switch port

※iPhoneのSMSからルータと通信しているスクリーンショット

IMG_4149.PNG

EEMについては、以下の辺りを参照ください。

マニュアルは、以下が包括的で個人的にお勧めです。


環境と準備

Cisco 1100 LTE のSMS と IOS-XE EEMで遊ぶと同じなので、省略。


ルータで動作させるTclスクリプト

Cisco IOSルータでTclスクリプトを動作させる方法は、以下を参照ください。

以下のスクリプトを、LTE付き Cisco 1100 ルータで動作させています。同じことは、Cisco 800とかでもできると思います。雑なコードでアレですが、エッセンス&スニペット用ということで..。


sms.tcl

# ---------------------------------------------------------------------------

# 0. EEM Script
# ---------------------------------------------------------------------------
::cisco::eem::event_register_syslog pattern "New SMS received"

namespace import ::cisco::eem::*
namespace import ::cisco::lib::*

# ---------------------------------------------------------------------------
# 1. Procedures
# ---------------------------------------------------------------------------
proc CLIProc {clifd cmds} {
global errorInfo cmd_output
foreach a_cmd $cmds {
if [catch {cli_exec $clifd $a_cmd} result] {
error $result $errorInfo
} else {
set cmd_output $result
}
}
}
# ---------------------------------------------------------------------------
# 2. Body
# ---------------------------------------------------------------------------

if [catch {cli_open} result] {
error $result $errorInfo
} else {
array set cli1 $result
}

# ---------------------------------------------------------------------------
# 3. Get SMS Index Number
# ---------------------------------------------------------------------------
# array set arr_einfo [event_reqinfo]
# set msg $arr_einfo(msg)
# set syslog_line [split $msg]
# set num [lindex $syslog_line 11]
# regsub -all .$ $num "" num
# action_syslog msg "Number is $num"

# ---------------------------------------------------------------------------
# 4. Get SMS Message & From Mobile Number
# ---------------------------------------------------------------------------
set Cmds [list "enable" "cellular 0/2/0 lte sms view summary" ]
CLIProc $cli1(fd) $Cmds

foreach line [split $cmd_output \n] {
set instr_line [split $line]
set instr [lindex $instr_line 0]
switch $instr {
0 {
regsub -all "{}" $instr_line "" instr_line
set mobileNum [lindex $instr_line 1]
set smsMsg [lindex $instr_line 5]
}
}
}

action_syslog msg "Received From : $mobileNum"
action_syslog msg "Received Message : $smsMsg"

# ---------------------------------------------------------------------------
# 5. Append SMS log file
# ---------------------------------------------------------------------------
if [file exists sms.log] {
puts "file sms.log being overwritten"
}
set myfileid [open sms.log a+]
puts $myfileid $cmd_output
close $myfileid

# ---------------------------------------------------------------------------
# 6. Actions
# ---------------------------------------------------------------------------
switch -regexp $smsMsg {
Command {
set Cmds [list "enable" "cellular 0/2/0 lte sms send $mobileNum Cpu, Serial, Route, Ios, RttCisco, RttAmazon" ]
CLIProc $cli1(fd) $Cmds
}
^[0-9]+$ {
set Cmds [list "enable" "cellular 0/2/0 lte sms send $smsMsg Hello from ISR1100LTE! Please send #Command# to me!"
]
CLIProc $cli1(fd) $Cmds
}
Cpu {
set Cmds [list "enable" "show proc cpu | i CPU" ]
CLIProc $cli1(fd) $Cmds
set Cmds [list "enable" "cellular 0/2/0 lte sms send $mobileNum $cmd_output" ]
CLIProc $cli1(fd) $Cmds
}
Serial {
set Cmds [list "enable" "sh snmp chassis" ]
CLIProc $cli1(fd) $Cmds
set Cmds [list "enable" "cellular 0/2/0 lte sms send $mobileNum $cmd_output" ]
CLIProc $cli1(fd) $Cmds
}
Route {
set Cmds [list "enable" "sh ip route summary | be Total" ]
CLIProc $cli1(fd) $Cmds
set Cmds [list "enable" "cellular 0/2/0 lte sms send $mobileNum $cmd_output" ]
CLIProc $cli1(fd) $Cmds
}
Ios {
set Cmds [list "enable" "sh version | i bin" ]
CLIProc $cli1(fd) $Cmds
set Cmds [list "enable" "cellular 0/2/0 lte sms send $mobileNum $cmd_output" ]
CLIProc $cli1(fd) $Cmds
}
RttCisco {
set Cmds [list "enable" "sh ip sla statistics 100 | i Latest RTT" ]
CLIProc $cli1(fd) $Cmds
set Cmds [list "enable" "cellular 0/2/0 lte sms send $mobileNum $cmd_output" ]
CLIProc $cli1(fd) $Cmds
}
RttAmazon {
set Cmds [list "enable" "sh ip sla statistics 103 | i Latest RTT" ]
CLIProc $cli1(fd) $Cmds
set Cmds [list "enable" "cellular 0/2/0 lte sms send $mobileNum $cmd_output" ]
CLIProc $cli1(fd) $Cmds
}
Vlan[0-9]{1,2} {
set vlanNum [string trim $smsMsg Vlan]
set Cmds [list "enable" "conf t" "int range gi 0/1/0 - 3" "switchport access vlan $vlanNum" "end" "write memory" ]
CLIProc $cli1(fd) $Cmds
append smsmsg "gi 0/1/0 - 3 is changed to " "$smsMsg"
set Cmds [list "enable" "cellular 0/2/0 lte sms send $mobileNum $smsmsg" ]
CLIProc $cli1(fd) $Cmds
}
default {
set Cmds [list "enable" "cellular 0/2/0 lte sms send $mobileNum $smsMsg" ]
CLIProc $cli1(fd) $Cmds
}
}

# ---------------------------------------------------------------------------
# 7. Clear messages on Modem
# ---------------------------------------------------------------------------
if [catch {cli_exec $cli1(fd) "enable"} result] {
error $result $errorInfo
}
if [catch {cli_write $cli1(fd) "cellular 0/2/0 lte sms delete all"} result] {
error $result $errorInfo
}
if [catch {cli_read_pattern $cli1(fd) "Are you sure you want to delete all SMS?"} result] {
error $result $errorInfo
}
if [catch {cli_write $cli1(fd) "\n"} result] {
error $result $errorInfo
}
if [catch {cli_read $cli1(fd)} result] {
error $result $errorInfo
}

if [catch {cli_close $cli1(fd) $cli1(tty_id)} result] {
error $result $errorInfo
}



解説


0. EEM Script

EEM Event Detectorの記法です。

::cisco::eem::event_register_syslog pattern "New SMS received" 

組込ライブラリの読み込み(ほぼおまじない)です。

namespace import ::cisco::eem::*

namespace import ::cisco::lib::*


1. Procedures

IOS Execコマンドをリストに入れて、連打するプロシージャです。

proc CLIProc {clifd cmds} {

global errorInfo cmd_output
foreach a_cmd $cmds {
if [catch {cli_exec $clifd $a_cmd} result] {
error $result $errorInfo
} else {
set cmd_output $result
}
}
}


2. Body

ここからが本文。cli_openで、EEMでコマンドを打ち込む内部的なVTYを開きます。


if [catch {cli_open} result] {
error $result $errorInfo
} else {
array set cli1 $result
}


3. Get SMS Index Number

今回は使いませんでしたが、SMSを受信すると、Syslogが出ます。このSyslogからIndex番号を取り出しました。以下の例では、「14」の部分です。

*Jul 27 10:02:35.033: Cellular0/2/0: New SMS received on index 14. Please issue a view command to see it

*Jul 27 10:02:35.033: %CELLWAN-2-SMS_ARCH_PATH_UNCONFIGURED: Cellular0/2/0 failed to archive SMS because 'gsm|cdma|lte sms archive path' under cellular controller is not configured.

event_reqinfoのTcl版を使います。Event Detectorに応じて、内部的に情報を引っ張り出せます。Tclの場合、配列を作っておきます。今回はSyslog EDを使っているので、$arr_einfo(msg)でSyslogメッセージを取り出して、刻んでます。

array set arr_einfo [event_reqinfo]

set msg $arr_einfo(msg)

何をevent_reqinfoで取り出せるか?については、毎回マニュアルを見てもいいのですが、IOSコマンドで確認できるので便利です。Tcl event_reqinfo Array Names:の部分す。以下、Syslog EDの例です。

C1111LTE#show event manager detector ?

all All available event detectors
application Application event detector
cli CLI event detector
config Config event detector
counter Counter event detector
env Environmental event detector
generic Generic event detector
gold GOLD event detector
interface Interface event detector
ioswdsysmon Ioswdsysmon event detector
ipsla IPSLA event detector
mat mac-address-table event detector
neighbor-discovery neighbor discovery event detector
none None event detector
oir OIR event detector
resource Resource event detector
rf RF event detector
routing Routing event detector
rpc RPC event detector
snmp Snmp event detector
snmp-notification Snmp notification event detector
snmp-object Snmp Object event detector
syslog Syslog event detector
test Test event detector
timer Timer event detector
track Track event detector

C1111LTE#show event manager detector syslog detail
No. Name Version Node Type
1 syslog 01.00 node0/0 RP

Tcl Configuration Syntax:
::cisco::eem::event_register_syslog
[tag <tag-val>]
[pattern <pattern-val>]
[sequence <sequence-val>]
[timestamp <timestamp-val>]
[facility <facility-val>]
[mnemonic <mnemonic-val>]
[occurs <occurs-val>]
[period <period-val>]
[priority {all | emergencies | alerts | critical |
errors | warnings | notifications |
informational | debugging}]
[severity_fatal]
[severity_critical]
[severity_major]
[severity_minor]
[severity_warning]
[severity_notification]
[severity_normal]
[severity_debugging]
[queue_priority {normal | low | high | last}]
[maxrun <sec.msec>]
[ratelimit <sec.msec>]
[nice {0 | 1}]

Tcl event_reqinfo Array Names:
event_id
job_id
event_type
event_type_string
event_pub_time
event_pub_sec
event_pub_msec
event_trigger_num
event_severity
msg
priority
sequence
timestamp
facility
mnemonic

Applet Configuration Syntax:
[ no ] event [tag <tag-val>] syslog
[pattern <pattern-val>]
[sequence <sequence-val>]
[timestamp <timestamp-val>]
[facility <facility-val>]
[mnemonic <mnemonic-val>]
[occurs <occurs-val>]
[period <period-val>]
[priority {all | emergencies | alerts | critical |
errors | warnings | notifications |
informational | debugging}]
[severity-fatal]
[severity-critical]
[severity-major]
[severity-minor]
[severity-warning]
[severity-notification]
[severity-normal]
[severity-debugging]
[maxrun <sec.msec>]
[ratelimit <sec.msec>]

Applet Built-in Environment Variables:
$_event_id
$_job_id
$_event_type
$_event_type_string
$_event_pub_time
$_event_pub_sec
$_event_pub_msec
$_event_severity
$_syslog_msg
$_syslog_priority
$_syslog_sequence
$_syslog_timestamp
$_syslog_facility
$_syslog_mnemonic

IOS内部の非同期イベントをEvent Detectorが捕捉し、それに関連する情報がevent_reqinfoで内部的に提供される、というのがEEMの醍醐味の一つですね。


4. Get SMS Message & From Mobile Number

モデム上のSMSログを確認するコマンド(cellular 0/2/0 lte sms view summary)を実行し、電話番号と受信メッセージを取得します。

C1111LTE#cellular 0/2/0 lte sms view summary 

ID FROM YY/MM/DD HR:MN:SC SIZE CONTENT
<snip>
9 0907717**** 18-07-27 17:48:03 8 Oh yeah
10 0907717**** 18-07-27 17:49:33 8 hogehoge
11 0802011**** 18-07-27 18:00:09 23 wifi on sent by hsakabe
12 0908870**** 18-07-27 18:00:27 5 ^_0U^S^_
13 0802011**** 18-07-27 18:00:54 6 sh ver
14 0909007**** 18-07-27 19:02:39 33 Hi, I am Kazumasa. You ar...

最初、「インデックス番号で最新のものを取得する」(上の例では、14の行を分解)という方針で行こうと考えましたが、SMSメッセージは別途、IOSフラッシュ上に保存するように実装し、モデム上は毎回ログをクリアすることにしました。モデム上は常に空っぽで、受信するとID 0が作られるようにしました。これで、モデム上のログ溢れは考えなくてよくなります。

確認用にsyslog出力をしていますが、送信してきた電話番号(mobileNum)と、SMSメッセージ(smsMsg)を取り出しました。

action_syslog msg "Received From : $mobileNum"

action_syslog msg "Received Message : $smsMsg"

今回は実装していませんが、セキュリティ用途として、登録澄み電話番号からのリクエストだけを処理するといった使い方も良いかと思いました。


5. Append SMS log file

EEMからIOS bootflash上にsms.logを作成し、cellular 0/2/0 lte sms view summary の結果を追記していきます。インデックス番号は、毎回クリアしているので、常に0になりますが、タイムスタンプが含まれるので良いでしょう。

こんな感じで保存されていきます。

C1111LTE#sh bootflash: | i sms.log

660 13220 Aug 05 2018 23:40:55.0000000000 +00:00 /bootflash/sms.log
C1111LTE#
C1111LTE#more bootflash:/sms.log

ID FROM YY/MM/DD HR:MN:SC SIZE CONTENT
0 0909007**** 18-08-03 11:46:04 3 Ios
C1111LTE#

ID FROM YY/MM/DD HR:MN:SC SIZE CONTENT
0 0909007**** 18-08-03 11:52:23 3 Cpu


6. Actions

受信したメッセージ(smsMsg)に応じて、アクションを書いていきます。見たまんまですが、Switchを使います。

switch -regexp $smsMsg {...

以下のような例をデモ用に書いてみました。Vlan変更などは、確認用のテストとその結果も送信したいところですね。あと、SMSは文字数が限られるので、やり取りは最小限として、別途メールで送信または、ファイルサーバまたはローカルフラッシュにログを保存するといった方法も良いかと思いました。


  • 電話番号が送られてきたら、その電話番号に対してHelloメッセージを送信

  • Commandが来たら、対応コマンドを送信

  • 対応コマンドは、Cpu、Ios、Route、Serialなど

  • RttCisco、RttAmazonは、IOSのIP-SLA機能を使ってURLまでのRTTを測定し、その結果を送信

  • Vlanと番号を送信すると、設定済みアクセスポート(gi 0/1/0 - 3)のVlanを変更


7. Clear messages on Modem

最後にモデム上のログをコマンド(cellular 0/2/0 lte sms delete all)でクリアして終わります。このコマンドは、プロンプトで確認が入るので、cli_execを連打するわけにもいきません。多くの場合、(file prompt quiet ) -> コマンド連打 -> (no file prompt quiet )でいけるのですが、今回はこれが使えなかったので、パターンに呼応するタイプのコマンド実行を使います。これは、(cli_write)と(cli_read_pattern)を組み合わせて書けます。


if [catch {cli_write $cli1(fd) "cellular 0/2/0 lte sms delete all"} result] {
error $result $errorInfo
}
if [catch {cli_read_pattern $cli1(fd) "Are you sure you want to delete all SMS?"} result] {
error $result $errorInfo
}
if [catch {cli_write $cli1(fd) "\n"} result] {
error $result $errorInfo
}


まとめ

意外と、簡単に色々できそうですね!

わりと力技のパターンを実行していますが、もうちょっと汎用化できれば、面白いかもしれません。