Доброго времени суток, коллеги. В наличии есть Cisco ASA 5512 с настроенным сервером IPSEC туннелей к которому цепляются пользователи для доступа в корпоративную сеть. Поступила задача — выводить список активных пользователей в мониторинге, а также вести логирование кто, когда, с какого адреса и с каким профилем цеплялся.
Полазил по интернету, ничего подходящего для моей задачи не нашёл (может конечно плохо искал), и решил написать скрипт, который парсит вывод 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[$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]?dd?).){3}(25[0-5]|2[0-4]d|[01]?dd?)/",$value[7]) and preg_match("/((25[0-5]|2[0-4]d|[01]?dd?).){3}(25[0-5]|2[0-4]d|[01]?dd?)/",$value[5])){
$sql = "SELECT * from logins where login = '$user'";
$result = mysqli_query($connect, $sql);
$res = mysqli_fetch_array($result);
$time = date("Y-m-d 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[$result['login']][$result['s_index']][0]){
$sql_1 = "UPDATE sessions SET time_end = '".date("Y-m-d H:i:s",time())."' where s_index='".$result['s_index']."'";
mysqli_query($connect, $sql_1);
};
$result = mysqli_fetch_array($rw);
};
mysqli_close($connect);
?>
Логика работы:
Скрипт запускается каждый 30 секунд через crone и опрашивает по SNMP оборудование. Так как логинов пользователей в открытом виде Cisco не хранит, то необходимо вытащить логины из динамически формируемого SNMP OID. Каждый символ логин хранится с помощью ASCII кода в части SNMP OID (это почерпнул отсюда).
После отработки функции get_user() переменная $x принимает значение в следующем формате:
[login] => Array
(
[s_index] => Array
(
[0] => profile_name
.............................
[34] => 0
)
)
Описание значений можно посмотреть тут.
Дальше скрипт проверяет — есть ли логин в таблице Logins. Если такого логина нет — добавляет его туда, если есть — получает его id_l. Затем, смотрит — есть ли у этого логина открытые сессии с неустановленным датой окончания. Если нет — создаёт в таблице sessions новую запись.
Затем скрипт получает из базы список пользователей, у которых есть незавершённые сессии. И проверяет наличие логинов в опросе. Если логина нет в опросе или номер сессии не совпадает с той, которая в базе (s_index) — ему проставляется время завершения сессии.
Готов к замечаниям/исправлениям/доработкам/вопросам.
Автор: NvAriec