как присоединиться или разделить IP-сети с помощью переполнения стека

У меня есть задача, которая, кажется, включает в себя подзадачу. Возьмите два или более сегмента ip (это могут быть 192.168.1.32/27, 192.168.1.64/28 и 192.168.1.128/25) и объедините их в ближайший сегмент (192.168.1.0/24 с использованием предыдущих сегментов ip). Проверка, возможно ли объединение сегментов, должна быть.

Кто-нибудь знает, есть ли класс php с инструментами, которые могут сделать это — или пара функций аналогичным образом?

/ Lars

РЕДАКТИРОВАТЬ:
[код]

$ip_id_array = array();
$ip_level_array = array();
$ip_segment_array = array();
$ip_cidr_array = array();
$toplevel_array = array();

foreach ($_POST["net_ip_id"] AS $ip_id)
{
$sql = "SELECT
ip_segments.ip_id,
ip_segments.ip_segment,
ip_segments.ip_level,
ip_segments.ip_cidr
FROM
ip_segments
WHERE
ip_id = '".$ip_id."'
";
$relip_res = mysqli_query($db, $sql) or cc("ERROR: SQL Select subsegments related", $sql, mysqli_error($db) , $_SESSION["u_id"], $this_document);
$ip_array = mysqli_fetch_assoc($relip_res);
$ip_id_array[] = $ip_array["ip_id"];
$ip_level_array[] = $ip_array["ip_level"];
$ip_segment_array[] = $ip_array["ip_segment"];
$ip_cidr_array[] = $ip_array["ip_cidr"];

if ($ip_array["ip_level"] != 0 && !empty($ip_array["ip_level"]))
{
$sql = "SELECT
ip_segments.ip_id,
ip_segments.ip_segment,
ip_segments.ip_level,
ip_segments.ip_cidr
FROM
ip_segments
WHERE
ip_id = '".$ip_array["ip_level"]."'
";
$relip_res = mysqli_query($db, $sql) or cc("ERROR: SQL Select subsegments related", $sql, mysqli_error($db) , $_SESSION["u_id"], $this_document);
$toplevel[] = mysqli_fetch_assoc($relip_res);
}
}

$ip_level_array = array_unique($ip_level_array);
$ip_cidr_array = array_unique($ip_cidr_array);
$toplevel = array_unique($toplevel);

if(sizeof($ip_level_array) > 1)
$field_alerts[] = "IP Segments must be within the same segment.!";
if ($ip_cidr_array[0] <= 1)
$field_alerts[] = "Subnetmasks must be larger than or equal to 1";
if ($toplevel <= 1)
$field_alerts[] = "No Toplevel to merge to!";

if (sizeof($field_alerts) < 1)
{
$new_segment = $ip_id_array[0];
$new_cidr = $toplevel[0]["ip_cidr"];
}
[/код]

Редактировать:
Сегмент верхнего уровня 192.168.1.0/24 (id 1 — уровень 0)
Он может быть разделен на несколько различных типов подсетей в диапазоне от / 25 и до / 32 (хост).
Скажем, мы сегментируем / 26. Это дает следующее:

ID, Level, IP, CIDR
2,1,192.168.1.0,26
3,1,192.168.1.64,26
4,1,192.168.1.128,26
5,1,192.168.1.192,26

Увидеть: http://jodies.de/ipcalc?host=192.168.1.0&маска1 = 24&маска2 = 26

Что мне нужно, это кусок кода, который может взять массив идентификаторов, посмотреть на сегмент и cidr и посмотреть на возможность присоединения сегментов к ближайшей суперсети (в данном случае / 25 или / 24)
Опции:

