На данный момент разработан следующий принцип работы скрипта:
1. Скрипт написанный на php подключается к роутеру cisco, терминирующему pppoe сессии, собирает список online юзеров: username,interface,ip
2. Для каждого юзера с помощью sh interface $userinterface, собирается текущий объем трафика на интерфейсе.
3. Из базы данных netup берётся тарифный план пользователя, из базы данных скрипта берётся максимально допустимый объем трафика за час(можно указать другой период в конфиге) для данного тарифного плана.
3.1. Если текущий трафик пользователя за час больше установленного лимита для тарифа, посылаем на циску команду, добавляющую ip пользователя в определенный ACL, на котором установлен traffic_shape, в базу данных скрипта записывается значение is_shaped='1' для $username.
3.2. Если меньше лимита:
3.2.1 и у пользователя стоит флаг is_shaped=1, удаляем ip пользователя из шейпящего ACL.
3.2.1 если флаг не стоит: do nothing
4. clear interface counters
5. Скрипт перезапускается кроном через 1час.
В дальнейшем можно реализовать функционал, выставляющий лимиты в зависимости от текущей утилизации аплинка, либо по другим параметрам.
На данный момент написан класс, работающий с cisco. Функция, собирающая список юзеров онлайн, функция собирающая текущий трафик пользователя.
Класс cisco (cisco.php):
Код: Выделить всё
<?php
class Cisco
{
private $_hostname;
private $_password;
private $_username;
private $_connection;
private $_data;
private $_timeout;
private $_prompt;
public function getUserTraffic($user_interface)
{
$this->_send("sh int ".$user_interface." | in underruns");
$this->_readTo($this->_prompt);
$result = array();
$this->_data = explode("\r\n", $this->_data);
array_pop($this->_data);
$temp = $this->_data[1];
$temp = sscanf($temp, "%d %s %s %d %s %d %s");
$bytes = $temp[3];
$megabytes = $bytes/1048576;
//TEST
$string = $user_interface.":".$megabytes."\n";
return $string;
//return $megabytes;
}
public function __construct($hostname, $password, $username = "", $timeout = 10)
{
$this->_hostname = $hostname;
$this->_password = $password;
$this->_username = $username;
$this->_timeout = $timeout;
} // __construct
/**
* Подключаемся к устройству
*/
public function connect()
{
$this->_connection = fsockopen($this->_hostname, 23, $errno, $errstr, $this->_timeout);
if ($this->_connection === false) {
die("Error: Connection Failed for $this->_hostname\n");
} // if
stream_set_timeout($this->_connection, $this->_timeout);
$this->_readTo(':');
if (substr($this->_data, -9) == 'Username:') {
$this->_send($this->_username);
$this->_readTo(':');
} // if
$this->_send($this->_password);
$this->_prompt = '>';
$this->_readTo($this->_prompt);
if (strpos($this->_data, $this->_prompt) === false) {
fclose($this->_connection);
die("Error: Authentication Failed for $this->_hostname\n");
} // if
} // connect
/**
* Закрываем соединение
*/
public function close()
{
$this->_send('quit');
fclose($this->_connection);
} // close
/**
* Даём команду в терминал
*/
private function _send($command)
{
fputs($this->_connection, $command . "\r\n");
} // _send
/**
* Читаем терминал
*
*/
private function _readTo($char)
{
// Reset $_data
$this->_data = "";
while (($c = fgetc($this->_connection)) !== false) {
$this->_data .= $c;
if ($c == $char[0]) break;
if ($c == '-') {
// Continue at --More-- prompt
if (substr($this->_data, -8) == '--More--') fputs($this->_connection, ' ');
} // if
} // while
// Remove --More-- and backspace
$this->_data = str_replace('--More--', "", $this->_data);
$this->_data = str_replace(chr(8), "", $this->_data);
// Set $_data as false if previous command failed.
if (strpos($this->_data, '% Invalid input detected') !== false) $this->_data = false;
} // _readTo
/**
* заходим в привелегированный режим Enable
*
*
*/
public function enable($password)
{
$result = false;
if ($this->_prompt != '#') {
$this->_send('enable');
$this->_readTo(':');
$this->_send($password);
if ($this->_data !== false) {
$this->_prompt = '#';
$result = true;
} // if
$this->_readTo($this->_prompt);
return $result;
} // if
} // enable
/**
* Disable - выходим из Enable
*/
public function disable()
{
if ($this->_prompt == '#') {
$this->_send('disable');
$this->_prompt = '>';
$this->_readTo($this->_prompt);
} // if
} // disable
/**
* Ping
*/
public function ping($host)
{
$this->_send("ping $host");
$this->_readTo($this->_prompt);
$this->_data = explode("\r\n", $this->_data);
for ($i = 0; $i < 3; $i++) array_shift($this->_data);
array_pop($this->_data);
$this->_data = implode("\n", $this->_data);
return $this->_data;
} // ping
public function getUsers()
{
$this->_send('show users');
$this->_readTo($this->_prompt);
$result = array();
$this->_data = explode("\r\n", $this->_data);
array_pop($this->_data);
foreach ($this->_data as $entry) {
if (preg_match('/Bundle/i',$entry)) {
$temp = sscanf($entry, "%s %s %s %s %s %s");
$entry = array();
$entry['idle'] = $temp[4];
$entry['ip'] = $temp[5];
} else {
$temp = sscanf($entry, "%s %s %s %s %s");
$entry = array();
$entry['idle'] = $temp[3];
$entry['ip'] = $temp[4];
}//if
$entry['interface'] = $temp[0];
$entry['username'] = $temp[1];
if (strstr($entry['ip'],"10.1.")) {
$entry['uplink'] = "USI";
} else {
$entry['uplink'] = "RTK";
}//if
if (preg_match('/u\d\d/i',$entry['username'])) {
$entry['client_type'] = "HOME";
} else {
$entry['client_type'] = "CORPORATE";
}//if
if ($entry['idle'] != 'Idle' && $entry['ip'] != '' && $entry['ip'] != 'Idle') {
array_push($result, $entry);
} //if
} // foreach
$this->_data = $result;
return $this->_data;
}
} // Cisco
//
Исполняемый файл:
Код: Выделить всё
<?php
//ПОДКЛЮЧАЕМЫЕ МОДУЛИ
require 'Cisco.php';
///////////////////////////////////////////////////////////////////
//КОНФИГРУРАЦИЯ
$cisco_hostname = '11.11.11.11'; //ХОСТ
$cisco_username = 'user'; //ЮЗЕР
$cisco_password = 'pass'; //ПАРОЛЬ
$cisco_enpasswd = 'enablepass'; //ПАРОЛЬ НА ENABLE
///////////////////////////////////////////////////////////////////
//КОННЕКТИМСЯ
$cisco = new Cisco($cisco_hostname,$cisco_password,$cisco_username);
$cisco->connect();
$cisco -> enable($cisco_enpasswd);
///////////////////////////////////////////////////////////////////
$users_array = $cisco -> getUsers();
//for ($i=0;$i<count($users_array);$i++){
//sleep(2);
//$test = $cisco -> getUserTraffic($users_array[$i]['interface']);
//print($test);
//}
$cisco -> disable();
$cisco -> close();
print_r($users_array); //DEBUG USERS_ARRAY FUNCTION
?>