2603.9 frequesnt IPs added
This commit is contained in:
70
api/frequent_ips.php
Normal file
70
api/frequent_ips.php
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* GET /api/frequent_ips.php
|
||||||
|
*
|
||||||
|
* Returns all source IPs with a total connection count >= the configured
|
||||||
|
* threshold (frequent_ip_threshold setting, default 5), sorted highest first.
|
||||||
|
*
|
||||||
|
* Authentication (any one of):
|
||||||
|
* - Active web session (logged-in browser)
|
||||||
|
* - Authorization: Bearer <TRIGGER_TOKEN>
|
||||||
|
* - ?token=<TRIGGER_TOKEN>
|
||||||
|
*
|
||||||
|
* Optional query parameters:
|
||||||
|
* threshold int Override the configured minimum connection count
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../includes/auth.php';
|
||||||
|
require_once __DIR__ . '/../includes/functions.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
// ── Auth ──────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
$session_ok = false;
|
||||||
|
if (auth_enabled()) {
|
||||||
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
|
session_start();
|
||||||
|
}
|
||||||
|
$session_ok = !empty($_SESSION['authenticated']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$token_ok = false;
|
||||||
|
if (TRIGGER_TOKEN !== '') {
|
||||||
|
$provided = '';
|
||||||
|
$auth_header = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
|
||||||
|
if (str_starts_with($auth_header, 'Bearer ')) {
|
||||||
|
$provided = substr($auth_header, 7);
|
||||||
|
}
|
||||||
|
if ($provided === '' && isset($_REQUEST['token'])) {
|
||||||
|
$provided = $_REQUEST['token'];
|
||||||
|
}
|
||||||
|
$token_ok = $provided !== '' && hash_equals(TRIGGER_TOKEN, $provided);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$session_ok && !$token_ok) {
|
||||||
|
http_response_code(401);
|
||||||
|
echo json_encode(['error' => 'Unauthorized']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Query ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
$configured_threshold = max(1, (int)get_setting('frequent_ip_threshold', '5'));
|
||||||
|
$threshold = isset($_GET['threshold'])
|
||||||
|
? max(1, (int)$_GET['threshold'])
|
||||||
|
: $configured_threshold;
|
||||||
|
|
||||||
|
$rows = frequent_ips($threshold);
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'threshold' => $threshold,
|
||||||
|
'configured_threshold' => $configured_threshold,
|
||||||
|
'count' => count($rows),
|
||||||
|
'ips' => array_map(fn($r) => [
|
||||||
|
'src_ip' => $r['src_ip'],
|
||||||
|
'total_connections' => (int)$r['total_connections'],
|
||||||
|
'first_seen' => $r['first_seen'],
|
||||||
|
'last_seen' => $r['last_seen'],
|
||||||
|
], $rows),
|
||||||
|
], JSON_PRETTY_PRINT);
|
||||||
@@ -198,6 +198,27 @@ function set_setting(string $key, string $value): void {
|
|||||||
$s->execute([$key, $value]);
|
$s->execute([$key, $value]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Frequent IPs ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all IPs with a total connection count >= $min_connections, sorted
|
||||||
|
* highest-count first. Includes first and last seen timestamps.
|
||||||
|
*/
|
||||||
|
function frequent_ips(int $min_connections): array {
|
||||||
|
$s = db()->prepare(
|
||||||
|
'SELECT src_ip,
|
||||||
|
COUNT(*) AS total_connections,
|
||||||
|
MIN(occurred_at) AS first_seen,
|
||||||
|
MAX(occurred_at) AS last_seen
|
||||||
|
FROM connections
|
||||||
|
GROUP BY src_ip
|
||||||
|
HAVING total_connections >= ?
|
||||||
|
ORDER BY total_connections DESC'
|
||||||
|
);
|
||||||
|
$s->execute([$min_connections]);
|
||||||
|
return $s->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
// ── Purge ─────────────────────────────────────────────────────────────────────
|
// ── Purge ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -39,3 +39,4 @@ CREATE TABLE IF NOT EXISTS settings (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
INSERT IGNORE INTO settings (key_name, value) VALUES ('retention_days', '7');
|
INSERT IGNORE INTO settings (key_name, value) VALUES ('retention_days', '7');
|
||||||
|
INSERT IGNORE INTO settings (key_name, value) VALUES ('frequent_ip_threshold', '5');
|
||||||
|
|||||||
28
settings.php
28
settings.php
@@ -34,10 +34,20 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
set_setting('retention_days', (string)$days);
|
set_setting('retention_days', (string)$days);
|
||||||
$success = 'Retention period saved.';
|
$success = 'Retention period saved.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} elseif ($action === 'frequent_ip_threshold') {
|
||||||
|
$threshold = (int)($_POST['frequent_ip_threshold'] ?? 0);
|
||||||
|
if ($threshold < 1) {
|
||||||
|
$errors[] = 'Threshold must be at least 1.';
|
||||||
|
} else {
|
||||||
|
set_setting('frequent_ip_threshold', (string)$threshold);
|
||||||
|
$success = 'Frequent IP threshold saved.';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$retention_days = (int)get_setting('retention_days', '7');
|
$retention_days = (int)get_setting('retention_days', '7');
|
||||||
|
$frequent_ip_threshold = (int)get_setting('frequent_ip_threshold', '5');
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@@ -106,6 +116,22 @@ $retention_days = (int)get_setting('retention_days', '7');
|
|||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="card">
|
||||||
|
<h2>Frequent IP threshold</h2>
|
||||||
|
<p class="muted" style="margin-bottom:1rem;font-size:.85rem">
|
||||||
|
Minimum number of connections for an IP to appear in
|
||||||
|
<code>api/frequent_ips.php</code>.
|
||||||
|
</p>
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="action" value="frequent_ip_threshold">
|
||||||
|
<label>Minimum connections
|
||||||
|
<input type="number" name="frequent_ip_threshold" min="1" max="99999"
|
||||||
|
value="<?= $frequent_ip_threshold ?>" style="width:120px">
|
||||||
|
</label>
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
<?php include __DIR__ . '/includes/footer.php'; ?>
|
<?php include __DIR__ . '/includes/footer.php'; ?>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -50,5 +50,6 @@ $pdo->exec(
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"
|
||||||
);
|
);
|
||||||
$pdo->exec("INSERT IGNORE INTO settings (key_name, value) VALUES ('retention_days', '7')");
|
$pdo->exec("INSERT IGNORE INTO settings (key_name, value) VALUES ('retention_days', '7')");
|
||||||
|
$pdo->exec("INSERT IGNORE INTO settings (key_name, value) VALUES ('frequent_ip_threshold', '5')");
|
||||||
|
|
||||||
echo "Database '" . DB_NAME . "' and tables created/migrated successfully.\n";
|
echo "Database '" . DB_NAME . "' and tables created/migrated successfully.\n";
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
<?php
|
<?php
|
||||||
define('APP_VERSION', '2603.8');
|
define('APP_VERSION', '2603.9');
|
||||||
|
|||||||
Reference in New Issue
Block a user