Логування VPN-підключень на Cisco ASA

Доброго часу доби, колеги. В наявності є 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]?\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("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) — йому проставляється час завершення сесії.

Готовий до зауважень/виправлень/доопрацюванням/питань.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.