Bash

將 IP 列表轉換為固定 CIDR 形式

  • October 5, 2021

x.x.x.0/24有沒有一種工具可以用和將 IP 列表轉換為固定網路 CIDR 形式x.x.0.0/16?例如,為了證明這一點,我列出了可能可以轉換為這些固定形式的 IP,如下所示:

首先,如果我想將下面的 IP 列表轉換為可能的 CIDR 24 但具有固定形式x.x.x.0/24

./list2cidr 24 iplist.txt

1.22.3.4
1.28.3.5
1.211.3.7
1.211.3.2
1.211.3.1

Output:

1.22.3.4
1.28.3.5
1.211.3.0/24

它是如何工作的?

首先,它掃描具有相同網路的 IP 列表,如果它們在同一個網路中,它會查看第 3 個八位字節,我們將其合併為x.x.x.0/24. 在這種情況下,在第 3 個八位字節中有 3 個 IP 具有相同的網路:

1.211.3.7
1.211.3.2
1.211.3.1

所以這將是:1.211.3.0/24

另一個例子,如果我想將下面的 IP 列表轉換為可能的 CIDR 16,其固定形式為x.x.0.0/16

./list2cidr 16 iplist.txt

1.1.4.1
1.1.4.2
1.22.44.1
1.22.3.2
1.22.1.9

Output:

1.1.0.0/16
1.22.0.0/16

當我傳遞包含16它的參數時,如果它們在同一個網路中,它將查看第二個八位字節,所以我們將它組合成x.x.0.0/16

我應該開始為此編寫腳本還是有為此目的存在的工具?

編輯:

我有興趣使 CIDR 表單看起來像其中之一:1.1.1.0/241.1.0.0/16. 所以,1.1.0.0/24或者1.1.1.0/16不是我想要的。

這意味著,如果 pass list2cidr 24 iplist.txt,它必須形成這個輸出

x.x.x.0/24

如果我通過list2cidr 16 iplist.txt,它必須形成這個輸出

x.x.0.0/16

目前,我已經使用 bash 腳本完成了輸出的第一部分,但我還沒有完全測試它

我不知道,所以我寫了一個(在 perl 中)。我還認為您的工具設計不完整。

  • 它應該只給出所請求級別的 CIDR 塊,即使其中只有一個地址。
  • 它也應該在沒有目標級別的情況下工作。

因此:

$ cat sample

1.22.3.4
1.28.3.5
1.211.3.7
1.211.3.2
1.211.3.1

$ list2cidr 24 sample

1.22.3.0/24
1.28.3.0/24
1.211.3.0/24

$ list2cidr 16 sample

1.22.0.0/16
1.28.0.0/16
1.211.0.0/16

$ list2cidr sample

1.0.0.0/8
   1.16.0.0/12
       1.22.3.4
       1.28.3.5
   1.211.3.0/29
       1.211.3.0/30
           1.211.3.1
           1.211.3.2
       1.211.3.7

$ 

我目前的實現只做 IPv4。程式碼是:

#!/usr/bin/perl -w

use strict;

my $target;
if ($ARGV[0] =~ m{^\d+}) {
   $target = + shift @ARGV;
}


my $map = [];

sub record($) 
{
   my $v = shift;

   my $m = $map;
   for my $i ( 0 .. 31 ) {
       my $k = $v & (1 << (31-$i));
       $m = $m->[!!$k] ||= (($i == 31) ? $v : []);
   }
}

while (<>) {
   chomp;

   if (m{^\s*(\d+)\.(\d+)\.(\d+)\.(\d+)\s*\z}) {
       if (($1 < 256) && ($2 < 256) && ($3 < 256) && ($4 < 256)) {
           record(($1<<24) | ($2<<16) | ($3 << 8) | $4);
           next;
       }
   }

   printf("Invalid: %s\n", $_);
}

sub output($$$) {
   my ($addr, $bits, $indent) = @_;
   printf "%*s%d.%d.%d.%d",
          $indent*4, '',
          0xff & ($addr >> 24),
          0xff & ($addr >> 16),
          0xff & ($addr >>  8),
          0xff & ($addr      );
   printf("/%d", $bits) if $bits < 32;
   print "\n";
}

sub walk($$$$);
sub walk($$$$) {
   my ($prefix, $bits, $indent, $m) = @_;
   #printf ("%d %d %d ...\n", $prefix, $bits, $indent);
   if ($bits == ($target//-1)) {
       output $prefix<<(32-$bits), $bits, 0;
   } elsif ($bits == 32) { 
       warn 'mismatch '.$prefix.' != '.$m unless $prefix == $m;
       output $prefix, $bits, $indent unless defined $target;
   } elsif (defined $m->[0]) {
       if (defined $m->[1]) {
           output $prefix<<(32-$bits), $bits, $indent unless defined $target;
           walk($prefix*2,   $bits+1, $indent+1, $m->[0]);
           walk($prefix*2+1, $bits+1, $indent+1, $m->[1]);
       } else {
           walk($prefix*2,   $bits+1, $indent, $m->[0]);
       }
   } else {
       if (defined $m->[1]) {
           walk($prefix*2+1, $bits+1, $indent, $m->[1]);
       } else {
           warn sprintf('Empty node at prefix=%x bits=%d indent=%d', $prefix, $bits, $indent);
       }
   }
}

walk (0, 0, 0, $map);

引用自:https://unix.stackexchange.com/questions/671839