输出所有有效的有类公共单播IPv4地址


10

IPv4地址为32位宽,因此地址空间的大小为2 32或4,294,967,296。但是,这只是理论上的上限。它不能准确表示公共互联网上可能实际使用的所有地址。

出于此挑战的目的,假定所有寻址都是分类的。实际上,地址空间的有类别细分已被CIDR(无类别域间路由和VLSM(可变长度子网掩码))取代,但此挑战被忽略。

根据分类地址方案,分为3类:

  • A类- 0.0.0.0127.255.255.255/8网络掩码长度
  • B类- 128.0.0.0191.255.255.255/16网络掩码长度
  • C类- 192.0.0.0223.255.255.255/24网络掩码长度

还定义了类D(多播)和E(保留),但是它们不用于公共单播地址。

根据该类别的网络掩码将每个类别细分为网络。

因此3.0.0.0就是一个A类网络的例子。对于A类网络掩码长度为8,所以对于这个网络的完整地址空间是3.0.0.03.255.255.255。但是,第一个地址(3.0.0.0)保留为网络地址,最后一个地址(3.255.255.255)保留为该网络的广播地址。因此可用地址的实际范围是3.0.0.13.255.255.254为2 24 - 2(= 16777214)总地址。

同样,200.20.30.0是C类网络的示例。对于C类网络掩码长度是24,所以该网络的完整地址空间是200.20.30.0200.20.30.255。卸下网络和广播地址叶可用地址的实际范围是200.20.30.1200.20.30.254为2 8 - 2(= 254)的总的地址。

可用于公共单播的地址范围还有其他限制。根据RFC 6890,不允许的范围是:

  • 0.0.0.0/8 -本地网络
  • 10.0.0.0/8 -私人使用
  • 100.64.0.0/10 -共享地址空间
  • 127.0.0.0/8 -环回
  • 169.254.0.0/16 -本地链接
  • 172.16.0.0/12-私人使用
  • 192.0.0.0/24 -IETF协议分配
  • 192.0.2.0/24 -保留供文档使用
  • 192.88.99.0/24 -6to4中继任意播
  • 192.168.0.0/16 -私人使用
  • 198.18.0.0/15 -标杆管理
  • 198.51.100.0/24 -保留供文档使用
  • 203.0.113.0/24 -保留供文档使用

请注意,上面的列表使用VLSR网络掩码来有效地指定范围。在除一种情况外的所有情况下,给定的掩模长度在范围开始时的特异性均小于或等于正常分类掩模的长度。因此,这些VLSR范围中的每一个都等效于一个或多个分类网络。例如172.16.0.0/12等同于B类网络172.16.0.0172.31.0.0或地址范围172.16.0.0172.31.255.255

此规则的例外是100.64.0.0/10VLSR范围,它比包含的100.0.0.0A类范围更具体。因此,100.0.0.0它将像其他A类范围一样进行处理,不同的是它的中间有一个4,194,304-address孔。在此一类范围的有效地址将是 100.0.0.0100.63.255.255100.128.0.0100.255.255.254,共2 24 - 2 22 - 2(= 12582910)总地址。

这项挑战的目标是输出可以有效分配给公共Internet主机的所有A,B和C类单播IPv4地址(即,排除上面详述的那些地址)。

  • 将不提供任何输入,也不应该期望输入。

  • 输出可以采用适合您的语言的任何形式,例如数组,列表,定界字符串。地址必须以标准的点分十进制格式输出。

  • 输出顺序无关紧要。

  • 不允许专门提供所需地址范围的内建函数。类似地,不允许使用任何方法为公共Internet 动态检查BGP(或其他协议)路由表。

数字最低的地址为1.0.0.1,数字最高的地址为223.255.255.254


此挑战类似于“ 打印出所有IPv6地址”,但是由于这些限制,因此需要非常不同的实现。

Answers:


2

PowerShell中,648个 641 625字节

