Windowsの別端末の監視情報(SNMP)を取得する

# はじめに
サーバーリプレース作業(Windows Server 2008R2 + Oracle 11g → Windows Server 2016 + PostgreSQL 9.6)を終えてから初めての大規模なサーバーメンテナンス作業を先日から行いました。
サーバーリプレース作業の中には汎用サーバーからNASサーバーに変更するところがありまして、NASサーバーに変更すると監視ソフトウェアから監視情報が取得できなくなります。そもそも監視ソフトウェアではどういう仕組みで監視情報（CPU使用率、メモリ使用率、ディスク使用率、プロセス監視、稼働日数など）を取得しているのかを調べたところ、「SNMP」というキーワードが見つかりました。

今回のサーバーメンテナンス作業で、NASサーバーにSNMPサービスの追加作業をすることになりました。

# SNMPとは
SNMP(Simple Network Management Protocol)とは、ネットワーク内に存在する装置の状態を監視することを目的につくられたプロトコルで業界標準の規格です。各ベンダ共通の規格なので、サーバーやルータの種類を問わず利用可能です。

SNMPはマネージャ側(監視サーバなど、管理側)とエージェント側(監視対象のサーバ、ネットワーク機器など)に分かれて構成されます。

[ネットワーク監視の超基本「SNMP」とは？](https://blogs.manageengine.jp/itom_what_is_snmp/)

## MIBとは
MIB(Management Information Base)とは、管理情報を蓄積したデータベースで、SNMPエージェントは監視対象機器の情報をMIBから参照します。
MIBには「標準MIB」とメーカーや機器固有のものなどが存在します。メーカーや機器固有のものはメーカーに確認する必要があります。

## OIDとは
MIBに格納されている情報の1つ1つは「オブジェクト（Object）」と呼ばれます。
オブジェクトは情報の要素によってツリー構造で管理され、それぞれに「オブジェクトID(OID)」という識別子が割り振られています。
OIDはピリオドで区切られた数字で表現されます。

標準MIBのうち「MIB-2」はOID「1.3.6.1.2.1」になります。

```
iso(1)
　 Ｌ org(3)
　　　Ｌ dod(6)
　　　　　Ｌ internet(1)
　　　　　　　Ｌ private(4)
　　　　　　　Ｌ mgmt(2)
　　　　　　　　　Ｌ mib2(1)
　　　　　　　　　　　Ｌ system(1)
```

MIBに含まれているオブジェクトのOIDとその意味は「MIBファイル」というテキストファイルに記述されています。
監視対象機器からSNMPを使ってどのような情報を収集できるかは、その監視対象機器がサポートしているMIBファイルを確認する必要があります。

### よく使うOID情報

|名前|OID|説明|
|:--|:--|:--|
|MACHINE_NAME|.1.3.6.1.2.1.1.5.0|ホスト名(コンピューター名)|
|SNMP_MACHINE_UPTIME|.1.3.6.1.2.1.1.3.0|SNMPエージェントが起動してからの時間 1/100秒|
|MACHINE_SYS_UPTIME|.1.3.6.1.2.1.25.1.1.0|前回ホストが起動してからの時間 1/1000秒|
|MACHINE_SYS_DATE|.1.3.6.1.2.1.25.1.2.0|ホストから見たローカルの日付と時間|
|MACHINE_RAMMEMORY|.1.3.6.1.2.1.25.2.2.0|ホストが持っているRAMの容量|
|IP_ADDRESS|.1.3.6.1.2.1.4.20.1|ホストのIPアドレス|
|PROCESS_LIST|.1.3.6.1.2.1.1.1.0|プロセス一覧(snmpwalk使用)|

* [[SNMP]MIB-2ツリー配下のOIDの一覧](http://park1.wakwak.com/~ima/freebsd_netsnmpoidlist.html)
* [mib-2サブツリー](https://www.itmedia.co.jp/help/howto/linux/0007master/06/11.html)

http://oidref.com/ の次に OID 番号を入力すると何かを教えてくれます。

```bash:使用例
http://oidref.com/1.3.6.1.4.1.2021
```

# 設定
## SNMPサービスの追加
WindowsではデフォルトでSNMP設定がされていないため、「SNMPサービス」を追加する必要があります。
SNMPを使用できるようにする図入りの設定は下記サイトを参照
[WINDOWS SERVER : SNMP 設定方法](https://thwack.solarwinds.com/t5/%E6%8A%80%E8%A1%93%E3%82%B3%E3%83%9F%E3%83%A5%E3%83%8B%E3%83%86%E3%82%A3%E3%83%BC/Windows-Server-SNMP-%E8%A8%AD%E5%AE%9A%E6%96%B9%E6%B3%95/gpm-p/520293?%3F%3F)

## SNMPサービスの設定
SNMPサービスのプロパティにあるセキュリティタブにて、コミュニティ名"public"を追加して、「すべてのホストからSNMPパケットを受け取る」側にチェックを付ける。
なお、SNMPでアクセスできるサーバを限定する場合は、[これらのホストから、SNMPパケットを受け付ける]をチェックし、運用管理サーバのIPアドレスを追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/bd5dc152-972e-8182-9b28-ee30a43b4f0d.png)

## SNMPトラップの受信許可
ファイアーウォールの受信の一覧から「SNMP トラップ サービス (UDP 受信)」のプロファイル「プライベート, パブリック」側を選択し、右クリックメニューから「規則の有効化」をクリックします。
右クリックメニューのプロパティのスコープタブにて、リモートIPアドレスの「任意のIPアドレス」を選択してOKボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/b66c5b73-e66e-00a8-2d55-9599456c90d6.png)

# 取得方法
エージェントSNMPコミュニティ名には、SNMPサービスのプロパティのセキュリティータブで設定したコミュニティ名（例 public）を指定する。

## VBScript
VBScriptで取得するには、COMにある「OlePrn.OleSNMP」モジュールを使用することで取得することが出来る。
ただし、OID番号で指定する必要があるのとsnmpwalkのような列挙ができない。

```vb:ホスト名取得
agentIP = "192.168.64.123" ' エージェントIPアドレス
community = "public" ' エージェントSNMPコミュニティ名
retry = 1 ' リトライ回数
timeout = 200 ' 応答タイムアウト値（ミリ秒）
oid = ".1.3.6.1.2.1.1.5.0" ' OID（OIDを変えると取得情報を変えることができる）

set snmp = CreateObject("OlePrn.OleSNMP")
call snmp.Open(agentIP, community, retry, timeout)

value = snmp.Get(oid)

'メッセージを表示
WScript.Echo(value)

call snmp.Close()
set snmp = nothing
```
## Net-SNMP
SNMPプロトコルを実装したOSS  
http://www.net-snmp.org/

[WindowsでのSNMPお勉強メモ](https://qiita.com/gebo/items/3ba4450894bbfeed667b)

### インストール
下記サイトの「net-snmp-5.7.0-1.x86.exe」をダウンロードしてインストールする。  
https://sourceforge.net/projects/net-snmp/files/net-snmp%20binaries/5.7-binaries/

インストールオプションは、コマンドラインアプリケーションのみを使用のため「Base Components」のみインストールします。  
[Windows を使用した SNMP の検証環境構築のSNMP エージェントの通信テスト](https://blog.engineer-memo.com/2023/05/07/windows-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9F-snmp-%E3%81%AE%E6%A4%9C%E8%A8%BC%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89/)

### テスト
192.168.64.123サーバー名を取得する。

snmpwalk -v バージョン -c コミュニティ名 IPアドレス OID(.1.3.6...または値の名称でも可)

```bat
> snmpwalk -v2c -c public 192.168.64.123 .1.3.6.1.2.1.1.5.0

SNMPv2-MIB::sysName.0 = STRING: TEST
```

[ウィンドウズ - Snmpwalk のインストール](https://techexpert.tips/ja/windows-ja/%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6%E3%82%BA-snmpwalk-%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB/)

## CSharp
nugetからLextm.SharpSnmpLibをダウンロードして使用する。MITライセンスとなっている。
[Lextm.SharpSnmpLib の使用例](https://docs.sharpsnmp.com/tutorials/introduction.html)

Walk を使用することで一覧が一括で取得できる。

```csharp:プロセス一覧
var result = new List<Variable>();
Messenger.Walk(VersionCode.V1,
               new IPEndPoint(IPAddress.Parse("192.168.64.123"), 161),
               new OctetString("public"),
               new ObjectIdentifier("1.3.6.1.2.1.25.4.2.1.2"),
               result,
               60000,
               WalkMode.WithinSubtree);
```

# 最後に
現在は運用チームに属しているのでサーバー監視のような技術を知るようになります。
運用というのは、問題が発生する前に対処しておく必要があり平時が常な状態で問題が起きればお祭り状態です。
運用が平和な状態はいいことなんですが、経営層からすれば何も問題が発生していないとしてコスト削減で人数を減らしやすい対象となってしまいます。
問題がないように事前に対応しているということを経営層にアピールしていかないといけない。今の所はそんなことはなっていないんですけどね。