LoginSignup
2
3

More than 3 years have passed since last update.

SNMPトラップによる LANのLink Up/Down検知 をCloudWatchに通知する

Last updated at Posted at 2019-10-05

高機能なルータには、LANケーブルが挿されたり抜かれたりすると、Link Up/Downイベントが通知されるSNMPの機能がついているものがあります。
これがあれば、誰かが勝手にLANにつなごうとしているのを検出できたり、何かのはずみでLANケーブルが抜けてしまったことを検知できることになります。
さらに、この検知をCloudWatchに通知すれば、集中管理できそうです。

とは言いながら、そもそもCloudWatchに通知するためのLANケーブルが抜けてしまっては、CloudWatchに通知できないので、参考情報の一つととらえてください。

一方、このSNMPと同様の機能が、Windowsにもありますので、今回はWindowsをルータとみなして、SNMPのLink Up/Down検知およびCloudWatchへの通知をしてみたいとおもいます。

ネットワーク環境

こんな感じのネットワークを想定しています。

 別のネットワーク
  |
 Windows10(監視対象のルータ想定)
  |
 ルータ - SNMP監視サーバ
  |
 CloudWatch

Windows10を監視対象のルータとして見立てています。Windows10には2つのネットワークインタフェースがあり、片方のネットワークケーブルが断線した場合を考えます。

SNMPエージェントをWindows10で動作させ、常時監視をします。
SNMPエージェントがネットワークインタフェースのダウンを検知すると、SNMP監視サーバに通知します。
SNMP監視サーバは、通知を検知すると、通知内容を判別し、CloudWatchに通知します。

SNMPエージェントが「snmpd」、SNMP監視サーバが「snmptrapd」です。また、「snmp」の各種コマンドを使えば、ローカルまたはリモートマシンのSNMPの情報を取得することができます。

SNMPエージェントのインストール

Windows10とUbuntuそれぞれでのインストール方法を示しておきます。

Windows10の場合

OS標準の機能ですが、手動で有効化する必要があります。
設定から「アプリと機能」を開きます。

image.png

「オプション機能の管理」を選択します。

image.png

「機能の追加」を押下し、リストの中から「簡易ネットワーク管理プロトコル(SNMP)」を選択します。

そうすると、コンピュータの管理の「サービス」に「SNMPサービス」が現れます。おそらく、状態は実行中になっているかと思います。

image.png

次に、SNMPサービスをダブルクリックしてプロパティを表示します。
「セキュリティ」タブを選択します。

image.png

受け付けるコミュニティ名として、コミュニティ「public」、権利「読み取りのみ」を追加します。
また、SNMPパケットを受け付けるホスト名またはIPアドレスを指定します。ここでは単純に、「すべてのホストからSNMPパケットを受け付ける」を選択しています。

これで、SNMP監視サーバから、SNMPの各種情報を取得できるようになりました。

Ubuntuの場合

Ubuntuの場合のインストールは、以下を実行します。

# apt-get install snmpd

以下のファイルを修正する必要があります。

 /etc/snmp/snmpd.conf

/etc/snmp/snmpd.conf
・・・

#  Listen for connections from the local system only
#agentAddress  udp:127.0.0.1:161
#  Listen for connections on all interfaces (both IPv4 *and* IPv6)
agentAddress udp:161,udp6:[::1]:161

・・・

# rocommunity public  default    -V systemonly
rocommunity public default

・・・

これで再起動すれば、他のPCからSNMP情報を取得できるようになります。

# /etc/init.d/snmpd restart

SNMPの情報の取得

Ubuntuで、以下を実行します。

# apt-get install snmp snmp-mibs-downloader

これで、SNMPの情報取得のための各種コマンドを実行できるようになりました。
その前に、以下のファイルで、修正が必要です。

 /etc/snmp/snmp.conf

mibs:をコメントアウトし、mibs allを追記します。

/etc/snmp/snmp.conf
# As the snmp packages come without MIB files due to license reasons, loading
# of MIBs is disabled by default. If you added the MIBs you can reenable
# loading them by commenting out the following line.
#mibs :
mibs all

これで準備ができたはずなのですが、環境によって以下のようなエラーが出る場合があります。

Bad operator (INTEGER): At line 73 in /usr/share/mibs/ietf/SNMPv2-PDU