Join ID, Result
2,3 => true (/25)
2,4 => false (networks not "next" to each other (a /26 between))
3,4 => false (subsegments will split toplevel (/25) segment
4,5 => true (/25)

Дайте мне знать, если нужна дополнительная информация.

-1

Решение

Основываясь на вашем последнем редактировании, я думаю, что вы хотите найти оптимальное суммирование для предоставленных подсетей.

Допустим, у вас есть подсети из вашего примера:

192.168.1.0/26
192.168.1.64/26
192.168.1.128/26
192.168.1.192/26

Поскольку все операции, связанные с вычислением свойств подсети, возможно, проще взглянуть на двоичное представление подсетей:

11000000101010000000000100000000
11000000101010000000000101000000
11000000101010000000000110000000
11000000101010000000000111000000

Чтобы проверить, можно ли объединить две подсети, нужно посмотреть последний бит подсети. Маскирующая часть узла (последние 6 битов в этом примере) единственное допустимое различие между двумя идентификаторами подсети для их объединения должно быть в последнем бите подсети (между каналами).

1100000010101000000000010|0|hhhhhh
1100000010101000000000010|1|hhhhhh
1100000010101000000000011|0|hhhhhh
1100000010101000000000011|1|hhhhhh

В этом примере первые две подсети имеют одинаковые первые 25 битов, поэтому их можно объединить. То же самое относится к двум последним подсетям. Но подсети 2 и 3 имеют другой 25-й бит, поэтому их нельзя объединить. Таким образом, для объединения двух подсетей они должны иметь одинаковую маску подсети длины N и первый N-1 биты адреса должны быть одинаковыми.

При реализации этого с массивом IP-адресов вам необходимо решить две проблемы:

  1. Что делать с массивом и в каком порядке идти через него
  2. Как объединить лучших кандидатов и проверить, можно ли их обобщить

и обе проблемы могут быть решены путем структурирования и сортировки массива. Допустим, вы получили свой массив из базы данных и хотите суммировать подсети.

$ips = array(
array("ip" => "192.168.1.0", "cidr" => "26"),
array("ip" => "192.168.1.64", "cidr" => "26"),
array("ip" => "192.168.1.128", "cidr" => "26"),
array("ip" => "192.168.1.192", "cidr" => "26")
);

Я бы решил эту проблему, построив массив с адресами, представленными в виде чисел, а длины CIDR в качестве ключей. Обратите внимание & (-1 << (32 - $ips[$i]['cidr']) часть: это не нужно, если адреса в вашей базе данных являются адреса подсети, но я включил это на всякий случай. Это будет делать побитовое И для IP-адреса и маски подсети и вычислять адрес подсети для любого IP-адреса.

for($i = 0; $i < sizeof($ips); $i++){
$net = ip2long($ips[$i]['ip']) & (-1 << (32 - $ips[$i]['cidr']));
$n_ips[$ips[$i]['cidr']][]= $net;
}

Это даст вам $n_ips массив (который выглядит следующим образом) и позволяет вам сортировать массив по CIDR, обрабатывать сначала самые маленькие подсети и, возможно, позже присоединиться к этой сводке с большими подсетями.

array
26 =>
array
0 => int -1062731520
1 => int -1062731456
2 => int -1062731392
3 => int -1062731328

Вы должны сделать то же самое с массивом второго уровня. Сортировка адресов позволит расположить наилучших кандидатов рядом друг с другом. Затем вы должны выполнить итерацию каждого массива и проверить, можно ли объединить подсети, используя правило, упомянутое ранее:

Две подсети должны иметь одинаковую маску подсети длины N (что они и делают, так как вы классифицировали подсети по префиксу CIDR) и первый N-1 биты адреса должны быть одинаковыми. Второе легко сделать, рассчитав оба адреса подсети, используя более короткий на 1 бит префикс CIDR: $ip & (-1 << 32 - ($cidr+1)) и проверка, если они одинаковы.

Таким образом, последняя функция (которая принимает $n_ips массив, который вы сделали ранее в качестве аргумента), может выглядеть так:

function summarize($n_ips){
$changed = false; // Did you change anything in this iteration?
$new = array();   // Array with summarized scopes
krsort($n_ips);  // Sort array keys (CIDR)
foreach($n_ips as $cidr => $ips){
sort($n_ips[$cidr]);  // Sort the scopes from lowest to highest
for($i = 0; $i < sizeof($n_ips[$cidr]); $i++){
if($n_ips[$cidr][$i] == $n_ips[$cidr][$i+1]){   //Skip if you have two same subnets (not needed if your list of scopes is clean)
continue;
}
if(($n_ips[$cidr][$i] & (-1 << 33 - $cidr)) == ($n_ips[$cidr][$i+1] & (-1 << 33 - $cidr))){ //Are subnet IDs from current and next subnet the same if you have smaller subnet mask?
$new[$cidr-1][] = $n_ips[$cidr][$i] & (-1 << 33 - $cidr);    //If yes add the summarized subnet to the new array
$i++;                                                       //Skip the next subnet
$changed = true;                                            //And raise the changed flag
}else{
$new[$cidr][] = $n_ips[$cidr][$i];                          //If not just copy the current subnet
}
}
}
return $changed ? summarize($new) : $n_ips; //If there were no changes you have the optimized summarization, otherwise summarize the new array
}

Выводом будет массив суммированных подсетей с числовым представлением адресов, которые вы можете преобразовать в десятичное представление:

$s_ips = summarize($n_ips)

foreach($s_ips as $cidr => $ips){
foreach($ips as $ip){
echo long2ip($ip) . "/" . $cidr . "<br/>";
}
}

Вы сказали, что вам просто нужно true / false, если суммирование возможно, но я намеренно предоставил более общий ответ. Вы можете изменить функцию так, чтобы она возвращала значение true, только если в суммированном массиве осталась одна подсеть.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]