for([uint64]$a=16MB;$a-lt2GB-16mb;$a++){if(($a%16mb)*(($a+1)%16mb)*($a-lt160MB-or$a-gt176MB)*($a-lt1604MB-or$a-ge1608MB)){([ipaddress]$a).IPAddressToString}}
for($a=2GB;$a-lt3GB;$a++){if(($a%64kb)*(($a+1)%64kb)*($a-lt2785152kb-or$a-gt2720mb)*($a-lt2753mb-or$a-gt2754mb)){([ipaddress]$a).IPAddressToString}}
for($a=3221225728;$a-lt3.5GB;$a++){if(($a%256)*(($a+1)%256)*(($a-lt3221225984-or$a-gt3221226240))*(($a-lt3227017984-or$a-gt3151385kb))*(($a-lt3156480kb-or$a-gt3156544kb))*(($a-lt3245184kb-or$a-gt3245312kb))*(($a-lt3247321kb-or$a-gt3325256959))*(($a-lt3405803776-or$a-gt3405804032))){([ipaddress]$a).IPAddressToString}}

编辑1-我淘汰了所有剩余的2的幂运算符,这又节省了7个字节。
编辑2-将[uint64]演员表移至第一个声明,$a从而消除了其他两个重铸,节省了16个字节。

三行,A类/ B类/ C类。为便于阅读,保留为单独的行。;-)

了解正在发生的事情的两个关键点:

  • PowerShell具有2的幂运算符KB, MB, GB。例如,4KB4096作为int 返回。我们在多个位置利用它来剃除数十个字节。
  • .NET [ipaddress]类将尝试通过采用数字的二进制表示形式将数字值解析为IP地址。我们将该构造函数与IPAddressToString参数一起用于输出。

通过将这两件事结合起来,我们可以将IP地址视为数字,并通过一个for()循环遍历它们。例如,A类子网的第一个循环从16MB2GB-16MB或从16777216213070643216777216is 的二进制表示形式,1000000000000000000000000或者00000001.00000000.00000000.00000000如果将其分成8位的块,那么我们可以轻松地看到它对应1.0.0.0于点分十进制表示法。同样,2130706432可以写为0111111100000000000000000000000001111111.00000000.00000000.00000000127.0.0.0。此处使用的每个整数或2的幂的整数都可以以此方式重写为IP地址。

因此,对于每个循环迭代,我们if()通过将各个语句相乘来构造一条语句,以清除排除的地址。由于在每个第一语句if是一个整数(由于模测试),剩余的布尔值被转换为任一01假/真。如果任何一个语句为假,则整个乘法将变为0,因此为假。因此,仅当所有语句为真时,我们才输出解析结果。

略微偏离地面:

# Class A
for($a=16MB;$a-lt2GB-16mb;$a++){
  $b=($a%16mb)                     # x.0.0.0
  $b*=(($a+1)%16mb)                # x.255.255.255
  $b*=($a-lt160MB-or$a-gt176MB)    # 10.0.0.0/8
  $b*=($a-lt1604MB-or$a-ge1608MB)  # 100.64.0.0/10
  if($b){([ipaddress]::Parse($a)).IPAddressToString}
}

# Class B
for($a=2GB;$a-lt3GB;$a++){
  $b=($a%64kb)                           # x.y.0.0
  $b*=(($a+1)%64kb)                      # x.y.255.255
  $b*=(($a-lt2785152kb-or$a-gt2720mb))  # 169.254.0.0/16
  $b*=(($a-lt2753mb-or$a-gt2754mb))      # 172.16.0.0/12
  if($b){([ipaddress]::Parse($a)).IPAddressToString}
}

