mirror of
https://github.com/pavel-odintsov/fastnetmon
synced 2024-11-23 09:12:14 +01:00
add mikrotik api support
This commit is contained in:
parent
7a048eb8b1
commit
a4ea97c7a5
99
src/mikrotik_plugin/fastnetmon_mikrotik.php
Normal file
99
src/mikrotik_plugin/fastnetmon_mikrotik.php
Normal file
@ -0,0 +1,99 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
/*****************************
|
||||
*
|
||||
* MikroTik RouterOS PHP API integration for FastNetMon
|
||||
*
|
||||
* This script connect to router MikroTik and add or remove a blackhole's rule for the IP attack
|
||||
*
|
||||
* Author: Maximiliano Dobladez info@mkesolutions.net
|
||||
*
|
||||
* http://maxid.com.ar | http://www.mkesolutions.net
|
||||
*
|
||||
* for API MIKROTIK:
|
||||
* http://www.mikrotik.com
|
||||
* http://wiki.mikrotik.com/wiki/API_PHP_class
|
||||
*
|
||||
* LICENSE: GPLv2 GNU GENERAL PUBLIC LICENSE
|
||||
*
|
||||
*
|
||||
* v1.0 - 4 Jul 16 - initial version
|
||||
******************************/
|
||||
//sin errores
|
||||
error_reporting( 0 );
|
||||
// error_reporting( E_ALL );
|
||||
// ini_set( 'display_errors', 'On' );
|
||||
define( "_VER", '1.0' );
|
||||
|
||||
$fecha_now = date("Y-m-d H:i:s", time());
|
||||
|
||||
$cfg[ ip_mikrotik ] = "192.168.10.1"; // IP Mikrotik Router
|
||||
$cfg[ api_user ] = "api"; //user
|
||||
$cfg[ api_pass ] = "api123"; //pass
|
||||
/*
|
||||
INPUT info
|
||||
This script will get following params:
|
||||
$1 client_ip_as_string
|
||||
$2 data_direction
|
||||
$3 pps_as_string
|
||||
$4 action (ban or unban)
|
||||
*/
|
||||
$IP_ATTACK = $argv[ 1 ];
|
||||
$DIRECTION_ATTACK = $argv[ 2 ];
|
||||
$POWER_ATTACK = $argv[ 3 ];
|
||||
$ACTION_ATTACK = $argv[ 4 ];
|
||||
//**Si faltan argumentos no hacer nada
|
||||
if ( $argc <= 4 ) {
|
||||
$msg .= "MikroTik's API Integration for FastNetMon - Ver: " . _VER . "\n";
|
||||
$msg .= "missing arguments";
|
||||
$msg .= "php fastnetmon_logger.php [IP] [data_direction] [pps_as_string] [action] \n";
|
||||
echo $msg;
|
||||
exit( 1 );
|
||||
}
|
||||
//NOTE help
|
||||
if ( $argv[ 1 ] == "help" ) {
|
||||
$msg = "MikroTik's API Integration for FastNetMon - Ver: " . _VER;
|
||||
echo $msg;
|
||||
_log( $msg );
|
||||
exit( 1 );
|
||||
}
|
||||
require_once "routeros_api.php";
|
||||
$API = new RouterosAPI();
|
||||
// $API->debug = true;
|
||||
if ( $API->connect( $cfg[ ip_mikrotik ], $cfg[ api_user ], $cfg[ api_pass ] ) ) {
|
||||
//Blocking by route blackhole
|
||||
if ( $ACTION_ATTACK == "ban" ) {
|
||||
$comment_rule = 'FastNetMon Guard: IP ' . $IP_ATTACK . ' blocked because ' . $DIRECTION_ATTACK . ' attack with power ' . $POWER_ATTACK . ' pps | at '.$fecha_now;
|
||||
$API->write( '/ip/route/add', false );
|
||||
$API->write( '=dst-address=' . $IP_ATTACK, false );
|
||||
$API->write( '=type=blackhole', false );
|
||||
$API->write( '=comment=' . $comment_rule );
|
||||
$ret = $API->read();
|
||||
|
||||
}
|
||||
if ( $ACTION_ATTACK == "unban" ) {
|
||||
$comment_rule = 'FastNetMon Guard: IP ' . $IP_ATTACK . ' remove from blacklist ';
|
||||
$API->write( '/ip/route/print', false );
|
||||
$API->write( '?dst-address=' . $IP_ATTACK . "/32" );
|
||||
$ID_ARRAY = $API->read();
|
||||
$API->write( '/ip/route/remove', false );
|
||||
$API->write( '=.id=' . $ID_ARRAY[ 0 ][ '.id' ] );
|
||||
$ret = $API->read();
|
||||
}
|
||||
if ($ret) _log( $comment_rule );
|
||||
} else { // can't connect
|
||||
$msg = "Couldn't connect to " . $cfg[ ip_mikrotik ];
|
||||
_log( $msg );
|
||||
echo $msg;
|
||||
exit( 1 );
|
||||
}
|
||||
function _log( $msg ) {
|
||||
$FILE_LOG_TMP = "/tmp/fastnetmon_api_mikrotik.log";
|
||||
if ( !file_exists( $FILE_LOG_TMP ) ) {
|
||||
exec( "echo `date` \"- [FASTNETMON] - " . $msg . " \" > " . $FILE_LOG_TMP );
|
||||
} else {
|
||||
exec( "echo `date` \"- [FASTNETMON] - " . $msg . " \" >> " . $FILE_LOG_TMP );
|
||||
}
|
||||
return;
|
||||
}
|
||||
?>
|
16
src/mikrotik_plugin/notify_about_attack.sh
Executable file
16
src/mikrotik_plugin/notify_about_attack.sh
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Fastnetmon: MikroTik RouterOS plugin
|
||||
#
|
||||
# by Maximiliano Dobladez - info@mkesolutions.net - http://maxid.com.ar
|
||||
#
|
||||
# This script will get following params:
|
||||
# $1 client_ip_as_string
|
||||
# $2 data_direction
|
||||
# $3 pps_as_string
|
||||
# $4 action (ban or unban)
|
||||
|
||||
|
||||
php -f /opt/fastnetmon/fastnetmon_mikrotik.php $1 $2 $3 $4
|
||||
exit 0
|
||||
|
34
src/mikrotik_plugin/readme.txt
Normal file
34
src/mikrotik_plugin/readme.txt
Normal file
@ -0,0 +1,34 @@
|
||||
Fastnetmon Plugin: MikroTik RouterOS PHP API integration for FastNetMon
|
||||
|
||||
|
||||
This script connect to router MikroTik and add or remove a blackhole's rule for the IP attack.
|
||||
|
||||
You can modify the action, ex add a firewall rule, etc.
|
||||
|
||||
This script use PHP API for MikroTik:
|
||||
* http://www.mikrotik.com
|
||||
* http://wiki.mikrotik.com/wiki/API_PHP_class
|
||||
|
||||
|
||||
v1.0 - 4 Jul 16 - initial version
|
||||
|
||||
Author: Maximiliano Dobladez info@mkesolutions.net
|
||||
|
||||
http://maxid.com.ar | http://www.mkesolutions.net
|
||||
|
||||
** instalation
|
||||
|
||||
* You must to have an user with API access on the router MikroTik.
|
||||
|
||||
* Set the router's config on fastnetmon_mikrotik.php file
|
||||
|
||||
$cfg[ ip_mikrotik ] = "192.168.10.1"; // IP Mikrotik Router
|
||||
$cfg[ api_user ] = "api"; //user
|
||||
$cfg[ api_pass ] = "api123"; //pass
|
||||
|
||||
* Change the notify_about_attack.sh file with the new to run the php script
|
||||
|
||||
**
|
||||
|
||||
This is the first buggy version, you are welcome to add more feature.
|
||||
|
423
src/mikrotik_plugin/routeros_api.php
Normal file
423
src/mikrotik_plugin/routeros_api.php
Normal file
@ -0,0 +1,423 @@
|
||||
<?php
|
||||
/*****************************
|
||||
*
|
||||
* RouterOS PHP API class v1.6
|
||||
* Author: Denis Basta
|
||||
* Contributors:
|
||||
* Nick Barnes
|
||||
* Ben Menking (ben [at] infotechsc [dot] com)
|
||||
* Jeremy Jefferson (http://jeremyj.com)
|
||||
* Cristian Deluxe (djcristiandeluxe [at] gmail [dot] com)
|
||||
* Mikhail Moskalev (mmv.rus [at] gmail [dot] com)
|
||||
*
|
||||
* http://www.mikrotik.com
|
||||
* http://wiki.mikrotik.com/wiki/API_PHP_class
|
||||
*
|
||||
******************************/
|
||||
|
||||
class RouterosAPI
|
||||
{
|
||||
var $debug = false; // Show debug information
|
||||
var $connected = false; // Connection state
|
||||
var $port = 8728; // Port to connect to (default 8729 for ssl)
|
||||
var $ssl = false; // Connect using SSL (must enable api-ssl in IP/Services)
|
||||
var $timeout = 2; // Connection attempt timeout and data read timeout
|
||||
var $attempts = 2; // Connection attempt count
|
||||
var $delay = 2; // Delay between connection attempts in seconds
|
||||
var $socket; // Variable for storing socket resource
|
||||
var $error_no; // Variable for storing connection error number, if any
|
||||
var $error_str; // Variable for storing connection error text, if any
|
||||
|
||||
/* Check, can be var used in foreach */
|
||||
public function isIterable($var)
|
||||
{
|
||||
return $var !== null
|
||||
&& (is_array($var)
|
||||
|| $var instanceof Traversable
|
||||
|| $var instanceof Iterator
|
||||
|| $var instanceof IteratorAggregate
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print text for debug purposes
|
||||
*
|
||||
* @param string $text Text to print
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function debug($text)
|
||||
{
|
||||
if ($this->debug) {
|
||||
echo $text . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param string $length
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function encodeLength($length)
|
||||
{
|
||||
if ($length < 0x80) {
|
||||
$length = chr($length);
|
||||
} elseif ($length < 0x4000) {
|
||||
$length |= 0x8000;
|
||||
$length = chr(($length >> 8) & 0xFF) . chr($length & 0xFF);
|
||||
} elseif ($length < 0x200000) {
|
||||
$length |= 0xC00000;
|
||||
$length = chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF);
|
||||
} elseif ($length < 0x10000000) {
|
||||
$length |= 0xE0000000;
|
||||
$length = chr(($length >> 24) & 0xFF) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF);
|
||||
} elseif ($length >= 0x10000000) {
|
||||
$length = chr(0xF0) . chr(($length >> 24) & 0xFF) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF);
|
||||
}
|
||||
|
||||
return $length;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Login to RouterOS
|
||||
*
|
||||
* @param string $ip Hostname (IP or domain) of the RouterOS server
|
||||
* @param string $login The RouterOS username
|
||||
* @param string $password The RouterOS password
|
||||
*
|
||||
* @return boolean If we are connected or not
|
||||
*/
|
||||
public function connect($ip, $login, $password)
|
||||
{
|
||||
for ($ATTEMPT = 1; $ATTEMPT <= $this->attempts; $ATTEMPT++) {
|
||||
$this->connected = false;
|
||||
$PROTOCOL = ($this->ssl ? 'ssl://' : '' );
|
||||
$this->debug('Connection attempt #' . $ATTEMPT . ' to ' . $PROTOCOL . $ip . ':' . $this->port . '...');
|
||||
$this->socket = @fsockopen($PROTOCOL . $ip, $this->port, $this->error_no, $this->error_str, $this->timeout);
|
||||
if ($this->socket) {
|
||||
socket_set_timeout($this->socket, $this->timeout);
|
||||
$this->write('/login');
|
||||
$RESPONSE = $this->read(false);
|
||||
if (isset($RESPONSE[0]) && $RESPONSE[0] == '!done') {
|
||||
$MATCHES = array();
|
||||
if (preg_match_all('/[^=]+/i', $RESPONSE[1], $MATCHES)) {
|
||||
if ($MATCHES[0][0] == 'ret' && strlen($MATCHES[0][1]) == 32) {
|
||||
$this->write('/login', false);
|
||||
$this->write('=name=' . $login, false);
|
||||
$this->write('=response=00' . md5(chr(0) . $password . pack('H*', $MATCHES[0][1])));
|
||||
$RESPONSE = $this->read(false);
|
||||
if ($RESPONSE[0] == '!done') {
|
||||
$this->connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose($this->socket);
|
||||
}
|
||||
sleep($this->delay);
|
||||
}
|
||||
|
||||
if ($this->connected) {
|
||||
$this->debug('Connected...');
|
||||
} else {
|
||||
$this->debug('Error...');
|
||||
}
|
||||
return $this->connected;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disconnect from RouterOS
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
// let's make sure this socket is still valid. it may have been closed by something else
|
||||
if( is_resource($this->socket) ) {
|
||||
fclose($this->socket);
|
||||
}
|
||||
$this->connected = false;
|
||||
$this->debug('Disconnected...');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse response from Router OS
|
||||
*
|
||||
* @param array $response Response data
|
||||
*
|
||||
* @return array Array with parsed data
|
||||
*/
|
||||
public function parseResponse($response)
|
||||
{
|
||||
if (is_array($response)) {
|
||||
$PARSED = array();
|
||||
$CURRENT = null;
|
||||
$singlevalue = null;
|
||||
foreach ($response as $x) {
|
||||
if (in_array($x, array('!fatal','!re','!trap'))) {
|
||||
if ($x == '!re') {
|
||||
$CURRENT =& $PARSED[];
|
||||
} else {
|
||||
$CURRENT =& $PARSED[$x][];
|
||||
}
|
||||
} elseif ($x != '!done') {
|
||||
$MATCHES = array();
|
||||
if (preg_match_all('/[^=]+/i', $x, $MATCHES)) {
|
||||
if ($MATCHES[0][0] == 'ret') {
|
||||
$singlevalue = $MATCHES[0][1];
|
||||
}
|
||||
$CURRENT[$MATCHES[0][0]] = (isset($MATCHES[0][1]) ? $MATCHES[0][1] : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($PARSED) && !is_null($singlevalue)) {
|
||||
$PARSED = $singlevalue;
|
||||
}
|
||||
|
||||
return $PARSED;
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse response from Router OS
|
||||
*
|
||||
* @param array $response Response data
|
||||
*
|
||||
* @return array Array with parsed data
|
||||
*/
|
||||
public function parseResponse4Smarty($response)
|
||||
{
|
||||
if (is_array($response)) {
|
||||
$PARSED = array();
|
||||
$CURRENT = null;
|
||||
$singlevalue = null;
|
||||
foreach ($response as $x) {
|
||||
if (in_array($x, array('!fatal','!re','!trap'))) {
|
||||
if ($x == '!re') {
|
||||
$CURRENT =& $PARSED[];
|
||||
} else {
|
||||
$CURRENT =& $PARSED[$x][];
|
||||
}
|
||||
} elseif ($x != '!done') {
|
||||
$MATCHES = array();
|
||||
if (preg_match_all('/[^=]+/i', $x, $MATCHES)) {
|
||||
if ($MATCHES[0][0] == 'ret') {
|
||||
$singlevalue = $MATCHES[0][1];
|
||||
}
|
||||
$CURRENT[$MATCHES[0][0]] = (isset($MATCHES[0][1]) ? $MATCHES[0][1] : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($PARSED as $key => $value) {
|
||||
$PARSED[$key] = $this->arrayChangeKeyName($value);
|
||||
}
|
||||
return $PARSED;
|
||||
if (empty($PARSED) && !is_null($singlevalue)) {
|
||||
$PARSED = $singlevalue;
|
||||
}
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Change "-" and "/" from array key to "_"
|
||||
*
|
||||
* @param array $array Input array
|
||||
*
|
||||
* @return array Array with changed key names
|
||||
*/
|
||||
public function arrayChangeKeyName(&$array)
|
||||
{
|
||||
if (is_array($array)) {
|
||||
foreach ($array as $k => $v) {
|
||||
$tmp = str_replace("-", "_", $k);
|
||||
$tmp = str_replace("/", "_", $tmp);
|
||||
if ($tmp) {
|
||||
$array_new[$tmp] = $v;
|
||||
} else {
|
||||
$array_new[$k] = $v;
|
||||
}
|
||||
}
|
||||
return $array_new;
|
||||
} else {
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read data from Router OS
|
||||
*
|
||||
* @param boolean $parse Parse the data? default: true
|
||||
*
|
||||
* @return array Array with parsed or unparsed data
|
||||
*/
|
||||
public function read($parse = true)
|
||||
{
|
||||
$RESPONSE = array();
|
||||
$receiveddone = false;
|
||||
while (true) {
|
||||
// Read the first byte of input which gives us some or all of the length
|
||||
// of the remaining reply.
|
||||
$BYTE = ord(fread($this->socket, 1));
|
||||
$LENGTH = 0;
|
||||
// If the first bit is set then we need to remove the first four bits, shift left 8
|
||||
// and then read another byte in.
|
||||
// We repeat this for the second and third bits.
|
||||
// If the fourth bit is set, we need to remove anything left in the first byte
|
||||
// and then read in yet another byte.
|
||||
if ($BYTE & 128) {
|
||||
if (($BYTE & 192) == 128) {
|
||||
$LENGTH = (($BYTE & 63) << 8) + ord(fread($this->socket, 1));
|
||||
} else {
|
||||
if (($BYTE & 224) == 192) {
|
||||
$LENGTH = (($BYTE & 31) << 8) + ord(fread($this->socket, 1));
|
||||
$LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1));
|
||||
} else {
|
||||
if (($BYTE & 240) == 224) {
|
||||
$LENGTH = (($BYTE & 15) << 8) + ord(fread($this->socket, 1));
|
||||
$LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1));
|
||||
$LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1));
|
||||
} else {
|
||||
$LENGTH = ord(fread($this->socket, 1));
|
||||
$LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1));
|
||||
$LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1));
|
||||
$LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$LENGTH = $BYTE;
|
||||
}
|
||||
|
||||
$_ = "";
|
||||
|
||||
// If we have got more characters to read, read them in.
|
||||
if ($LENGTH > 0) {
|
||||
$_ = "";
|
||||
$retlen = 0;
|
||||
while ($retlen < $LENGTH) {
|
||||
$toread = $LENGTH - $retlen;
|
||||
$_ .= fread($this->socket, $toread);
|
||||
$retlen = strlen($_);
|
||||
}
|
||||
$RESPONSE[] = $_;
|
||||
$this->debug('>>> [' . $retlen . '/' . $LENGTH . '] bytes read.');
|
||||
}
|
||||
|
||||
// If we get a !done, make a note of it.
|
||||
if ($_ == "!done") {
|
||||
$receiveddone = true;
|
||||
}
|
||||
|
||||
$STATUS = socket_get_status($this->socket);
|
||||
if ($LENGTH > 0) {
|
||||
$this->debug('>>> [' . $LENGTH . ', ' . $STATUS['unread_bytes'] . ']' . $_);
|
||||
}
|
||||
|
||||
if ((!$this->connected && !$STATUS['unread_bytes']) || ($this->connected && !$STATUS['unread_bytes'] && $receiveddone)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($parse) {
|
||||
$RESPONSE = $this->parseResponse($RESPONSE);
|
||||
}
|
||||
|
||||
return $RESPONSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write (send) data to Router OS
|
||||
*
|
||||
* @param string $command A string with the command to send
|
||||
* @param mixed $param2 If we set an integer, the command will send this data as a "tag"
|
||||
* If we set it to boolean true, the funcion will send the comand and finish
|
||||
* If we set it to boolean false, the funcion will send the comand and wait for next command
|
||||
* Default: true
|
||||
*
|
||||
* @return boolean Return false if no command especified
|
||||
*/
|
||||
public function write($command, $param2 = true)
|
||||
{
|
||||
if ($command) {
|
||||
$data = explode("\n", $command);
|
||||
foreach ($data as $com) {
|
||||
$com = trim($com);
|
||||
fwrite($this->socket, $this->encodeLength(strlen($com)) . $com);
|
||||
$this->debug('<<< [' . strlen($com) . '] ' . $com);
|
||||
}
|
||||
|
||||
if (gettype($param2) == 'integer') {
|
||||
fwrite($this->socket, $this->encodeLength(strlen('.tag=' . $param2)) . '.tag=' . $param2 . chr(0));
|
||||
$this->debug('<<< [' . strlen('.tag=' . $param2) . '] .tag=' . $param2);
|
||||
} elseif (gettype($param2) == 'boolean') {
|
||||
fwrite($this->socket, ($param2 ? chr(0) : ''));
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write (send) data to Router OS
|
||||
*
|
||||
* @param string $com A string with the command to send
|
||||
* @param array $arr An array with arguments or queries
|
||||
*
|
||||
* @return array Array with parsed
|
||||
*/
|
||||
public function comm($com, $arr = array())
|
||||
{
|
||||
$count = count($arr);
|
||||
$this->write($com, !$arr);
|
||||
$i = 0;
|
||||
if ($this->isIterable($arr)) {
|
||||
foreach ($arr as $k => $v) {
|
||||
switch ($k[0]) {
|
||||
case "?":
|
||||
$el = "$k=$v";
|
||||
break;
|
||||
case "~":
|
||||
$el = "$k~$v";
|
||||
break;
|
||||
default:
|
||||
$el = "=$k=$v";
|
||||
break;
|
||||
}
|
||||
|
||||
$last = ($i++ == $count - 1);
|
||||
$this->write($el, $last);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard destructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->disconnect();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user