1
0
mirror of https://github.com/pavel-odintsov/fastnetmon synced 2026-07-25 03:44:56 +02:00
Files

224 lines
6.0 KiB
PHP

#!/usr/bin/php
<?php
declare(strict_types=1);
/*****************************
*
* Juniper PHP Integration for Fastnetmon
*
* This script connect to Juniper Router and add or remove a blackhole's rule for the IP attack
*
* Author: Christian David <davidchristia@gmail.com>
*
* Credits for the Netconf API By Juniper/netconf-php <https://github.com/Juniper/netconf-php>
* Script based on Mikrotik Plugin by Maximiliano Dobladez <info@mkesolutions.net>
*
* Made based on a MX5 CLI and not tested yet, please feedback-us in Issues on github
*
* LICENSE: GPLv2 GNU GENERAL PUBLIC LICENSE
*
*
* v1.0 - 5 Dec 18 - initial version
******************************/
error_reporting(E_ALL);
ini_set('display_errors', 'On');
define("_VER", '1.0');
/* NOTE: YOU NEED TO ENABLE NETCONF ON YOUR JUNIPER */
/* https://www.juniper.net/documentation/en_US/junos/topics/task/configuration/netconf-ssh-connection-establishing.html#task-netconf-service-over-ssh-enabling */
/*
Example configuration file /etc/juniper_integration.json:
{
"hostname": "10.0.0.1",
"port": 880,
"username": "user",
"password": "password"
}
*/
$config_path = "/etc/juniper_integration.json";
if (!file_exists($config_path)) {
$msg = "Configuration file not found: " . $config_path;
_log($msg);
echo $msg . "\n";
exit(1);
}
$cfg = json_decode(file_get_contents($config_path), true);
if (!is_array($cfg)) {
$msg = "Failed to parse configuration file: " . $config_path;
_log($msg);
echo $msg . "\n";
exit(1);
}
foreach (['hostname', 'port', 'username', 'password'] as $key) {
if (empty($cfg[$key])) {
$msg = "Missing required config key: " . $key;
_log($msg);
echo $msg . "\n";
exit(1);
}
}
// help
if ($argc > 1 && $argv[1] == "help") {
$msg = "Juniper API Integration for FastNetMon - Ver: " . _VER;
echo $msg;
exit(1);
}
/*
This script will get following params from FastNetMon:
$1 client_ip_as_string
$2 data_direction
$3 pps_as_string
$4 action (ban or unban)
*/
// Ensure that we got all required arguments
if ($argc <= 4) {
$msg = "Juniper API Integration for FastNetMon - Ver: " . _VER . "\n";
$msg .= "missing arguments\n";
$msg .= "php fastnetmon_juniper.php [IP] [data_direction] [pps_as_string] [action]\n";
_log($msg);
echo $msg;
exit(1);
}
// IPv4 or IPv6 address of attack
$IP_ATTACK = $argv[1];
if (filter_var($IP_ATTACK, FILTER_VALIDATE_IP) === false) {
$msg = "Invalid IP address: " . $IP_ATTACK;
_log($msg);
echo $msg . "\n";
exit(1);
}
// incoming, outgoing or unknown
$DIRECTION_ATTACK = $argv[2];
if (!in_array($DIRECTION_ATTACK, ['incoming', 'outgoing', 'unknown'], true)) {
$msg = "Invalid direction: " . $DIRECTION_ATTACK . ". Must be incoming, outgoing, or unknown.";
_log($msg);
echo $msg . "\n";
exit(1);
}
// Power of attack in packets per second
$POWER_ATTACK = $argv[3];
if (!ctype_digit($POWER_ATTACK)) {
$msg = "Invalid pps value: " . $POWER_ATTACK . ". Must be a positive integer.";
_log($msg);
echo $msg . "\n";
exit(1);
}
// Action: ban or unban
$ACTION_ATTACK = $argv[4];
if (!in_array($ACTION_ATTACK, ['ban', 'unban'], true)) {
$msg = "Invalid action: " . $ACTION_ATTACK . ". Must be ban or unban.";
_log($msg);
echo $msg . "\n";
exit(1);
}
$netconf_path = __DIR__ . "/netconf/netconf/Device.php";
if (!file_exists($netconf_path)) {
$msg = "Netconf library not found: " . $netconf_path;
_log($msg);
echo $msg . "\n";
exit(1);
}
if (!function_exists('expect_popen')) {
$msg = "PHP expect extension is required but not installed. Install it with PECL: pecl install expect";
_log($msg);
echo $msg . "\n";
exit(1);
}
set_include_path(get_include_path() . PATH_SEPARATOR . dirname($netconf_path));
require_once $netconf_path;
$conn = new Device($cfg);
$time_now = date("Y-m-d H:i:s", time());
if ($ACTION_ATTACK == 'ban') {
try {
$desc = 'FastNetMon Community: IP ' . $IP_ATTACK . ' blocked because ' . $DIRECTION_ATTACK . ' attack with power ' . $POWER_ATTACK . ' pps | at ' . $time_now;
$conn->connect();
$locked = $conn->lock_config();
if ($locked) {
// Community 65535:666 = BLACKHOLE
$conn->load_set_configuration("set routing-options static route {$IP_ATTACK} community 65535:666 discard");
$conn->commit();
}
$conn->unlock();
$conn->close();
_log($desc);
echo $desc . "\n";
} catch (NetconfException $e) {
$msg = "Couldn't connect to " . $cfg['hostname'] . " - " . $e->getMessage();
_log($msg);
echo $msg . "\n";
exit(1);
} catch (Exception $e) {
$msg = "Ban failed for " . $IP_ATTACK . " - " . $e->getMessage();
_log($msg);
echo $msg . "\n";
exit(1);
}
} elseif ($ACTION_ATTACK == 'unban') {
try {
$desc = 'FastNetMon Community: IP ' . $IP_ATTACK . ' remove from blacklist.';
$conn->connect();
$locked = $conn->lock_config();
if ($locked) {
$conn->load_set_configuration("delete routing-options static route {$IP_ATTACK}/32");
$conn->commit();
}
$conn->unlock();
$conn->close();
_log($desc);
echo $desc . "\n";
} catch (NetconfException $e) {
$msg = "Couldn't connect to " . $cfg['hostname'] . " - " . $e->getMessage();
_log($msg);
echo $msg . "\n";
exit(1);
} catch (Exception $e) {
$msg = "Unban failed for " . $IP_ATTACK . " - " . $e->getMessage();
_log($msg);
echo $msg . "\n";
exit(1);
}
} else {
$msg = "Unknown action: " . $ACTION_ATTACK;
_log($msg);
echo $msg . "\n";
exit(1);
}
/**
* [_log Write a log file]
* @param string $msg text to log
*/
function _log(string $msg): void
{
$FILE_LOG_TMP = "/tmp/fastnetmon_api_juniper.log";
$line = date("D M j H:i:s T Y") . " - [FASTNETMON] - " . $msg . "\n";
file_put_contents($FILE_LOG_TMP, $line, FILE_APPEND);
}
?>