# Class C
for($a=3221225728;$a-lt3.5GB;$a++){
  $b=($a%256)                               # x.y.z.0
  $b*=(($a+1)%256)                          # x.y.z.255
  $b*=(($a-lt3221225984-or$a-gt3221226240)) # 192.0.2.0/24
  $b*=(($a-lt3227017984-or$a-gt3151385kb)) # 192.88.99.0/24
  $b*=(($a-lt3156480kb-or$a-gt3156544kb)) # 192.168.0.0/16
  $b*=(($a-lt3245184kb-or$a-gt3245312kb)) # 198.18.0.0/15
  $b*=(($a-lt3247321kb-or$a-gt3325256959)) # 198.51.100.0/24
  $b*=(($a-lt3405803776-or$a-gt3405804032)) # 203.0.113.0/24
  if($b){([ipaddress]::Parse($a)).IPAddressToString}
}

1

Batch,1930 1884 1848 1830字节

@echo off
for /l %%a in (1,1,9)do call:a1 %%a
for /l %%a in (11,1,99)do call:a1 %%a
for /l %%b in (0,1,63)do call:a2 100 %%b
for /l %%b in (128,1,255)do call:a2 100 %%b
for /l %%a in (101,1,126)do call:a1 %%a
for /l %%a in (128,1,168)do call:b1 %%a
for /l %%b in (0,1,253)do call:b2 169 %%b
call:b2 169 255
call:b1 170
call:b1 171
for /l %%b in (0,1,15)do call:b2 172 %%b
for /l %%b in (32,1,255)do call:b2 172 %%b
for /l %%a in (173,1,191)do call:b1 %%a
call:c3 192 0 1
for /l %%c in (3,1,255)do call:c3 192 0 %%c
for /l %%b in (1,1,87)do call:c2 192 %%b
for /l %%c in (0,1,98)do call:c3 192 88 %%c
for /l %%c in (100,1,255)do call:c3 192 88 %%c
for /l %%b in (89,1,167)do call:c2 192 %%b
for /l %%b in (169,1,255)do call:c2 192 %%b
for /l %%a in (193,1,197)do call:c1 %%a
for /l %%b in (0,1,17)do call:c2 198 %%b
for /l %%b in (20,1,50)do call:c2 198 %%b
for /l %%c in (0,1,99)do call:c3 198 51 %%c
for /l %%c in (101,1,255)do call:c3 198 51 %%c
for /l %%b in (52,1,255)do call:c2 198 %%b
for /l %%a in (199,1,202)do call:c1 %%a
for /l %%c in (0,1,112)do call:c3 203 0 %%c
for /l %%c in (114,1,255)do call:c3 203 0 %%c
for /l %%b in (1,1,255)do call:c2 203 %%b
for /l %%a in (204,1,223)do call:c1 %%a
exit/b
:a1
for /l %%b in (0,1,255)do call:a2 %1 %%b
exit/b
:a2
for /l %%c in (0,1,255)do call:a3 %1 %2 %%c
exit/b
:a3
for /l %%d in (0,1,255)do if not %2%3%%d==000 if not %2%3%%d==255255255 echo %1.%2.%3.%%d
exit/b
:b1
for /l %%b in (0,1,255)do call:b2 %1 %%b
exit/b
:b2
for /l %%c in (0,1,255)do call:b3 %1 %2 %%c
exit/b
:b3
for /l %%d in (0,1,255)do if not %3%%d==00 if not %3%%d==255255 echo %1.%2.%3.%%d
exit/b
:c1
for /l %%b in (0,1,255)do call:c2 %1 %%b
exit/b
:c2
for /l %%c in (0,1,255)do call:c3 %1 %2 %%c
exit/b
:c3
for /l %%d in (1,1,254)do echo %1.%2.%3.%%d

编辑:通过删除不必要的空格,节省了46 82个字节。使用exit/b代替节省了18个字节goto:eof


1
我数了1872个字节。从技术上讲,您也不需要@echo off
Addison Crump

@FlagAsSpam可能是CR;记事本喜欢保存它们。
尼尔

我认为您可以删除它们,因为我们以Unix UTF-8字节计数。
Addison Crump
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.