SYLOGはUDPを使ってアスキー文字列を送信しているだけなので、他のプロトコルと比べて非常に簡単にサーバーを作ることができます。
$udp = New-Object Net.Sockets.UdpClient -ArgumentList 514
$sender = $null
while($true) `
{
if($udp.Available) `
{
$buffer = $udp.Receive([ref]$sender)
$sender.ToString()+[Text.Encoding]::UTF8.GetString($buffer)
}
[Threading.Thread]::Sleep(500)
}
これを実行するとSYSLOGを受信するたびに、受信したデータと送信元情報を表示します。
192.168.0.1:54677<141>[00:00:00:00:00:00] ABCDEFGHIJKLMN ntpclient: SUCCESS: set time : Sun Mar 30 17:27:37 2014途中の<141>はSYSLOGのプロトコルに規定されている部分で、FacilityやSeverityを表しています。141を8で割った余りは5ですが、これはSeverity(深刻度)を表しています。このログは5なので「通知」を意味します。141を8で割った商は17ですが、これはFacilityを表していてます。Facilityはログの種類を表していて、Facilityの17はlocal1です。ちゃんとしたSYSLOGサーバーならFacilityの値によって出力先のログファイルを分けることができます。
<141>より前の部分は送信元のIPアドレスとポート番号です。送信されてきたUDPデータグラムのIPヘッダー部分に書かれていた情報をここで表示しています。
<141>より後の部分は実際のSYSLOGのメッセージです。
FacilityとSeverityの値をそれぞれ以下の表に示します。
| コード | Facility |
|---|---|
| 0 | カーネル |
| 1 | ユーザー・レベル |
| 2 | 電子メール |
| 3 | システム・デーモン |
| 4 | セキュリティー・認証 |
| 5 | syslogd内部生成 |
| 6 | ラインプリンター |
| 7 | ネット・ニューズ |
| 8 | UUCP |
| 9 | クロック・デーモン |
| 10 | セキュリティー・認証 |
| 11 | FTP(ファイル転送) |
| 12 | NTP(時刻合わせ) |
| 13 | 監査 |
| 14 | 警戒 |
| 15 | クロックデーモン |
| 16 | local0 |
| 17 | local1 |
| 18 | local2 |
| 19 | local3 |
| 20 | local4 |
| 21 | local5 |
| 22 | local6 |
| 23 | local7 |
| コード | Severity |
| 0 | Emergency |
| 1 | Alert |
| 2 | Critical |
| 3 | Error |
| 4 | Warning |
| 5 | Notice |
| 6 | Informational |
| 7 | Debug |
ここからはスクリプトを解説していきます。
まず、最初の行は.NET Frameworkのクラス呼び出しであり、System.Net.Sockets.UdpClientクラスのオブジェクト(実体)を生成しています。このとき、-ArgumentList 514の指定は解放するポート番号を意味しています。
$udp = New-Object Net.Sockets.UdpClient -ArgumentList 5142行目は送信元を格納するための変数を用意しています。
$sender = $nullwhile($true)は無限ループを意味するので、Ctrl+Cなどユーザー操作で終了させられるまで{ }の中身をくり返します。
while($true) { (中略) }$udp.Availableは、受信したUDPデータグラムがあるときに$trueになります。UDPデータグラムを読むだけなら後述する$udp.Receiveを実行すれば良いのですが、受信していない状態で$udp.Receiveを実行すると受信待ちになり、受信するまではCtrl+Cを入力しても終了できなくなります。そこで、受信したかどうか判定してから読み込むようにします。
if($udp.Available) { (中略) }$udp.Receiveの行では、受信したUDPデータグラムを読み込みます。読み込んだ内容は返却値として得られるので$bufferに格納され、送信元のIPアドレスやポート番号は引数の$senderに格納されます。$udp.Receive()で行われる処理は$senderの値変更を含んでいるので、$senderには[ref]をつけなければなりません。
$buffer = $udp.Receive([ref]$sender)次の行は、送信元IP、ポート番号、および受信したUDPデータグラムを表す文字列です。$senderは送信元のIPとポート番号を表すデータなので、$sender.ToString()で、ポート番号を表す文字列が得られます。その後ろは、受信したUDPデータグラムである$bufferをUTF8の文字列とみなして、その文字列を出力することを意味します。+で、その前後の文字列を連結します。
$sender.ToString()+[Text.Encoding]::UTF8.GetString($buffer)この行は、500ミリ秒待つことを意味します。これを入れないと、受信していない間は空っぽの無限ループを実行することになってしまうので少し待ってから受信するようにしています。
[Threading.Thread]::Sleep(500)タグ:SYSLOGサーバー UDP

