インターネットに登って、自分の仕事にふさわしいものを見つけられなかった(もちろん、見た目がひどかった)ので、SNMP出力を解析してテーブルに入れるスクリプトを書くことにしました。
MySQLテーブル構造:
CREATE DATABASE `vpn_log` /*!40100 DEFAULT CHARACTER SET latin1 */; CREATE TABLE `logins` ( `id_l` int(10) unsigned NOT NULL AUTO_INCREMENT, `login` varchar(90) NOT NULL, `id_s` int(10) unsigned DEFAULT NULL, PRIMARY KEY (`id_l`), UNIQUE KEY `id_l_UNIQUE` (`id_l`), UNIQUE KEY `login_UNIQUE` (`login`) ) ENGINE=InnoDB AUTO_INCREMENT=121 DEFAULT CHARSET=latin1; CREATE TABLE `sessions` ( `id_s` int(10) unsigned NOT NULL AUTO_INCREMENT, `id_l` int(10) unsigned NOT NULL, `time_start` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `time_end` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `ip_source` varchar(45) NOT NULL, `ip_lan` varchar(45) NOT NULL, `s_index` int(10) unsigned NOT NULL, `profile` varchar(255) NOT NULL, PRIMARY KEY (`id_s`), UNIQUE KEY `id_s_UNIQUE` (`id_s`) ) ENGINE=InnoDB AUTO_INCREMENT=2923 DEFAULT CHARSET=latin1;
処理スクリプト自体:
#!/usr/bin/php <?php ##Database settings $settings['sql_host']="localhost"; $settings['sql_db']="vpn_log"; $settings['sql_user']="vpn_log"; $settings['sql_password']="vpn_log"; # # function connectdb(){ global $settings; $dbconn = mysqli_connect( $settings['sql_host'], $settings['sql_user'], $settings['sql_password'], $settings['sql_db'] ) or die('Could not connect: ' . mysqli_connect_errno()); return $dbconn; } # IPSEC # function get_users(){ $ret = snmp3_real_walk( '10.10.10.10', #IP Cisco ASA 'snmpuser', #SNMP 'authNoPriv', # 'MD5', # 'authpassword', # '', # '', # '1.3.6.1.4.1.9.9.392.1.3.21' # OID ); $result = []; $user = []; foreach ($ret as $oid=>$value){ $re = '/(SNMPv2-SMI::enterprises\.9\.9\.392\.1\.3\.21\.1\.[0-9]{1,2}\.[0-9]{1,2}\.)([\.0-9]*)\.([0-9]{4,10})/'; # , $str = $oid; preg_match_all($re, $str, $matches); $oid = explode(".",$matches[2][0]); $value = explode(": ",$value); $login = ""; foreach ($oid as $chr){ $login.=chr($chr); }; $result[strtolower($login)][$matches[3][0]][] = @str_ireplace("\"","",$value[1]); }; return $result; # [login][s_index][value] }; $x = get_users(); $connect = connectdb(); foreach ($x as $user=>$sessions){ $user = addslashes($user); foreach ($sessions as $session=>$value ){ if (preg_match("/((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)/",$value[7]) and preg_match("/((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)/",$value[5])){ $sql = "SELECT * from logins where login = '$user'"; $result = mysqli_query($connect, $sql); $res = mysqli_fetch_array($result); $time = date("Ymd H:i:s",time()-$value[3]); $id_l = $res['id_l']; if (mysqli_num_rows($result)==0){ $sql_1 = "INSERT INTO logins value ('','".$user."','')"; $result_1 = mysqli_query($connect, $sql_1); $id_l = mysqli_insert_id($connect); $sql_1 = "INSERT INTO sessions (id_l,time_start,ip_source,ip_lan,s_index, profile)value ('$id_l','$time','$value[7]','$value[5]','$session', '$value[0]')"; $result_1 = mysqli_query($connect, $sql_1); $id_s = mysqli_insert_id($connect); } else{ $sql_1 = "SELECT * from sessions where (id_l = (select id_l from logins where login = '$user'))and(s_index = '$session')and(time_end = '0')"; $result_1 = mysqli_query($connect, $sql_1); if (mysqli_num_rows($result_1)==0){ $sql_2 = "INSERT INTO sessions (id_l,time_start,ip_source,ip_lan,s_index, profile)value ('$id_l','$time','$value[7]','$value[5]','$session', '$value[0]')"; $result_2 = mysqli_query($connect, $sql_2); } } } } } $sql = "SELECT l.login,s.s_index FROM logins as l left join sessions as s on l.id_l=s.id_l where (s.time_end=0)"; $rw = mysqli_query($connect,$sql); $result = mysqli_fetch_array($rw); while ($result['s_index']>0){ if (@!$x[strtolower($result['login'])][$result['s_index']][0]){ $sql_1 = "UPDATE sessions SET time_end = '".date("Ymd H:i:s",time())."' where s_index='".$result['s_index']."'"; mysqli_query($connect, $sql_1); }; $result = mysqli_fetch_array($rw); }; mysqli_close($connect); ?>
仕事の論理:
このスクリプトは、30秒ごとにクローンを介して実行され、SNMP機器をポーリングします。 シスコはユーザーログインを明確な形式で保存しないため、動的に生成されたSNMP OIDからログインを抽出する必要があります。 各ログイン文字は、SNMP OID部分のASCIIコードを使用して保存されます(これはここから取得されます )。
get_user()関数を実行した後、変数$ xは次の形式の値を取ります。
[login] => Array ( [s_index] => Array ( [0] => profile_name ............................. [34] => 0 ) )
値の説明はここにあります 。
次に、スクリプトはLoginsテーブルにログインがあるかどうかを確認します。 そのようなログインが存在しない場合-そこに追加し、存在する場合-id_lを取得します。 次に、このログインに終了日が未定義のセッションが開いているかどうかを確認します。 そうでない場合は、セッションテーブルに新しいレコードを作成します。
次に、スクリプトはデータベースから、不完全なセッションを持つユーザーのリストを受け取ります。 そして、調査でログインをチェックします。 ログインが調査に含まれていない場合、またはセッション番号がデータベース内の番号(s_index)と一致しない場合、セッション終了時刻がスタンプされます。
コメント/修正/改善/質問の準備ができています。
UPD:ログイン解析機能およびアクティブセッションでのログインの存在の確認にstrtolower()が追加されました(ほぼ最後に)。 それ以外の場合、ログインに大文字が含まれていると、すべてが正しく機能しません。