情報収集と理論
これを行う方法に関する情報を求めて、Googleに尋ねられ、短い検索の後、目的のアドレスを取得し、それらが表示されるポートを決定するためのアルゴリズムを説明する素晴らしいドキュメントがCiscoによって著者として発見されました。
3Com 4200Gスイッチからのsnmpwalkの結論を簡単に調べたところ、私の場合はvlanを決定する必要さえなく、ポートごとにMACアドレスを決定するための3つのステップしかありませんでした。
ドキュメントから理解できるように、必要なものは次のとおりです。
1)住所リストを取得する
$snmpwalk -c public -v 2c hostname .1.3.6.1.2.1.17.4.3.1.1
17.4.3.1.1.0.0.12.7.172.8 = Hex: 00 00 0C 07 AC 08
17.4.3.1.1.0.1.2.27.80.145 = Hex: 00 01 02 1B 50 91
17.4.3.1.1.0.1.3.72.77.90 = Hex: 00 01 03 48 4D 5A
17.4.3.1.1.0.1.3.72.221.191 = Hex: 00 01 03 48 DD BF
...
2)コマンドでポートのリストを取得する
$snmpwalk -c public -v 2c hostname .1.3.6.1.2.1.17.4.3.1.2
17.4.3.1.2.0.0.12.7.172.8 = 13
17.4.3.1.2.0.1.2.27.80.128 = 13
17.4.3.1.2.0.1.2.27.80.145 = 13
17.4.3.1.2.0.1.2.163.145.225 = 13
...
単純なスイッチに問い合わせている場合、この素晴らしい数(この例では13)はスイッチのポートです。
3)OID番号間の対応を見つけることだけが残っており、 12.7.172.8で終わるOIDは、このMACがハングするMACとポート番号を提供することがわかります。
理論から実践へ
このすべてを自動化するために、真珠の簡単なスクリプトをスケッチしました( UPDATE0:gescheitのアドバイスでコードが更新されました; UPDATE1: FreeLSDのアドバイスでコードが再び更新されました)
#! / usr / bin / perl
#================================================= =====================
#
#選択したポートからの3COMスイッチからのMACアドレスのクエリ
#================================================= =====================
厳格な使用;
Net :: SNMP qw ( snmp_dispatcher oid_lex_sort )を使用します。
私の$ show_vendor = 1 ;
私の$ script = "/usr/share/zabbix/scripts/mac.sh -s" ;
私の$ debug = 0 ;
my $ file_name = "/ tmp / $ ARGV [0] -getmac.tmp" ;
私の$ interval = 90 ; #リフレッシュレート
私の$ new = 0 ;
私の@リスト;
私の$ write_secs = ( stat ( $ file_name ) )) [ 9 ] ;
if ( $ debug == 1 ) {
print "file $ file_name updated at" 、スカラー( localtime ( $ write_secs ) ) 、 " \ n " ;
} ;
if ( $ write_secs + $ interval < time ) { #ファイルの更新間隔が$ interval秒前
if ( $ debug == 1 ) { print "新しいMacテーブルの生成\ n " ; }
$ new = 1 ;
FHを開く、 "> $ file_name "またはdie "ca n't open '' $ file_name ':$!" ;
} else {
if ( $ debug == 1 ) { print "古いmacテーブルを使用\ n " ; }
FRを開く、 「< $ file_name 」またはdie 「開けません ' $ file_name ':$!」 ;
while ( my $ line = < FR > ) {
ムシャムシャ( $ライン ) ;
my ( $ p 、 $ m ) = split / ; / 、 $行 ;
@ list [ $ p ] = "@list [ $ p ] $ m 、" ;
}
}
#======================================
私の$セッション ;
私の$エラー ;
私の$ port = $ ARGV [ 1 ] ;
if ( $ new == 1 ) {
#===リモートホストへのセッションのセットアップ===
( $ session 、 $ error ) = Net :: SNMP- >セッション(
-hostname = > $ ARGV [ 0 ] || 'localhost' 、
-community = > 'public' 、
-version = > '2c' 、
-translate = > [ -octetstring = > 0 ] 、
-port = > 161
) ;
#===セッションは作成されましたか? ===
if ( ! defined ( $ session ) ) {
printf ( "ERROR:%s \ n " 、 $ error ) ;
出口 1 ;
}
} ;
#==================================
#===情報を取得するためにクエリされるOID ====
私の$ TpFdbAddress = '1.3.6.1.2.1.17.4.3.1.1' ;
私の$ TpFdbPort = '1.3.6.1.2.1.17.4.3.1.2' ;
#=============================================
私の$結果 ;
私の@ tmp;
私の$ x ;
if ( $ new == 1 ) {
if ( defined ( $ result = $ session- > get_table ( $ TpFdbAddress ) ) )) {
foreach ( oid_lex_sort ( keys ( % { $ result } ) ) )) {
$ x = unpack ( 'H *' 、 $ result- > { $ _ } ) ;
$ x =〜s / ( .. ( ? ! \ Z ) ) / \ 1 : / g;
push ( @ tmp、 $ x ) ;
}
} else {
if ( $ debug == 1 ) {
printf ( "ERROR:%s \ n \ n " 、 $ session- > error ( ) ) ;
}
}
#===========================================
#===返されたMACポートを出力===
$ result ;
if ( defined ( $ result = $ session- > get_table ( -baseoid = > $ TpFdbPort ) ) )) {
私の$ i = 0 ;
私の$ out = "" ;
私の$ res = 0 ;
私の$ tmp_port ;
私の$ tmp_mac_list = "" ;
foreach ( oid_lex_sort ( keys ( % { $ result } ) ) )) {
if ( $ result- > { $ _ } == $ port ) {
$ res = 1 ;
if ( $ show_vendor == 1 ) {
$ out = ` $ script $ tmp [ $ i ] ` ;
printf ( "%s(%s)" 、 $ tmp [ $ i ] 、 $ out ) ;
} else {
printf ( "%s" 、 $ tmp [ $ i ] ) ;
} ;
print "、" ;
} ;
if ( $ show_vendor == 1 ) {
$ out = ` $ script $ tmp [ $ i ] ` ;
printf FH ( "%s;%s(%s) \ n " 、 $ result- > { $ _ } 、 $ tmp [ $ i ] 、 $ out ) ;
} else {
printf FH ( "%s;%s \ n " 、 $ result- > { $ _ } 、 $ tmp [ $ i ] ) ;
} ;
$ i ++;
}
if ( $ res == 0 ) {
「null」を印刷します 。
} ;
} else {
if ( $ debug == 1 ) {
printf ( "ERROR:%s \ n \ n " 、 $ session- > error ( ) ) ;
} else {
「null」を印刷します 。
} ;
}
} else {
if ( @ list [ $ port ] ) {
print "@list [ $ port ]" ;
} else {
「null」を印刷します 。
} ;
}
print " \ n " ;
#=============================================
#===セッションを閉じてプログラムを終了します===
if ( $ new == 1 ) {
$セッション - >閉じる;
FHを閉じます。
} else {
FRを閉じます。
}
exit 0 ;
コードは非常に洗練されていません。OIDが既に受信されているファイルがない場合は、MACアドレスを持つOIDを取得し、アレイに書き込みます。 次に、同じシーケンスでポート付きのOIDを取得します。これにより、配列内のn番目の値と、受信したOIDのn番目の値とポート番号との対応が得られます。 次に、受信したデータをファイルにドロップします。
ファイルがスクリプトの開始時に既に存在し、$ interval(私の場合は90秒)よりも古いものではない場合、そのファイルからデータを取得します。 これにより、スイッチごとに2つのSNMP要求のみを使用できました。
スクリプトは入力に2つのパラメーターを取ります。最初のパラメーターはデバイスアドレスです(これはzabbixの仕様です。外部スクリプトの場合、ホストのアドレスは常に最初のパラメーターです)。私たちにとって重要なポート番号は2番目のパラメーターです。 このポートにアドレスがない場合、スクリプトはテキスト「null」を含む文字列を返します。 新しいバージョンでは、mac-addressでデバイスの製造元を確認できます。 この機能を有効にするには、値が1の$ show_vendor変数があります。スクリプトは、スクリプト変数で指定された別のスクリプトからメーカーに関する情報を取得しようとします。 このスクリプトには、デバイスのMACアドレスが渡されます。 私自身のために、かなりシンプルなshスクリプトを実装しました。その全体のポイントは、1行実行することです。
awk --assign IGNORECASE = 1 '/ hex / && /' $ mac '/ {for(x = 3; x <= NF; x ++){printf( "%s"、$ x)}}' $ filename
変数$ filenameの下に隠れている神秘的なファイルはreferenceによって取得され、ieeeによって慎重に選択された必要なすべてのデータが含まれています。
この1行を少し変更し、「更新」モードも追加して、メーカーのリストの最新バージョンを収縮させました。 結果は次のとおりです。
#!/ bin / sh
#mac-addressからベンダーを取得
if [ -z "$ 1" ] ; それから
echo "引数が指定されていません。終了します!$ 0 [-option] macを使用します"
echo "[-option]には-u(データベースを更新して終了)または-s(サイレントモード、ベンダーのみ表示)を指定できます。"
1 番出口
fi
#スクリプトを実行するときにZabbixが$ PATHを設定しないことを忘れないでください
ファイル名 = / usr / share / zabbix / scripts / oui.txt
tmpfile = / tmp / oui.txt
link = http: // standard.ieee.org / development / regauth / oui / oui.txt
sed = / bin / sed
awk = / bin / awk
ケース $ 1 in
-s )
サイレント = 1
mac = 2ドル
if [ -z "$ 2" ] ; それから
echo "macが指定されていません、終了します!"
1 番出口
fi
;;
-u )
wget $ link -O $ tmpfile
if [ $? -gt 0 ] ; それから
echo "ダウンロードエラー、終了"
1 番出口
他に
echo "OKをダウンロード!"
echo " $ tmpfileを$ filenameに移動..."
mv -f $ tmpfile $ filename
if [ $? -gt 0 ] ; それから
echo "エラー!"
他に
echo "成功!"
fi
出口 0
fi
;;
* )
mac = $ 1
;;
エサック
もし [ ! -f $ filename ] ; それから
if [ -z $ silent ] ; それから
echo "macリストファイルはありません、ダウンロードしますか?[y / n]"
他に
1 番出口
fi
ながら :
する
INPUT_STRINGを読む
ケース $ INPUT_STRING
y )
echo " $リンクからダウンロードしようとしています"
wget $ link -O $ filename
if [ $? -gt 0 ] ; それから
echo "ダウンロードエラー、終了"
1 番出口
他に
echo "OKをダウンロード!"
fi
破る
;;
n )
echo "exiting!"
出口 0
;;
* )
echo "間違った入力、[y / n]を使用"
;;
エサック
やった
fi
if [ $ { #mac } -lt 8 ] ; それから
mac = ` echo " $ mac " | $ sed 's / ^ \(.. \)\(.. \)\(.. \)/ \ 1- \ 2- \ 3 /' '
他に
mac = ` echo " $ mac " | $ sed -e 's /:/-/ g' '
fi
mac = $ {mac:0:8}
if [ -z $ silent ] ; それから
echo " $ macを検索しています..."
fi
result = ` $ awk --assign IGNORECASE = 1 '/ hex / && /' $ mac '/ {for(x = 3; x <= NF; x ++){printf("%s "、$ x)}}' $ファイル名 `
if [ -z " $ result " ] ; それから
結果 = 「情報なし」
fi
echo -n $結果
メーカーにパフォーマンスをテストするスクリプトを実行します。
$./mac.sh "000000"
no mac list file, dowload it? [y/n]
y
Trying to download from standards.ieee.org/develop/regauth/oui/oui.txt
--2011-10-06 14:20:16-- standards.ieee.org/develop/regauth/oui/oui.txt
proxy.organization.ltd... 192.168.0.1
proxy.organization.ltd|192.168.0.1|:3128... .
Proxy , ... 200 OK
: 2493060 (2,4M) [text/plain]
Saving to: «oui.txt»
100%[==========================================================================================================================================================================>] 2 493 060 784K/s 3,1s
2011-10-06 14:20:26 (784 KB/s) - «oui.txt» saved [2493060/2493060]
Download ok!
Searching for 00-00-00...
XEROX CORPORATION
すべてが機能する場合は、次に進みます。
次に、zabbixa configでスクリプトの実行時間を設定し、必要な値に増やします。 選択したタイムアウト値が十分でない場合、macアドレスを反映するデータ要素が「スクリプト実行タイムアウト」などのエラー説明とともに「サポートされていない」カテゴリに1つずつ移動するため、すぐにこれを理解できます。
構成を編集します。
#vim /etc/zabbix/zabbix-server.conf
私たちはそこにそのような行を探しています
### Option: Timeout
# Specifies how long we wait for agent, SNMP device or external check (in seconds).
# Range: 1-30
コメントを外し、目的の値に変更します
Timeout=5
そこを見て
### Option: ExternalScripts
# Location of external scripts
ExternalScripts=/usr/share/zabbix/scripts/
必要に応じて、スクリプトへの正しいパスに変更します。
このパスに沿って、真珠の上にスクリプトを配置します。 私はそれを巧妙に呼び出しました-get_mac.pl
次に、Zabbixで、スイッチのテンプレートに必要なデータ型を設定します。
そして、すべてのポートに。
その後、zabbixでスイッチのポートのアドレス情報を直接受信できます。
私にはこのように見えます(更新されたスクリーンショットをメーカーの名前で投稿することはできません。habrastorageはフラッシュなしでは機能せず、Google Chromeのフラッシュでも機能しないためです)。
ポート16を見ているときに心配しないでください-これはアップリンクです。
この手法はテストされており、3Comブランドの9つのスイッチ(4200G、4210、2916、2924)で1か月間正常に動作しています。Zabbixバージョン1.8.5、最近1.8.7に更新されました。 シスコのドキュメントに従ってこれらすべてを作成したことを考えると、シスコスイッチに問題はないはずです。
PS私はスクリプトを完成させて処理できると信じていますが、私はperlが得意ではないので、この高貴な仕事に助けを求めてhabrasocietyに頼み、Zabbixのような素晴らしいプロジェクトを価値ある高品質のソリューションとして入れます。 また、スイッチ3Com 4200G、4210、2924のテンプレートを改良されたスクリプトと一緒に配置する予定です。
gescheitによって更新されたUPD0スクリプトコード
FreeLSDのアドバイスに基づいて更新されたUPD1の記事とコード