Merge branch 'IpNetwork/v2' into 'master'
ipnetwork v2 update See merge request fronk/thetool!1672
This commit is contained in:
@@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property mixed|null $name
|
|
||||||
*/
|
|
||||||
class IpNetwork extends mfBaseModel
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
// IpNetworkController.php
|
||||||
|
|
||||||
class IpNetworkController extends mfBaseController {
|
class IpNetworkController extends mfBaseController {
|
||||||
private User $me;
|
private User $me;
|
||||||
|
|
||||||
|
|
||||||
protected function init(): void {
|
protected function init(): void {
|
||||||
$me = new User();
|
$me = new User();
|
||||||
$me->loadMe();
|
$me->loadMe();
|
||||||
@@ -16,15 +16,14 @@ class IpNetworkController extends mfBaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function indexAction(): void {
|
protected function indexAction(): void {
|
||||||
$JSGlobals = ["BASE_URL" => self::getUrl("IpNetwork"),
|
$JSGlobals = [
|
||||||
"DASHBOARD_URL" => self::getUrl("Dashboard"),
|
"BASE_URL" => self::getUrl("IpNetwork"),
|
||||||
"MFAPPNAME" => MFAPPNAME_SLUG,
|
"API_BASE_URL" => self::getUrl("IpNetwork"),
|
||||||
"PAGE_TITLE" => "IPAM",
|
"PAGE_TITLE" => "IPAM",
|
||||||
"PATH" => [
|
"PATH" => [
|
||||||
["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
|
["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
|
||||||
["text" => "IPAM", "href" => self::getUrl("IpNetwork")]
|
["text" => "IPAM", "href" => self::getUrl("IpNetwork")]
|
||||||
],
|
],
|
||||||
"IPNETWORK_API_URL" => self::getUrl("IpNetwork/api"),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->layout()->set("vueViewName", "IpNetwork");
|
$this->layout()->set("vueViewName", "IpNetwork");
|
||||||
@@ -32,187 +31,124 @@ class IpNetworkController extends mfBaseController {
|
|||||||
$this->layout()->setTemplate("VueViews/Vue");
|
$this->layout()->setTemplate("VueViews/Vue");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function apiAction() {
|
protected function getAction() {
|
||||||
$do = $this->request->do;
|
|
||||||
|
|
||||||
if (!$this->me->isAdmin()) {
|
|
||||||
$this->redirect("dashboard");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($do) {
|
|
||||||
case "get":
|
|
||||||
$return = $this->get();
|
|
||||||
break;
|
|
||||||
case "getById":
|
|
||||||
$return = $this->getById();
|
|
||||||
break;
|
|
||||||
case "create":
|
|
||||||
$return = $this->create();
|
|
||||||
break;
|
|
||||||
case "update":
|
|
||||||
$return = $this->update();
|
|
||||||
break;
|
|
||||||
case "delete":
|
|
||||||
$return = $this->delete();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$return = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$return) {
|
|
||||||
$return = [
|
|
||||||
"status" => "error",
|
|
||||||
"message" => "Invalid request."
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
die(json_encode($return));
|
|
||||||
}
|
|
||||||
|
|
||||||
private function aggregateChildren($network, &$childrenCount) {
|
|
||||||
$children = IpNetworkModel::getChildren($network->id);
|
|
||||||
|
|
||||||
foreach ($children as $child) {
|
|
||||||
$childrenCount++;
|
|
||||||
if ($child->cidr !== 32) {
|
|
||||||
$this->aggregateChildren($child, $childrenCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get(): array {
|
|
||||||
$json = json_decode(file_get_contents('php://input'), true);
|
$json = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
$filters = $json['filters'] ?? [];
|
$filters = $json['filters'] ?? [];
|
||||||
$order = $json['order'] ?? [];
|
$order = $json['order'] ?? ['key' => 'network_address', 'order' => 'asc'];
|
||||||
$page = $json['pagination']['page'] ?? 1;
|
$page = $json['pagination']['page'] ?? 1;
|
||||||
$perPage = $json['pagination']['per_page'] ?? 10;
|
$perPage = $json['pagination']['per_page'] ?? 50;
|
||||||
|
$offset = ($page - 1) * $perPage;
|
||||||
|
|
||||||
$orderChildren = false;
|
$networks = IpNetworkModel::getIpNetworks($filters, $perPage, $offset, $order);
|
||||||
|
$total_rows = IpNetworkModel::countIpNetworks($filters);
|
||||||
|
|
||||||
if ($order['key'] === 'network_address_str') {
|
self::returnJson([
|
||||||
$order['key'] = 'network_address';
|
"rows" => $networks,
|
||||||
} else if ($order['key'] === 'children') {
|
|
||||||
$orderChildren = $order['order'];
|
|
||||||
$order = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$networks = IpNetworkModel::getIpNetworks($filters, null, $perPage * $page - $perPage, $order);
|
|
||||||
$total_rows = IpNetworkModel::countIpNetworks([
|
|
||||||
"parent_network_id" => $filters['parent_network_id'] ?? ''
|
|
||||||
]);
|
|
||||||
|
|
||||||
$processedNetworks = [];
|
|
||||||
|
|
||||||
foreach ($networks as $network) {
|
|
||||||
$childrenCount = 0;
|
|
||||||
$this->aggregateChildren($network, $childrenCount);
|
|
||||||
|
|
||||||
$from = $filters['children']['from'] ?? null;
|
|
||||||
$to = $filters['children']['to'] ?? null;
|
|
||||||
|
|
||||||
if (($from !== null && $childrenCount < $from) || ($to !== null && $childrenCount > $to)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$network->children = $childrenCount;
|
|
||||||
$processedNetworks[] = $network;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($orderChildren) {
|
|
||||||
usort($processedNetworks, function ($a, $b) use ($orderChildren) {
|
|
||||||
if ($orderChildren === 'asc') {
|
|
||||||
return $a->children <=> $b->children;
|
|
||||||
} else {
|
|
||||||
return $b->children <=> $a->children;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
"rows" => array_slice($processedNetworks, $perPage * $page - $perPage, $perPage),
|
|
||||||
"pagination" => [
|
"pagination" => [
|
||||||
"page" => $page,
|
"page" => $page,
|
||||||
"total_pages" => ceil(count($processedNetworks) / $perPage),
|
"total_pages" => ceil($total_rows / $perPage),
|
||||||
"filtered_available" => count($processedNetworks),
|
"filtered_available" => intval($total_rows),
|
||||||
"per_page" => $perPage,
|
"per_page" => $perPage,
|
||||||
"total_rows" => intval($total_rows)
|
"total_rows" => intval($total_rows)
|
||||||
]
|
]
|
||||||
];
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getById(): array {
|
protected function getByIdAction() {
|
||||||
$json = json_decode(file_get_contents('php://input'), true);
|
$id = $this->request->id;
|
||||||
|
if (!$id) {
|
||||||
$network = IpNetworkModel::getById($json['id']);
|
self::sendError("Network ID is missing.");
|
||||||
|
|
||||||
if ($network === null) {
|
|
||||||
return [
|
|
||||||
"status" => "error",
|
|
||||||
"message" => "Network not found."
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
$network = IpNetworkModel::getById($id);
|
||||||
"status" => "success",
|
|
||||||
"network" => $network
|
if ($network === null) {
|
||||||
];
|
self::sendError("Network not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
self::returnJson(["success" => true, "network" => $network]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function globalSearchAction() {
|
||||||
|
$query = $this->request->q ?? '';
|
||||||
|
if (strlen($query) < 2) {
|
||||||
|
self::returnJson([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$suggestions = IpNetworkModel::findSuggestions($query);
|
||||||
|
self::returnJson($suggestions);
|
||||||
|
}
|
||||||
|
|
||||||
private function create(): array {
|
protected function findNetworkByStringAction() {
|
||||||
|
$networkString = $this->request->network_string;
|
||||||
|
if (!$networkString) {
|
||||||
|
self::sendError("Network string is missing.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$network = IpNetworkModel::findByNetworkString($networkString);
|
||||||
|
|
||||||
|
if ($network === null) {
|
||||||
|
self::sendError("Network not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$navigateToId = null;
|
||||||
|
if ($network->cidr < 31) {
|
||||||
|
$navigateToId = $network->id;
|
||||||
|
} else {
|
||||||
|
$navigateToId = $network->parent_network_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::returnJson(["success" => true, "navigateToId" => $navigateToId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createAction() {
|
||||||
$json = json_decode(file_get_contents('php://input'), true);
|
$json = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IpNetworkModel::createIpNetwork($json);
|
IpNetworkModel::createIpNetwork($json);
|
||||||
return [
|
self::returnJson([
|
||||||
"status" => "success",
|
"success" => true,
|
||||||
"message" => "IP Network created."
|
"message" => "IP-Netzwerk wurde erstellt."
|
||||||
];
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return [
|
self::sendError($e->getMessage());
|
||||||
"status" => "error",
|
|
||||||
"message" => $e->getMessage()
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function update(): array {
|
protected function updateAction() {
|
||||||
$json = json_decode(file_get_contents('php://input'), true);
|
$json = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
if (empty($json['id'])) {
|
||||||
|
self::sendError("Netzwerk-ID fehlt.");
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IpNetworkModel::updateIpNetwork($json);
|
IpNetworkModel::updateIpNetwork($json);
|
||||||
return [
|
self::returnJson([
|
||||||
"status" => "success",
|
"success" => true,
|
||||||
"message" => "IP Network updated."
|
"message" => "IP-Netzwerk wurde aktualisiert."
|
||||||
];
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return [
|
self::sendError($e->getMessage());
|
||||||
"status" => "error",
|
|
||||||
"message" => $e->getMessage()
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function delete(): array {
|
protected function deleteAction() {
|
||||||
$json = json_decode(file_get_contents('php://input'), true);
|
$json = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
if (empty($json['id'])) {
|
||||||
|
self::sendError("Netzwerk-ID fehlt.");
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IpNetworkModel::deleteIpNetwork($json['id']);
|
IpNetworkModel::deleteIpNetwork($json['id']);
|
||||||
return [
|
self::returnJson([
|
||||||
"status" => "success",
|
"success" => true,
|
||||||
"message" => "IP Network deleted."
|
"message" => "IP-Netzwerk wurde gelöscht."
|
||||||
];
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return [
|
self::sendError($e->getMessage());
|
||||||
"status" => "error",
|
|
||||||
"message" => $e->getMessage()
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
// IpNetworkModel.php
|
||||||
|
|
||||||
class IpNetworkModel {
|
class IpNetworkModel {
|
||||||
|
|
||||||
@@ -7,6 +8,7 @@ class IpNetworkModel {
|
|||||||
public $cidr;
|
public $cidr;
|
||||||
public $parent_network_id;
|
public $parent_network_id;
|
||||||
public $status;
|
public $status;
|
||||||
|
public $children;
|
||||||
public $network_address_str;
|
public $network_address_str;
|
||||||
public $name;
|
public $name;
|
||||||
public $description;
|
public $description;
|
||||||
@@ -22,14 +24,52 @@ class IpNetworkModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function getSqlFilter(array $filters): string {
|
||||||
|
$sqlConditions = [];
|
||||||
|
$db = FronkDB::singleton()->link;
|
||||||
|
|
||||||
|
if (!empty($filters['globalSearch'])) {
|
||||||
|
$searchTerm = $db->real_escape_string($filters['globalSearch']);
|
||||||
|
$sqlConditions[] = " (CONCAT(INET_NTOA(network_address), '/', cidr) LIKE '%{$searchTerm}%' OR `name` LIKE '%{$searchTerm}%' OR `description` LIKE '%{$searchTerm}%') ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($filters['name'])) $sqlConditions[] = Helper::generateFilterCondition($filters['name'], 'name');
|
||||||
|
if (isset($filters['description'])) $sqlConditions[] = Helper::generateFilterCondition($filters['description'], 'description');
|
||||||
|
if (isset($filters['location'])) $sqlConditions[] = Helper::generateFilterCondition($filters['location'], 'location');
|
||||||
|
if (isset($filters['status'])) $sqlConditions[] = Helper::generateFilterCondition($filters['status'], 'status');
|
||||||
|
|
||||||
|
if (empty($filters['parent_network_id'])) {
|
||||||
|
$sqlConditions[] = " `parent_network_id` IS NULL ";
|
||||||
|
} else {
|
||||||
|
$sqlConditions[] = " `parent_network_id` = " . intval($filters['parent_network_id']) . " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return empty($sqlConditions) ? "" : " WHERE " . implode(" AND ", $sqlConditions);
|
||||||
|
}
|
||||||
|
|
||||||
public static function getIpNetworks($filters, $limit = null, $offset = 0, $order = null): array {
|
public static function getIpNetworks($filters, $limit = null, $offset = 0, $order = null): array {
|
||||||
$db = FronkDB::singleton();
|
$db = FronkDB::singleton()->link;
|
||||||
|
|
||||||
|
$orderClause = "ORDER BY `network_address` ASC";
|
||||||
|
if ($order && !empty($order['key'])) {
|
||||||
|
$orderKey = $db->real_escape_string($order['key']);
|
||||||
|
$orderDir = (isset($order['order']) && strtolower($order['order']) === 'desc') ? 'DESC' : 'ASC';
|
||||||
|
if ($orderKey === 'network_address_str') $orderKey = 'network_address';
|
||||||
|
$orderClause = "ORDER BY `{$orderKey}` {$orderDir}";
|
||||||
|
}
|
||||||
|
|
||||||
|
$limitClause = is_null($limit) ? "" : " LIMIT " . intval($limit) . " OFFSET " . intval($offset);
|
||||||
|
|
||||||
|
$sql = "
|
||||||
|
SELECT
|
||||||
|
main.*,
|
||||||
|
CONCAT(INET_NTOA(main.network_address), '/', main.cidr) AS network_address_str,
|
||||||
|
(SELECT COUNT(*) FROM `IpNetwork` WHERE `parent_network_id` = main.id) as children
|
||||||
|
FROM `IpNetwork` main
|
||||||
|
" . self::getSqlFilter($filters) . "
|
||||||
|
" . $orderClause . "
|
||||||
|
" . $limitClause;
|
||||||
|
|
||||||
$sql = "SELECT *, CONCAT(INET_NTOA(network_address), '/', cidr) AS network_address_str FROM `IpNetwork` WHERE 1 ";
|
|
||||||
$sql .= isset($filters['network_address_str']) ? " AND CONCAT(INET_NTOA(network_address), '/', cidr) LIKE '%" . $filters['network_address_str'] . "%'" : "";
|
|
||||||
$sql .= self::getSqlFilter($filters);
|
|
||||||
$sql .= $order === null || $order['key'] === null ? " ORDER BY `network_address` ASC" : " ORDER BY `" . $order['key'] . "` " . $order['order'];
|
|
||||||
$sql .= $limit === null ? "" : " LIMIT " . $limit . " OFFSET " . $offset;
|
|
||||||
|
|
||||||
$result = $db->query($sql);
|
$result = $db->query($sql);
|
||||||
$rows = [];
|
$rows = [];
|
||||||
@@ -40,209 +80,140 @@ class IpNetworkModel {
|
|||||||
return $rows;
|
return $rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getSqlFilter($filters): string {
|
public static function findByNetworkString(string $networkString): ?IpNetworkModel {
|
||||||
$sql = isset($filters['name']) ? Helper::generateFilterCondition($filters['name'], 'name') : "";
|
$db = FronkDB::singleton()->link;
|
||||||
$sql .= isset($filters['description']) ? Helper::generateFilterCondition($filters['description'], 'description') : "";
|
if (!str_contains($networkString, '/')) {
|
||||||
$sql .= isset($filters['location']) ? Helper::generateFilterCondition($filters['location'], 'location') : "";
|
return null;
|
||||||
$sql .= isset($filters['status']) ? Helper::generateFilterCondition($filters['status'], 'status') : "";
|
|
||||||
$sql .= empty($filters['parent_network_id']) ? " AND `parent_network_id` IS NULL" : " AND `parent_network_id` = " . $filters['parent_network_id'];
|
|
||||||
|
|
||||||
return $sql;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function countIpNetworks($filters) {
|
|
||||||
$db = FronkDB::singleton();
|
|
||||||
$sql = "SELECT COUNT(*) as `total_rows` FROM `IpNetwork` WHERE 1 " . self::getSqlFilter($filters);
|
|
||||||
$result = $db->query($sql);
|
|
||||||
return $result->fetch_assoc()['total_rows'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function countChildren($id) {
|
|
||||||
$db = FronkDB::singleton();
|
|
||||||
$sql = "SELECT COUNT(*) as `total_rows` FROM `IpNetwork` WHERE `parent_network_id` = $id";
|
|
||||||
$result = $db->query($sql);
|
|
||||||
return $result->fetch_assoc()['total_rows'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getChildren($id): array {
|
|
||||||
$db = FronkDB::singleton();
|
|
||||||
$sql = "SELECT * FROM `IpNetwork` WHERE `parent_network_id` = $id";
|
|
||||||
$result = $db->query($sql);
|
|
||||||
$rows = [];
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$rows[] = new IpNetworkModel($row);
|
|
||||||
}
|
}
|
||||||
|
// Extract IP and CIDR, allowing for extra text like "(My Network)"
|
||||||
|
preg_match('/^([0-9\.]+)\/(\d+)/', $networkString, $matches);
|
||||||
|
if (count($matches) < 3) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$ip = $db->real_escape_string($matches[1]);
|
||||||
|
$cidr = (int)$matches[2];
|
||||||
|
|
||||||
return $rows;
|
$sql = "SELECT * FROM `IpNetwork` WHERE `network_address` = INET_ATON('$ip') AND `cidr` = $cidr";
|
||||||
|
$result = $db->query($sql);
|
||||||
|
$row = $result->fetch_assoc();
|
||||||
|
return $row ? new IpNetworkModel($row) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function countIpNetworks($filters): int {
|
||||||
|
$db = FronkDB::singleton()->link;
|
||||||
|
$sql = "SELECT COUNT(*) as `total_rows` FROM `IpNetwork`" . self::getSqlFilter($filters);
|
||||||
|
$result = $db->query($sql);
|
||||||
|
return (int)$result->fetch_assoc()['total_rows'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function findSuggestions(string $query, int $limit = 10): array {
|
||||||
|
$db = FronkDB::singleton()->link;
|
||||||
|
$query = $db->real_escape_string($query);
|
||||||
|
$sql = "
|
||||||
|
SELECT
|
||||||
|
CONCAT(INET_NTOA(network_address), '/', cidr) as network_address_str,
|
||||||
|
name
|
||||||
|
FROM `IpNetwork`
|
||||||
|
WHERE
|
||||||
|
CONCAT(INET_NTOA(network_address), '/', cidr) LIKE '%{$query}%' OR
|
||||||
|
`name` LIKE '%{$query}%' OR
|
||||||
|
`description` LIKE '%{$query}%'
|
||||||
|
LIMIT " . $limit;
|
||||||
|
|
||||||
|
$result = $db->query($sql);
|
||||||
|
$suggestions = [];
|
||||||
|
while ($row = $result->fetch_assoc()) {
|
||||||
|
$text = $row['network_address_str'];
|
||||||
|
if ($row['name']) {
|
||||||
|
$text .= " ({$row['name']})";
|
||||||
|
}
|
||||||
|
$suggestions[] = [
|
||||||
|
'value' => $row['network_address_str'],
|
||||||
|
'text' => $text
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $suggestions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function createIpNetwork($data): void {
|
public static function createIpNetwork($data): void {
|
||||||
$db = FronkDB::singleton();
|
$db = FronkDB::singleton()->link;
|
||||||
|
|
||||||
$network_address = $data['network_address'];
|
$network_address = $data['network_address'];
|
||||||
$cidr = $data['cidr'];
|
if (!filter_var($network_address, FILTER_VALIDATE_IP)) {
|
||||||
$parent_network_id = $data['parent_network_id'] ?? 'NULL';
|
throw new Exception("Ungültige IP-Adresse angegeben.");
|
||||||
$status = $data['status'];
|
}
|
||||||
$name = $data['name'];
|
|
||||||
$description = $data['description'];
|
|
||||||
$location = $data['location'];
|
|
||||||
|
|
||||||
// Convert network address to integer
|
$cidr = (int)$data['cidr'];
|
||||||
$network_address_int = ip2long($network_address);
|
$parent_network_id = !empty($data['parent_network_id']) ? (int)$data['parent_network_id'] : 'NULL';
|
||||||
|
$status = $db->real_escape_string($data['status']);
|
||||||
// Define query to check for overlapping networks
|
$name = $db->real_escape_string($data['name']);
|
||||||
$check_sql = "
|
$description = $db->real_escape_string($data['description']);
|
||||||
SELECT `id`, `network_address`, `cidr`
|
$location = $db->real_escape_string($data['location']);
|
||||||
FROM `IpNetwork`
|
|
||||||
WHERE (
|
|
||||||
(INET_ATON('$network_address') & ~((1 << (32 - `cidr`)) - 1)) = `network_address`
|
|
||||||
OR
|
|
||||||
(`network_address` & ~((1 << (32 - $cidr)) - 1)) = INET_ATON('$network_address')
|
|
||||||
)";
|
|
||||||
|
|
||||||
// die($check_sql);
|
|
||||||
|
|
||||||
|
$check_sql = "SELECT id FROM `IpNetwork` WHERE `network_address` = INET_ATON('$network_address') AND `cidr` = $cidr";
|
||||||
$result = $db->query($check_sql);
|
$result = $db->query($check_sql);
|
||||||
|
if($result->num_rows > 0) {
|
||||||
$parentFound = false;
|
throw new Exception("Ein identisches Netzwerk existiert bereits.");
|
||||||
$parentFoundId = null;
|
|
||||||
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$existing_network_address_int = $row['network_address'];
|
|
||||||
$existing_cidr = $row['cidr'];
|
|
||||||
|
|
||||||
// Check if the new network is within an existing network
|
|
||||||
if ($network_address_int >= $existing_network_address_int &&
|
|
||||||
$network_address_int < ($existing_network_address_int + pow(2, (32 - $existing_cidr)))) {
|
|
||||||
|
|
||||||
if ($cidr <= $existing_cidr) {
|
|
||||||
// The new network is larger or equal, which is invalid
|
|
||||||
if ($cidr == 32) {
|
|
||||||
throw new Exception("Address $network_address/32 already exists");
|
|
||||||
} else {
|
|
||||||
throw new Exception("Network $network_address/$cidr conflicts with existing network " . long2ip($existing_network_address_int) . "/$existing_cidr");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the new network is a correct subnetwork
|
|
||||||
if ($parent_network_id != 'NULL') {
|
|
||||||
$result->data_seek(0);
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
if ($row['id'] == $parent_network_id) {
|
|
||||||
$parentFoundId = $row['id'];
|
|
||||||
$parentFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!$parentFound) {
|
|
||||||
throw new Exception("Parent network ID $parent_network_id does not match the actual parent network ID {$row['id']}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// New check for conflicts with child networks
|
|
||||||
$check_child_sql = "
|
|
||||||
SELECT `id`, `network_address`, `cidr`
|
|
||||||
FROM `IpNetwork`
|
|
||||||
WHERE `parent_network_id` = $parent_network_id
|
|
||||||
AND (
|
|
||||||
INET_ATON('$network_address') BETWEEN `network_address`
|
|
||||||
AND (`network_address` + POW(2, (32 - `cidr`)) - 1)
|
|
||||||
OR
|
|
||||||
`network_address` BETWEEN INET_ATON('$network_address')
|
|
||||||
AND (INET_ATON('$network_address') + POW(2, (32 - $cidr)) - 1)
|
|
||||||
)";
|
|
||||||
;
|
|
||||||
|
|
||||||
$child_result = $db->query($check_child_sql);
|
|
||||||
|
|
||||||
while ($child_row = $child_result->fetch_assoc()) {
|
|
||||||
$existing_child_network_address_int = $child_row['network_address'];
|
|
||||||
$existing_child_cidr = $child_row['cidr'];
|
|
||||||
|
|
||||||
// Check if the new network overlaps any existing child networks
|
|
||||||
if ($network_address_int < $existing_child_network_address_int &&
|
|
||||||
($network_address_int + pow(2, (32 - $cidr))) > $existing_child_network_address_int) {
|
|
||||||
throw new Exception("Network $network_address/$cidr conflicts with child network " . long2ip($existing_child_network_address_int) . "/$existing_child_cidr");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// If no parent ID provided and the new network is within an existing network, throw an error
|
|
||||||
throw new Exception("Network $network_address/$cidr must be a child of " . long2ip($existing_network_address_int) . "/$existing_cidr.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// For CIDR 32, check if it already exists but also check if $parent_network_id is same as $parentFoundId but if $parentFoundId is null, throw an error
|
|
||||||
if ($cidr == 32 && $parent_network_id != 'NULL' && $parent_network_id != $parentFoundId) {
|
|
||||||
throw new Exception("CIDR 32 address $network_address already exists within " . long2ip($existing_network_address_int) . "/$existing_cidr");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the new network overlaps any existing networks
|
|
||||||
if ($network_address_int < $existing_network_address_int &&
|
|
||||||
($network_address_int + pow(2, (32 - $cidr))) > $existing_network_address_int) {
|
|
||||||
throw new Exception("Network $network_address/$cidr overlaps with existing network " . long2ip($existing_network_address_int) . "/$existing_cidr");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$parentFound && $parent_network_id === 'NULL' && intval($cidr) >= 32) {
|
if ($parent_network_id === 'NULL' && $cidr >= 32) {
|
||||||
throw new Exception("Root Networks cannot be single IPs");
|
throw new Exception("Stamm-Netzwerke können keine einzelnen IPs sein.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proceed with insertion if no conflicts are found
|
|
||||||
$sql = "INSERT INTO `IpNetwork` (`network_address`, `cidr`, `parent_network_id`, `status`, `name`, `description`, `location`, `create`, `edit`)
|
$sql = "INSERT INTO `IpNetwork` (`network_address`, `cidr`, `parent_network_id`, `status`, `name`, `description`, `location`, `create`, `edit`)
|
||||||
VALUES (INET_ATON('$network_address'), $cidr, $parent_network_id, '$status', '$name', '$description', '$location', UNIX_TIMESTAMP(), UNIX_TIMESTAMP())";
|
VALUES (INET_ATON('$network_address'), $cidr, $parent_network_id, '$status', '$name', '$description', '$location', UNIX_TIMESTAMP(), UNIX_TIMESTAMP())";
|
||||||
$result = $db->query($sql);
|
|
||||||
|
|
||||||
if (!$result) {
|
if (!$db->query($sql)) {
|
||||||
throw new Exception("Failed to insert network");
|
throw new Exception("Fehler beim Einfügen des Netzwerks: " . $db->error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function updateIpNetwork($data): void {
|
public static function updateIpNetwork($data): void {
|
||||||
$db = FronkDB::singleton();
|
$db = FronkDB::singleton()->link;
|
||||||
|
$id = (int)$data['id'];
|
||||||
|
|
||||||
$sqlSetStr = "";
|
$sqlSetStr = [];
|
||||||
$sqlSetStr .= isset($data['status']) ? "`status` = '" . $data['status'] . "', " : "";
|
if (isset($data['status'])) $sqlSetStr[] = "`status` = '" . $db->real_escape_string($data['status']) . "'";
|
||||||
$sqlSetStr .= isset($data['name']) ? "`name` = '" . $data['name'] . "', " : "";
|
if (isset($data['name'])) $sqlSetStr[] = "`name` = '" . $db->real_escape_string($data['name']) . "'";
|
||||||
$sqlSetStr .= isset($data['description']) ? "`description` = '" . $data['description'] . "', " : "";
|
if (isset($data['description'])) $sqlSetStr[] = "`description` = '" . $db->real_escape_string($data['description']) . "'";
|
||||||
$sqlSetStr .= isset($data['location']) ? "`location` = '" . $data['location'] . "', " : "";
|
if (isset($data['location'])) $sqlSetStr[] = "`location` = '" . $db->real_escape_string($data['location']) . "'";
|
||||||
$sqlSetStr .= "`edit` = UNIX_TIMESTAMP()";
|
|
||||||
|
|
||||||
$sql = "UPDATE `IpNetwork` SET $sqlSetStr WHERE `id` = " . $data['id'];
|
if(empty($sqlSetStr)) return;
|
||||||
$result = $db->query($sql);
|
|
||||||
|
|
||||||
if (!$result) {
|
$sqlSetStr[] = "`edit` = UNIX_TIMESTAMP()";
|
||||||
throw new Exception("Failed to update network");
|
|
||||||
|
$sql = "UPDATE `IpNetwork` SET " . implode(', ', $sqlSetStr) . " WHERE `id` = $id";
|
||||||
|
|
||||||
|
if (!$db->query($sql)) {
|
||||||
|
throw new Exception("Fehler beim Aktualisieren des Netzwerks: " . $db->error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function getById($id) {
|
public static function getById($id) {
|
||||||
$db = FronkDB::singleton();
|
$db = FronkDB::singleton()->link;
|
||||||
$sql = "SELECT *, INET_NTOA(network_address) as network_address_str FROM `IpNetwork` WHERE `id` = $id";
|
$id = (int)$id;
|
||||||
|
$sql = "SELECT *, CONCAT(INET_NTOA(network_address), '/', cidr) as network_address_str FROM `IpNetwork` WHERE `id` = $id";
|
||||||
$result = $db->query($sql);
|
$result = $db->query($sql);
|
||||||
$row = $result->fetch_assoc();
|
$row = $result->fetch_assoc();
|
||||||
return $row ? new IpNetworkModel($row) : null;
|
return $row ? new IpNetworkModel($row) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function deleteIpNetwork($id) {
|
public static function deleteIpNetwork($id) {
|
||||||
// delete this id and all children and children of children until no more children
|
$db = FronkDB::singleton()->link;
|
||||||
$db = FronkDB::singleton();
|
$id = (int)$id;
|
||||||
$sql = "SELECT `id` FROM `IpNetwork` WHERE `parent_network_id` = $id";
|
|
||||||
$result = $db->query($sql);
|
|
||||||
|
|
||||||
|
$child_sql = "SELECT `id` FROM `IpNetwork` WHERE `parent_network_id` = $id";
|
||||||
|
$result = $db->query($child_sql);
|
||||||
while ($row = $result->fetch_assoc()) {
|
while ($row = $result->fetch_assoc()) {
|
||||||
self::deleteIpNetwork($row['id']);
|
self::deleteIpNetwork($row['id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = "DELETE FROM `IpNetwork` WHERE `id` = $id";
|
$delete_sql = "DELETE FROM `IpNetwork` WHERE `id` = $id";
|
||||||
$result = $db->query($sql);
|
if (!$db->query($delete_sql)) {
|
||||||
if (!$result) {
|
throw new Exception("Fehler beim Löschen des Netzwerks: " . $db->error);
|
||||||
throw new Exception("Failed to delete network");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,226 +1,285 @@
|
|||||||
|
// IpNetwork.js
|
||||||
Vue.component('IpNetwork', {
|
Vue.component('IpNetwork', {
|
||||||
//language=Vue
|
|
||||||
template: `
|
template: `
|
||||||
<tt-card>
|
<tt-card>
|
||||||
|
<div class="d-flex align-items-center mb-3">
|
||||||
<tt-table :fetch-url="window['TT_CONFIG']['IPNETWORK_API_URL'] + '?do=get'"
|
<div>
|
||||||
:config="IpNetworkTableConfig"
|
<tt-button
|
||||||
@row-click="(row) => row.cidr !== '32' && switchCurrentNetwork(row.id)"
|
v-if="currentNetworkData"
|
||||||
@reset-table="switchCurrentNetwork"
|
@click="navigateBack"
|
||||||
small ssr disable-initial-fetch ref="table">
|
icon="fas fa-arrow-left"
|
||||||
|
text="Zurück"
|
||||||
<template v-slot:top-buttons>
|
additional-class="btn-secondary mr-2"
|
||||||
|
/>
|
||||||
<button type="button" class="btn btn-primary"
|
<tt-button
|
||||||
@click="switchCurrentNetwork(currentNetworkData.parent_network_id)"
|
@click="openModal(null)"
|
||||||
:disabled="!currentNetworkData">
|
icon="fas fa-plus"
|
||||||
<i class="fas fa-sync-alt"></i>Go Back
|
text="Netzwerk hinzufügen"
|
||||||
</button>
|
additional-class="btn-primary"
|
||||||
|
/>
|
||||||
<button type="button" class="btn btn-primary" @click="openModal(false)">
|
</div>
|
||||||
<i class="fas fa-sync-alt"></i>Add new Network Space
|
<div style="max-width: 400px;min-width:300px; margin-left: 1rem;">
|
||||||
</button>
|
<tt-autocomplete
|
||||||
|
v-model="globalSearchTerm"
|
||||||
</template>
|
@input="handleGlobalSearchSelect"
|
||||||
|
:api-url="apiUrl + '/globalSearch'"
|
||||||
<!-- add $slots.expandedRow to the table component and display discription -->
|
placeholder="Suche nach IP, Name, Beschreibung..."
|
||||||
<template v-slot:expandedRow="{row}">
|
sm
|
||||||
<span style="white-space: pre;" v-if="row.description" v-text="row.description"></span>
|
no-form-group
|
||||||
<span v-else>No description</span>
|
/>
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-slot:actions="{ row }">
|
|
||||||
<div style="display: flex; justify-content: space-around; align-items: center; min-width: 20px">
|
|
||||||
<a style="cursor: pointer;" @click.stop="openModal(row)"><i class="far fa-edit text-primary"
|
|
||||||
title="Editieren"></i></a>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</tt-table>
|
|
||||||
|
|
||||||
<!-- add modal -->
|
|
||||||
<div class="modal show d-block" tabindex="-1" role="dialog" style="background: rgba(0, 0, 0, 0.5);"
|
|
||||||
ref="addModal" @click="addModal = false" @keydown.esc="addModal = false" v-if="addModal === true">
|
|
||||||
<div class="modal-dialog" role="document" @click.stop>
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">Edit DNS Record</h5>
|
|
||||||
<button type="button" class="close" @click="addModal = false">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div id="wrapper" style="display:grid; grid-template-columns: 3fr 1fr 2fr; grid-gap: 12px">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="network_address">Network Address</label>
|
|
||||||
<input type="text" class="form-control" id="network_address"
|
|
||||||
:disabled="!!addModalData.id"
|
|
||||||
v-model="addModalData.network_address">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="cidr">CIDR</label>
|
|
||||||
<input type="text" class="form-control" id="cidr" :disabled="!!addModalData.id" v-model="addModalData.cidr">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="status">Status</label>
|
|
||||||
<select class="form-control" id="status" v-model="addModalData.status">
|
|
||||||
<option value="active">Active</option>
|
|
||||||
<option value="inactive">Inactive</option>
|
|
||||||
<option value="reserved">Reserved</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group" style="grid-column: span 2">
|
|
||||||
<label for="name_location">Name</label>
|
|
||||||
<input type="text" class="form-control" id="name_location"
|
|
||||||
v-model="addModalData.name">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="name_location">Location</label>
|
|
||||||
<input type="text" class="form-control" id="name_location"
|
|
||||||
v-model="addModalData.location">
|
|
||||||
</div>
|
|
||||||
<div class="form-group" style="grid-column: span 3">
|
|
||||||
<label for="description">Description</label>
|
|
||||||
<input type="text" class="form-control" id="description"
|
|
||||||
v-model="addModalData.description">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button class="btn btn-primary" @click="addSubmit">Save</button>
|
|
||||||
<button class="btn btn-danger" @click="deleteSubmit" v-if="addModalData.id">Delete</button>
|
|
||||||
<button class="btn btn-secondary" @click="addModal = false">Close</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<tt-table
|
||||||
|
:fetch-url="apiUrl + '/get'"
|
||||||
|
:config="IpNetworkTableConfig"
|
||||||
|
@row-click="row => row.cidr < 31 && switchCurrentNetwork(row.id)"
|
||||||
|
@reset-table="resetFiltersAndSwitch"
|
||||||
|
small
|
||||||
|
ssr
|
||||||
|
ref="table"
|
||||||
|
>
|
||||||
|
<template v-slot:expandedRow="{ row }">
|
||||||
|
<div class="p-2 bg-light">
|
||||||
|
<strong>Beschreibung:</strong>
|
||||||
|
<span style="white-space: pre-wrap;" v-if="row.description" v-text="row.description"></span>
|
||||||
|
<em v-else class="text-muted">Keine Beschreibung vorhanden.</em>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:actions="{ row }">
|
||||||
|
<div class="text-center">
|
||||||
|
<tt-button
|
||||||
|
icon="far fa-edit"
|
||||||
|
title="Bearbeiten"
|
||||||
|
@click.stop="openModal(row)"
|
||||||
|
additional-class="btn-link text-primary p-0"
|
||||||
|
sm
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</tt-table>
|
||||||
|
|
||||||
|
<tt-modal
|
||||||
|
v-if="modalData"
|
||||||
|
:show="true"
|
||||||
|
@update:show="closeModal"
|
||||||
|
@submit="submitModal"
|
||||||
|
@delete="deleteNetwork"
|
||||||
|
:delete="!!modalData.id"
|
||||||
|
:title="modalData.id ? 'Netzwerk bearbeiten' : 'Netzwerk hinzufügen'"
|
||||||
|
save-text="Speichern"
|
||||||
|
delete-text="Löschen"
|
||||||
|
>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group col-md-8">
|
||||||
|
<label for="network_address">Netzwerkadresse / CIDR</label>
|
||||||
|
<div class="input-group input-group-sm">
|
||||||
|
<input type="text" class="form-control" id="network_address" v-model="modalData.network_address" :disabled="!!modalData.id" required placeholder="z.B. 192.168.1.0">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<span class="input-group-text">/</span>
|
||||||
|
</div>
|
||||||
|
<input type="number" class="form-control" style="max-width: 80px;" v-model="modalData.cidr" :disabled="!!modalData.id" required placeholder="24">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-4">
|
||||||
|
<label for="status">Status</label>
|
||||||
|
<select id="status" class="form-control form-control-sm" v-model="modalData.status" required>
|
||||||
|
<option v-for="option in statusOptions" :value="option.value">{{ option.text }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label for="name">Name</label>
|
||||||
|
<input type="text" class="form-control form-control-sm" id="name" v-model="modalData.name" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label for="location">Standort</label>
|
||||||
|
<input type="text" class="form-control form-control-sm" id="location" v-model="modalData.location">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="description">Beschreibung</label>
|
||||||
|
<textarea class="form-control form-control-sm" id="description" v-model="modalData.description" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</tt-modal>
|
||||||
</tt-card>
|
</tt-card>
|
||||||
`,
|
`,
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
window: window,
|
window: window,
|
||||||
apiUrl: window['TT_CONFIG']['IPNETWORK_API_URL'],
|
apiUrl: window.TT_CONFIG.API_BASE_URL,
|
||||||
|
currentNetworkData: null,
|
||||||
|
modalData: null,
|
||||||
|
globalSearchTerm: '',
|
||||||
|
isNavigating: false,
|
||||||
|
searchDebounce: null,
|
||||||
|
statusOptions: [
|
||||||
|
{value: 'active', text: 'Aktiv'},
|
||||||
|
{value: 'inactive', text: 'Inaktiv'},
|
||||||
|
{value: 'reserved', text: 'Reserviert'}
|
||||||
|
],
|
||||||
IpNetworkTableConfig: {
|
IpNetworkTableConfig: {
|
||||||
defaultPageSize: 50,
|
defaultPageSize: 50,
|
||||||
customRowClass: function (row) {
|
customRowClass: row => (row.cidr < 31 ? 'tt-pointer' : ''),
|
||||||
return row.cidr !== '32' ? 'tt-pointer' : '';
|
expandCondition: row => !!row.description,
|
||||||
},
|
|
||||||
expandCondition: function (row) {
|
|
||||||
return !!row.description;
|
|
||||||
},
|
|
||||||
headers: [
|
headers: [
|
||||||
{text: 'Network Address', key: 'network_address_str'},
|
{text: 'Netzwerkadresse', key: 'network_address_str', sortable: true},
|
||||||
{text: 'Name', key: 'name'},
|
{text: 'Name', key: 'name', sortable: true},
|
||||||
{
|
{text: 'Status', key: 'status', filter: 'iconSelect', sortable: true,
|
||||||
text: 'Status', key: 'status', filter: 'iconSelect',
|
filterOptions: [
|
||||||
filterOptions: [{value: 'active', text: 'Active', icon: 'fas fa-check text-success'},
|
{value: 'active', text: 'Aktiv', icon: 'fas fa-check text-success'},
|
||||||
{value: 'inactive', text: 'Inactive', icon: 'fas fa-times text-danger'},
|
{value: 'inactive', text: 'Inaktiv', icon: 'fas fa-times text-danger'},
|
||||||
{value: 'reserved', text: 'Reserved', icon: 'fas fa-lock text-warning'}]
|
{value: 'reserved', text: 'Reserviert', icon: 'fas fa-lock text-warning'}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{text: 'Children', key: 'children', filter: 'numberRange'},
|
{text: 'Subnetze', key: 'children', filter: 'numberRange', sortable: true},
|
||||||
{text: 'Aktionen', key: 'actions', sortable: false},
|
{text: 'Standort', key: 'location', sortable: true},
|
||||||
|
{text: 'Aktionen', key: 'actions', sortable: false, class: 'text-center'},
|
||||||
],
|
],
|
||||||
tableHeader: 'IPAM',
|
tableHeader: 'IPAM - Stamm',
|
||||||
key: 'IpNetwork'
|
key: 'IpNetwork'
|
||||||
},
|
}
|
||||||
currentNetworkData: null,
|
|
||||||
addModal: false,
|
|
||||||
addModalData: {
|
|
||||||
network_address: '',
|
|
||||||
cidr: '',
|
|
||||||
parent_network_id: '',
|
|
||||||
status: 'active',
|
|
||||||
name: '',
|
|
||||||
description: '',
|
|
||||||
location: '',
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
watch: {
|
||||||
function popstateFunction() {
|
globalSearchTerm(newValue) {
|
||||||
const parentNetworkId = new URLSearchParams(window.location.search).get('parent_network_id');
|
if (this.isNavigating) {
|
||||||
this.switchCurrentNetwork(parentNetworkId).then();
|
this.isNavigating = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clearTimeout(this.searchDebounce);
|
||||||
|
this.searchDebounce = setTimeout(() => {
|
||||||
|
this.$refs.table.filters.globalSearch = this.globalSearchTerm;
|
||||||
|
}, 300);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
window.onpopstate = popstateFunction.bind(this);
|
mounted() {
|
||||||
window.onpopstate.call(this)
|
window.addEventListener('popstate', this.handlePopState);
|
||||||
|
this.handlePopState(); // Initial load based on URL
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
window.removeEventListener('popstate', this.handlePopState);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openModal(row = false) {
|
async handleGlobalSearchSelect(selectedNetworkString) {
|
||||||
if (row) {
|
if (!selectedNetworkString || typeof selectedNetworkString !== 'string') {
|
||||||
const data = JSON.parse(JSON.stringify(row));
|
this.globalSearchTerm = selectedNetworkString;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.globalSearchTerm = selectedNetworkString;
|
||||||
|
|
||||||
|
try {
|
||||||
this.addModalData = {
|
const response = await axios.get(`${this.apiUrl}/findNetworkByString`, { params: { network_string: selectedNetworkString } });
|
||||||
id: data.id,
|
if (response.data.success) {
|
||||||
network_address: data.network_address_str.split('/')[0],
|
this.switchCurrentNetwork(response.data.navigateToId);
|
||||||
cidr: data.cidr,
|
this.isNavigating = true;
|
||||||
parent_network_id: this.currentNetworkData ? this.currentNetworkData.id : '',
|
this.globalSearchTerm = '';
|
||||||
status: data.status,
|
} else {
|
||||||
name: data.name,
|
window.notify('error', response.data.message || 'Netzwerk konnte nicht gefunden werden.');
|
||||||
description: data.description,
|
|
||||||
location: data.location,
|
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
window.notify('error', e.response?.data?.message || 'Fehler bei der Netzwerksuche.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handlePopState() {
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const parentId = params.get('parent_network_id') || null;
|
||||||
|
this.switchCurrentNetwork(parentId, false); // false to not push state
|
||||||
|
},
|
||||||
|
openModal(row = null) {
|
||||||
|
if (row) {
|
||||||
|
this.modalData = {
|
||||||
|
id: row.id,
|
||||||
|
network_address: row.network_address_str.split('/')[0],
|
||||||
|
cidr: row.cidr,
|
||||||
|
status: row.status,
|
||||||
|
name: row.name,
|
||||||
|
description: row.description,
|
||||||
|
location: row.location,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
this.addModalData = {
|
this.modalData = {
|
||||||
network_address: '',
|
network_address: '',
|
||||||
cidr: '',
|
cidr: '',
|
||||||
parent_network_id: this.currentNetworkData ? this.currentNetworkData.id : '',
|
|
||||||
status: 'active',
|
status: 'active',
|
||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
location: '',
|
location: '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this.addModal = true;
|
|
||||||
},
|
},
|
||||||
async switchCurrentNetwork(networkId = null) {
|
closeModal() {
|
||||||
if (!networkId) {
|
this.modalData = null;
|
||||||
this.$refs.table.$set(this.$refs.table.filters, 'parent_network_id', undefined);
|
},
|
||||||
this.currentNetworkData = null;
|
async switchCurrentNetwork(networkId = null, pushState = true) {
|
||||||
this.IpNetworkTableConfig.tableHeader = 'IPAM';
|
this.$refs.table.filters = { ...this.$refs.table.filters, parent_network_id: networkId || undefined };
|
||||||
this.$refs.table.disableDebounce = true;
|
|
||||||
window.history.pushState({}, '', `?`);
|
|
||||||
} else {
|
|
||||||
this.$refs.table.disableDebounce = true;
|
|
||||||
this.$refs.table.$set(this.$refs.table.filters, 'parent_network_id', networkId);
|
|
||||||
window.history.pushState({}, '', `?parent_network_id=${networkId}`);
|
|
||||||
|
|
||||||
const response = await axios.post(`${this.apiUrl}?do=getById`, {id: networkId});
|
if (pushState) {
|
||||||
this.currentNetworkData = response.data.network;
|
const url = new URL(window.location);
|
||||||
this.IpNetworkTableConfig.tableHeader = `IPAM - ${this.currentNetworkData.network_address_str}/${this.currentNetworkData.cidr} - ${this.currentNetworkData.name}`;
|
if (networkId) {
|
||||||
|
url.searchParams.set('parent_network_id', networkId);
|
||||||
|
} else {
|
||||||
|
url.searchParams.delete('parent_network_id');
|
||||||
|
}
|
||||||
|
window.history.pushState({path: url.href}, '', url.href);
|
||||||
}
|
}
|
||||||
await this.$refs.table.fetchData();
|
|
||||||
},
|
if (networkId) {
|
||||||
async addSubmit() {
|
try {
|
||||||
const response = await axios.post(`${this.apiUrl}?do=${this.addModalData.id ? 'update' : 'create'}`,
|
const response = await axios.get(`${this.apiUrl}/getById?id=${networkId}`);
|
||||||
{
|
this.currentNetworkData = response.data.network;
|
||||||
...this.addModalData,
|
this.IpNetworkTableConfig.tableHeader = `IPAM - ${this.currentNetworkData.network_address_str} ${this.currentNetworkData.name ? '- ' + this.currentNetworkData.name : ''}`;
|
||||||
parent_network_id: this.currentNetworkData ? this.currentNetworkData.id : null
|
} catch (e) {
|
||||||
});
|
window.notify('error', 'Details des übergeordneten Netzwerks konnten nicht geladen werden.');
|
||||||
if (response.data.status === 'success') {
|
this.currentNetworkData = null;
|
||||||
this.addModal = false;
|
this.IpNetworkTableConfig.tableHeader = 'IPAM - Stamm';
|
||||||
this.addModalData = {};
|
}
|
||||||
window.notify('success', 'Network space created successfully');
|
|
||||||
await this.$refs.table.fetchData();
|
|
||||||
} else {
|
} else {
|
||||||
window.notify('error', response.data.message);
|
this.currentNetworkData = null;
|
||||||
|
this.IpNetworkTableConfig.tableHeader = 'IPAM - Stamm';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async deleteSubmit() {
|
resetFiltersAndSwitch() {
|
||||||
const response = await axios.post(`${this.apiUrl}?do=delete`, {id: this.addModalData.id});
|
this.globalSearchTerm = '';
|
||||||
if (response.data.status === 'success') {
|
this.switchCurrentNetwork(null);
|
||||||
this.addModal = false;
|
},
|
||||||
this.addModalData = {};
|
navigateBack() {
|
||||||
window.notify('success', 'Network space deleted successfully');
|
window.history.back();
|
||||||
await this.$refs.table.fetchData();
|
},
|
||||||
} else {
|
async submitModal() {
|
||||||
window.notify('error', response.data.message);
|
const isUpdate = !!this.modalData.id;
|
||||||
|
const url = isUpdate ? `${this.apiUrl}/update` : `${this.apiUrl}/create`;
|
||||||
|
const payload = { ...this.modalData, parent_network_id: this.currentNetworkData?.id || null };
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.post(url, payload);
|
||||||
|
if (response.data.success) {
|
||||||
|
window.notify('success', response.data.message);
|
||||||
|
this.closeModal();
|
||||||
|
this.$refs.table.refreshTable();
|
||||||
|
} else {
|
||||||
|
window.notify('error', response.data.message || 'Ein Fehler ist aufgetreten.');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
window.notify('error', e.response?.data?.message || 'Ein Netzwerkfehler ist aufgetreten.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async deleteNetwork() {
|
||||||
|
if (!confirm('Sind Sie sicher, dass Sie dieses Netzwerk und alle untergeordneten Netzwerke löschen möchten?')) return;
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`${this.apiUrl}/delete`, { id: this.modalData.id });
|
||||||
|
if (response.data.success) {
|
||||||
|
window.notify('success', response.data.message);
|
||||||
|
this.closeModal();
|
||||||
|
this.$refs.table.refreshTable();
|
||||||
|
} else {
|
||||||
|
window.notify('error', response.data.message || 'Ein Fehler ist aufgetreten.');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
window.notify('error', e.response?.data?.message || 'Ein Netzwerkfehler ist aufgetreten.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
@@ -376,4 +376,8 @@ td {
|
|||||||
|
|
||||||
.tt-input-article-wrapper button[type=button].btn-link.position-absolute {
|
.tt-input-article-wrapper button[type=button].btn-link.position-absolute {
|
||||||
right: 30px !important;
|
right: 30px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div[no-form-group] {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
@@ -584,6 +584,8 @@ Vue.component('tt-table', {
|
|||||||
|
|
||||||
// go through filters and if there is a set value in filters and the filter of the column is select or autocomplete then parse the value to int
|
// go through filters and if there is a set value in filters and the filter of the column is select or autocomplete then parse the value to int
|
||||||
for (const key in this.filters) {
|
for (const key in this.filters) {
|
||||||
|
if (!this.columns[key]) continue;
|
||||||
|
|
||||||
if (this.filters[key] && (this.columns[key].filter === 'select' || this.columns[key].filter === 'autocomplete')) {
|
if (this.filters[key] && (this.columns[key].filter === 'select' || this.columns[key].filter === 'autocomplete')) {
|
||||||
// only if first character is a number
|
// only if first character is a number
|
||||||
// if (!isNaN(this.filters[key][0])) {
|
// if (!isNaN(this.filters[key][0])) {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,220 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This script parses a wiki text file containing network information and generates an SQL script
|
||||||
|
* to populate the IpNetwork table with a complete, hierarchical representation of the network.
|
||||||
|
*
|
||||||
|
* @version 1.0
|
||||||
|
* @author Gemini
|
||||||
|
*/
|
||||||
|
|
||||||
|
// --- Configuration ---
|
||||||
|
$inputFile = 'combined_wiki.txt';
|
||||||
|
$outputFile = 'initial_data.sql';
|
||||||
|
$dbTableName = 'IpNetwork';
|
||||||
|
|
||||||
|
// --- Main Execution ---
|
||||||
|
|
||||||
|
// Read and parse the wiki file into a structured PHP array
|
||||||
|
$networkData = parseWikiFile($inputFile);
|
||||||
|
|
||||||
|
// Generate the SQL script from the parsed data
|
||||||
|
$sqlScript = generateSqlScript($networkData, $dbTableName);
|
||||||
|
|
||||||
|
// Save the generated SQL script to the output file
|
||||||
|
file_put_contents($outputFile, $sqlScript);
|
||||||
|
|
||||||
|
echo "SQL-Skript wurde erfolgreich in '$outputFile' generiert.\n";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the entire wiki text file and organizes the network data hierarchically.
|
||||||
|
*
|
||||||
|
* @param string $filename The path to the wiki text file.
|
||||||
|
* @return array A structured array containing all network information.
|
||||||
|
*/
|
||||||
|
function parseWikiFile(string $filename): array
|
||||||
|
{
|
||||||
|
if (!file_exists($filename)) {
|
||||||
|
die("Fehler: Eingabedatei '$filename' nicht gefunden.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
|
$networks = [];
|
||||||
|
$currentNetwork = null;
|
||||||
|
$currentSubnet = null;
|
||||||
|
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
// Ignore section headers
|
||||||
|
if (preg_match('/^=====.*=====$/', $line)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match network/subnet definitions (e.g., "10.0.0.0/29 stko-tauka" or "10.0.0.1/32 Gateway")
|
||||||
|
if (preg_match('/^([\d\.]+)\/(\d+)\s*(.*)$/', trim($line), $matches)) {
|
||||||
|
$ip = $matches[1];
|
||||||
|
$cidr = (int)$matches[2];
|
||||||
|
$description = trim($matches[3]);
|
||||||
|
|
||||||
|
// Determine if it's a main network or a subnet based on CIDR
|
||||||
|
if ($cidr < 29) { // Heuristic: Treat larger blocks as potential parent subnets
|
||||||
|
$currentSubnet = "$ip/$cidr";
|
||||||
|
$networks[$currentSubnet] = [
|
||||||
|
'ip' => $ip,
|
||||||
|
'cidr' => $cidr,
|
||||||
|
'name' => $description,
|
||||||
|
'description' => $description,
|
||||||
|
'children' => []
|
||||||
|
];
|
||||||
|
} else { // Treat smaller blocks and hosts as children
|
||||||
|
if ($currentSubnet) {
|
||||||
|
$networks[$currentSubnet]['children'][] = [
|
||||||
|
'ip' => $ip,
|
||||||
|
'cidr' => $cidr,
|
||||||
|
'name' => $description,
|
||||||
|
'description' => $description,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Match host definitions (e.g., "10.0.0.2 stko-tauk:stko")
|
||||||
|
elseif (preg_match('/^([\d\.]+)\s+(.*)$/', trim($line), $matches)) {
|
||||||
|
$ip = $matches[1];
|
||||||
|
$description = trim($matches[2]);
|
||||||
|
|
||||||
|
if ($currentSubnet) {
|
||||||
|
$networks[$currentSubnet]['children'][] = [
|
||||||
|
'ip' => $ip,
|
||||||
|
'cidr' => 32, // Assume /32 for host entries
|
||||||
|
'name' => $description,
|
||||||
|
'description' => $description,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $networks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the complete SQL script string.
|
||||||
|
*
|
||||||
|
* @param array $data The structured network data.
|
||||||
|
* @param string $tableName The name of the database table.
|
||||||
|
* @return string The complete SQL script.
|
||||||
|
*/
|
||||||
|
function generateSqlScript(array $data, string $tableName): string
|
||||||
|
{
|
||||||
|
// --- SQL Header ---
|
||||||
|
$sql = "-- SQL-Daten für die Tabelle '$tableName'\n";
|
||||||
|
$sql .= "-- Automatisch generiert aus der Wiki-Dokumentation\n\n";
|
||||||
|
$sql .= "TRUNCATE TABLE `$tableName`;\n\n";
|
||||||
|
$sql .= "-- Eltern-Netzwerke (Top-Level)\n";
|
||||||
|
|
||||||
|
// --- Insert Top-Level Parent Networks ---
|
||||||
|
$parents = [
|
||||||
|
['10.0.0.0', 8, 'Privates Netzwerk Klasse A', 'RFC 1918 privater Adressbereich für große Netzwerke.'],
|
||||||
|
['172.16.0.0', 12, 'Privates Netzwerk Klasse B', 'RFC 1918 privater Adressbereich für mittlere Netzwerke.'],
|
||||||
|
['192.168.0.0', 16, 'Privates Netzwerk Klasse C', 'RFC 1918 privater Adressbereich für kleine Netzwerke.'],
|
||||||
|
['100.64.0.0', 10, 'Carrier-Grade NAT (CGNAT)', 'RFC 6598 Adressbereich für Carrier-Grade NAT.'],
|
||||||
|
['5.206.200.0', 21, 'Öffentlicher Netzblock 5.206.200.0/21', 'Öffentlicher IP-Adressbereich.'],
|
||||||
|
['185.29.88.0', 22, 'Öffentlicher Netzblock 185.29.88.0/22', 'Öffentlicher IP-Adressbereich.'],
|
||||||
|
['193.105.204.0', 22, 'Öffentlicher Netzblock 193.105.204.0/22', 'Öffentlicher IP-Adressbereich.'],
|
||||||
|
['193.186.244.0', 22, 'Öffentlicher Netzblock 193.186.244.0/22', 'Öffentlicher IP-Adressbereich.'],
|
||||||
|
['45.82.168.0', 22, 'Öffentlicher Netzblock 45.82.168.0/22', 'Öffentlicher IP-Adressbereich.'],
|
||||||
|
['46.151.200.0', 21, 'Öffentlicher Netzblock 46.151.200.0/21', 'Öffentlicher IP-Adressbereich.'],
|
||||||
|
['91.227.230.0', 22, 'Öffentlicher Netzblock 91.227.230.0/22', 'Öffentlicher IP-Adressbereich.']
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($parents as $p) {
|
||||||
|
$sql .= generateInsertStatement($tableName, $p[0], $p[1], 'NULL', 'active', $p[2], $p[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Insert Child Networks and Hosts ---
|
||||||
|
$sql .= "\n-- Kind-Netzwerke und Hosts aus der Wiki-Dokumentation\n";
|
||||||
|
foreach ($data as $subnetKey => $subnet) {
|
||||||
|
// Insert the subnet itself, linking it to the correct top-level parent
|
||||||
|
$parentSelect = getParentSelect($subnet['ip']);
|
||||||
|
$sql .= generateInsertStatement($tableName, $subnet['ip'], $subnet['cidr'], "($parentSelect)", 'active', $subnet['name'], $subnet['description']);
|
||||||
|
|
||||||
|
// Insert all children of this subnet
|
||||||
|
if (!empty($subnet['children'])) {
|
||||||
|
$childParentSelect = "SELECT id FROM `$tableName` p WHERE p.network_address = INET_ATON('{$subnet['ip']}') AND p.cidr = {$subnet['cidr']}";
|
||||||
|
foreach ($subnet['children'] as $child) {
|
||||||
|
$sql .= generateInsertStatement($tableName, $child['ip'], $child['cidr'], "($childParentSelect)", 'active', $child['name'], $child['description']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a single SQL INSERT statement.
|
||||||
|
*
|
||||||
|
* @param string $tableName
|
||||||
|
* @param string $ip
|
||||||
|
* @param int $cidr
|
||||||
|
* @param string $parentIdSql SQL string for parent ID (can be 'NULL' or a subquery).
|
||||||
|
* @param string $status
|
||||||
|
* @param string $name
|
||||||
|
* @param string $description
|
||||||
|
* @return string The generated INSERT statement.
|
||||||
|
*/
|
||||||
|
function generateInsertStatement(string $tableName, string $ip, int $cidr, string $parentIdSql, string $status, string $name, string $description): string
|
||||||
|
{
|
||||||
|
$name = substr(addslashes($name), 0, 100);
|
||||||
|
$description = addslashes($description);
|
||||||
|
|
||||||
|
return "INSERT INTO `$tableName` (`network_address`, `cidr`, `parent_network_id`, `status`, `name`, `description`, `location`, `create`, `edit`) VALUES " .
|
||||||
|
"(INET_ATON('$ip'), $cidr, $parentIdSql, '$status', '$name', '$description', NULL, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the correct parent network's SELECT statement based on the IP address.
|
||||||
|
*
|
||||||
|
* @param string $ip The IP address of the child network.
|
||||||
|
* @return string A SQL SELECT statement to find the parent ID.
|
||||||
|
*/
|
||||||
|
function getParentSelect(string $ip): string
|
||||||
|
{
|
||||||
|
if (strpos($ip, '10.') === 0) {
|
||||||
|
return "SELECT id FROM `IpNetwork` p WHERE p.network_address = INET_ATON('10.0.0.0') AND p.cidr = 8";
|
||||||
|
}
|
||||||
|
if (strpos($ip, '172.16.') === 0 || strpos($ip, '172.17.') === 0 || strpos($ip, '172.18.') === 0 || strpos($ip, '172.19.') === 0 || strpos($ip, '172.2') === 0 || strpos($ip, '172.30.') === 0 || strpos($ip, '172.31.') === 0) {
|
||||||
|
return "SELECT id FROM `IpNetwork` p WHERE p.network_address = INET_ATON('172.16.0.0') AND p.cidr = 12";
|
||||||
|
}
|
||||||
|
if (strpos($ip, '192.168.') === 0) {
|
||||||
|
return "SELECT id FROM `IpNetwork` p WHERE p.network_address = INET_ATON('192.168.0.0') AND p.cidr = 16";
|
||||||
|
}
|
||||||
|
if (strpos($ip, '100.') === 0) {
|
||||||
|
return "SELECT id FROM `IpNetwork` p WHERE p.network_address = INET_ATON('100.64.0.0') AND p.cidr = 10";
|
||||||
|
}
|
||||||
|
if (strpos($ip, '5.206.') === 0) {
|
||||||
|
return "SELECT id FROM `IpNetwork` p WHERE p.network_address = INET_ATON('5.206.200.0') AND p.cidr = 21";
|
||||||
|
}
|
||||||
|
if (strpos($ip, '185.29.') === 0) {
|
||||||
|
return "SELECT id FROM `IpNetwork` p WHERE p.network_address = INET_ATON('185.29.88.0') AND p.cidr = 22";
|
||||||
|
}
|
||||||
|
if (strpos($ip, '193.105.') === 0) {
|
||||||
|
return "SELECT id FROM `IpNetwork` p WHERE p.network_address = INET_ATON('193.105.204.0') AND p.cidr = 22";
|
||||||
|
}
|
||||||
|
if (strpos($ip, '193.186.') === 0) {
|
||||||
|
return "SELECT id FROM `IpNetwork` p WHERE p.network_address = INET_ATON('193.186.244.0') AND p.cidr = 22";
|
||||||
|
}
|
||||||
|
if (strpos($ip, '45.82.') === 0) {
|
||||||
|
return "SELECT id FROM `IpNetwork` p WHERE p.network_address = INET_ATON('45.82.168.0') AND p.cidr = 22";
|
||||||
|
}
|
||||||
|
if (strpos($ip, '46.151.') === 0) {
|
||||||
|
return "SELECT id FROM `IpNetwork` p WHERE p.network_address = INET_ATON('46.151.200.0') AND p.cidr = 21";
|
||||||
|
}
|
||||||
|
if (strpos($ip, '91.227.') === 0) {
|
||||||
|
return "SELECT id FROM `IpNetwork` p WHERE p.network_address = INET_ATON('91.227.230.0') AND p.cidr = 22";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for networks that don't match a known parent
|
||||||
|
return 'NULL';
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
Reference in New Issue
Block a user