212 lines
9.2 KiB
PHP
212 lines
9.2 KiB
PHP
<?php
|
|
|
|
class IpNetworkModel {
|
|
|
|
public $id;
|
|
public $network_address;
|
|
public $cidr;
|
|
public $parent_network_id;
|
|
public $status;
|
|
public $network_address_str;
|
|
public $name;
|
|
public $description;
|
|
public $create;
|
|
public $edit;
|
|
public $location;
|
|
|
|
public function __construct($data = []) {
|
|
foreach ($data as $field => $value) {
|
|
if (property_exists(get_called_class(), $field)) {
|
|
$this->$field = $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static function getIpNetworks($filters, $limit = null, $offset = 0, $order = null): array {
|
|
$db = FronkDB::singleton();
|
|
|
|
$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);
|
|
$rows = [];
|
|
while ($row = $result->fetch_assoc()) {
|
|
$rows[] = new IpNetworkModel($row);
|
|
}
|
|
|
|
return $rows;
|
|
}
|
|
|
|
public static function getSqlFilter($filters): string {
|
|
$sql = isset($filters['name']) ? Helper::generateFilterCondition($filters['name'], 'name') : "";
|
|
$sql .= isset($filters['description']) ? Helper::generateFilterCondition($filters['description'], 'description') : "";
|
|
$sql .= isset($filters['location']) ? Helper::generateFilterCondition($filters['location'], 'location') : "";
|
|
$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);
|
|
}
|
|
|
|
return $rows;
|
|
}
|
|
|
|
/**
|
|
* @throws Exception
|
|
*/
|
|
public static function createIpNetwork($data): void {
|
|
$db = FronkDB::singleton();
|
|
|
|
$network_address = $data['network_address'];
|
|
$cidr = $data['cidr'];
|
|
$parent_network_id = $data['parent_network_id'] ?? 'NULL';
|
|
$status = $data['status'];
|
|
$name = $data['name'];
|
|
$description = $data['description'];
|
|
$location = $data['location'];
|
|
|
|
// Convert network address to integer
|
|
$network_address_int = ip2long($network_address);
|
|
|
|
// Define query to check for overlapping networks
|
|
$check_sql = "
|
|
SELECT `id`, `network_address`, `cidr`
|
|
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);
|
|
|
|
$result = $db->query($check_sql);
|
|
|
|
$parentFound = false;
|
|
$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) {
|
|
throw new Exception("Root Networks cannot be single IPs");
|
|
}
|
|
|
|
// Proceed with insertion if no conflicts are found
|
|
$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())";
|
|
$result = $db->query($sql);
|
|
|
|
if (!$result) {
|
|
throw new Exception("Failed to insert network");
|
|
}
|
|
}
|
|
|
|
|
|
public static function getById($id) {
|
|
$db = FronkDB::singleton();
|
|
$sql = "SELECT *, INET_NTOA(network_address) as network_address_str FROM `IpNetwork` WHERE `id` = $id";
|
|
$result = $db->query($sql);
|
|
$row = $result->fetch_assoc();
|
|
return $row ? new IpNetworkModel($row) : null;
|
|
}
|
|
|
|
} |