その場合は、以下を実行します。

# wget http://www.iana.org/assignments/ianaippmmetricsregistry-mib/ianaippmmetricsregistry-mib -O /usr/share/snmp/mibs/iana/IANA-IPPM-METRICS-REGISTRY-MIB
# wget http://pastebin.com/raw.php?i=p3QyuXzZ -O /usr/share/snmp/mibs/ietf/SNMPv2-PDU
# wget http://pastebin.com/raw.php?i=gG7j8nyk -O /usr/share/snmp/mibs/ietf/IPATM-IPMC-MIB

(参考)
https://docs.linuxconsulting.mn.it/notes/net-snmp-errors

それでは、取得してみましょう。

ローカルホストの場合

$ snmpwalk -v1 localhost -c public

リモートホストの場合

$ snmpwalk -v1 【SNMPエージェントのホスト名】 -c public

すごくたくさんの情報が取得されたかと思います。以下のように指定すると、特定の情報のみ取得します。

$ snmpwalk -v1 localhost -c public .1.3.6.1.2.1.2.2.1.2

$ snmpwalk -v1 localhost -c public RFC1213-MIB:ifDescr

実は、上の2つは同じ情報を指しています。
 .1.3.6.1.2.1.2.2.1.2

 RFC1213-MIB:ifDescr
は同じです。そのOIDと名前のマッピング情報が「snmp-mibs-downloader」にあったわけです。

マッピング情報は、以下の方法で、相互に調べることができます。

$ snmptranslate .1.3.6.1.2.1.2.2.1.10
RFC1213-MIB::ifInOctets

$ snmptranslate -On RFC1213-MIB::ifInOctets
.1.3.6.1.2.1.2.2.1.10

ちなみに、SNMPの項目は、以下を実行することで一覧取得できます。多すぎて面喰いますが。

$ snmptranslate -Tp

どのようなOIDがあるかどうかは、以下の方の記事が参考になります。
 ネットワーク機器のSNMP MIB/OIDまとめ

SNMPトラップの設定

LANのLink Up/Down を通知するには、トラップ機能を使います。
通常、監視しているサーバから、snmpwalkやsnmpgetコマンドを使って、SNMPエージェントに対して情報取得を要求するのですが、トラップは、SNMPエージェント側から通知をするための機能です。

Windowsでは、SNMPサービスのプロパティから設定します。

image.png

通知する際のコミュニティ名を指定し、トラップ通知先をIPアドレスまたはホスト名を指定しておきます。

SNMPトラップの受信設定

SNMPトラップの受信側では、以下をインストールし、デーモンとして起動しておく必要があります。

# apt-get install snmptrapd

次に、以下のファイルを修正します。

 /etc/snmp/snmptrapd.conf

以下の部分のpublicの行のコメントを外します。Windows側から通知する際のコミュニティ名と合わせてください。

/etc/snmp/snmptrapd.conf
#authCommunity log,execute,net private 
authCommunity log,execute,net public

変更が完了したら、snmptrapd を再起動します。

# /etc/init.d/snmptrapd restart

準備ができました。
WindowsのLANケーブルを抜いてみてください。

ちょっとすると、/var/log/syslog に以下のようなログが記録されているかと思います。

Oct  6 01:47:34 【SNMP監視サーバのホスト名】 snmptrapd[1072]: 2019-10-06 01:47:34 【SNMPエージェントのホスト名】 [【SNMPエージェントのIPアドレス】] (via UDP: [【SNMPエージェントのIPアドレス】]:59663->[【SNMP監視サーバのIPアドレス】]:162) TRAP, SNMP v1, community public#012#011RFC1155-SMI::enterprises.311.1.1.3.1.1 Link Down Trap (0) Uptime: 23:18:52.53#012#011RFC1213-MIB::ifIndex.32 = INTEGER: 32

SNMPトラップをCloudWatchにアップする

snmptrapdには、SNMPトラップを受信したとき、指定されたプログラムを起動して、受信したSNMPトラップ情報を渡してくれる機能があります。
下記のような感じにしています。(traphandleのところ)

/etc/snmp/snmptrapd.conf

/etc/snmp/snmptrapd.conf
## send mail when get any events
#traphandle default /usr/bin/traptoemail -s smtp.example.org foobar@example.org
traphandle .1.3.6.1.6.3.1.1.5.* /home/XXXXXXXXXX/link_trap.sh

「.1.3.6.1.6.3.1.1.5.*」 の部分で、SNMPトラップで転送したいOIDを指定しています。

あとは、指定したプログラム(今回はシェルスクリプト)を実装し、その中でCloudWatchに上げればよいわけです。

実は、指定したプログラム(シェルスクリプト)には、以下のような情報が標準入力として渡されます。

【SNMPエージェントのホスト名】
UDP: [【SNMPエージェントのIPアドレス】]:59663->[【SNMP監視サーバのIPアドレス】]:162
DISMAN-EXPRESSION-MIB::sysUpTimeInstance 0:17:30:04.71
SNMPv2-MIB::snmpTrapOID.0 IF-MIB::linkDown
RFC1213-MIB::ifIndex.35 35
SNMP-COMMUNITY-MIB::snmpTrapAddress.0 【SNMPエージェントのIPアドレス】
SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 "public"
SNMPv2-MIB::snmpTrapEnterprise.0 RFC1155-SMI::enterprises.311.1.1.3.1.1

これがlinkDownのときの通知内容です。
このうち欲しかったのは以下の情報です。

【SNMPエージェントのホスト名】
SNMPv2-MIB::snmpTrapOID.0 IF-MIB::linkDown
RFC1213-MIB::ifIndex.35 35

先頭行には、送信元ホスト名があります。
linkDown通知であることがわかります。
35とは、linkDownの事象となったLANポートの番号です。Windowsでは、vEthernetやらBluetoothネットワークなど、たくさんの仮想的なネットワークインタフェースが動いており、それぞれに重ならないように番号がついています。
ルータの場合は、純粋にLAN端子の番号になると思います。

snmptrapd.confで指定したスクリプトは以下となります。
標準入力された情報から必要な情報を抽出し、CloudWatchに通知しています。(bashシェルスクリプトは初心者なのでもっと効率的に書けるのでは。。。)

/home/XXXXXXXXXX/link_trap.sh
#!/bin/bash

export AWS_CREDENTIAL_FILE=/home/XXXXXXXX/awscreds

while read line
do
    if [ -z "$host" ]; then
        host=${line}
    else
        set ${line}
        if [[ ${1} =~ "RFC1213-MIB::ifIndex." ]]; then
            ifIndex=${2}
        fi

        if [ ${1} = "SNMPv2-MIB::snmpTrapOID.0" ]; then
            if [ ${2} = 'IF-MIB::linkUp' ]; then
                link=1
            elif [ ${2} = 'IF-MIB::linkDown' ]; then
                link=0
            fi
        fi
    fi
done

if [ "$link" -a "$ifIndex" ]; then
    echo aws cloudwatch put-metric-data --namespace SNMP_IFLink --metric-name IFLink --dimensions "host=$host,ifNumber=$ifIndex" --value $link
    aws cloudwatch put-metric-data --namespace SNMP_IFLink --metric-name IFLink --dimensions "host=$host,ifNumber=$ifIndex" --value $link
fi

AWS_CREDENTIAL_FILEに指定するファイルには以下の形式で記載しておきます。当然ながら、そのIAMユーザにはCloudWatchへput-metric-dataする権利がある必要があります。

AWSAccessKeyId=YYYYYYYYYYYYYYYYYYYY
AWSSecretKey=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz

aws cloudwatch *** の部分が、CloudWatchに通知している個所になります。
コマンドラインからAWSを操作するためのaws-cliを使っています。

(参考)
 https://docs.aws.amazon.com/cli/latest/reference/cloudwatch/put-metric-data.html

SNMPトラップ機能をリスタートし、LANケーブルを抜いてみましょう。

# /etc/init.d/snmptrapd restart

ちょっとわかりにくいかもしれませんが、CloudWatchに情報がアップされているのがわかります。
メトリクスネームスペースはSNMP_IFLinkとしています。

image.png

メトリクスの値は、Link Up/Down の情報です。Upの場合は1、Downの場合は0としています。また、どのルータのどのLAN端子番号で発生したのかがわかるように、ディメンジョンとしてhostとifNumberが渡っているのがわかります。

以上

2
3
0

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
2
3