打印出所有IPv6地址


45

这使我想起几年前有人上传了洪流“黑客工具:所有IP地址的完整列表”。当然,这只是一个约40亿个IPv4地址的生成列表,但是有数千个“ h4xx0rz”下载了它。看妈妈,imahacker!

当时是这样,但如今每个人都已切换到IPv6。(对?)

您的任务是编写一个打印所有IPv6地址的程序

您应该编写一个完整的程序,该程序不输入任何内容并打印IPv6地址,每行显示一个,而没有其他输出。您的程序必须打印所有2 128个可能的地址,包括无效的地址。每个地址必须打印一次。您可以按任何顺序打印地址。

每个地址都可以完整打印,用冒号分隔8组4个十六进制数字,例如

2001:0db8:85a3:0000:0000:8a2e:0370:7334

您可以自行决定使用RFC 5952中的任何标准缩写:

  • 可以省略组中的前导零,除非0不能再进一步缩写。
  • :: 每个地址最多可使用一次,以缩写一个或多个全零组的序列。
  • 十六进制数字可以使用小写或大写。

如果您达到RFC 5952的推荐制式建议(仅小写字母,表示形式尽可能短,::如果可以在多个地方使用,请尽早使用),您将获得-20%的奖励

由于输出的大小,当我们坐在那里时,您的程序无法完成。您的程序可能在某些时候被外部手段中断(Ctrl+ C,拔出电源,…)。您的程序必须将输出作为流产生,以便在“合理”等待之后,它将产生一些行。基本上,不允许在内存中构造一个巨大的字符串仅在最后打印出来。任何会在“标准” PC上用尽内存的程序都将被取消资格。(尽管如此,如果您的程序运行了足够长的时间,它必须打印所有IPv6地址,然后退出。)

(如果这种情况对于运行该程序直到完成并随后让您看到输出的Web解释器来说是一个问题,并且您没有托管的解释器,请在问题的较小版本上测试您的程序,然后仔细进行调整到完整的2128。

您的分数是程序的长度(以字节为单位),如果获得奖励,则乘以0.8。这是代码高尔夫球,因此得分最低者获胜。


22
这是5.445 * 10 15兆字节。要存储所有这些数据,您至少需要15个地球大小的数据中心,其中除了紧密装入的硬盘驱动器外什么都没有。那是一个大洪流.....
卡兹·沃尔夫

7
@Mew我想知道文件将压缩到多小(使用gzip等通用压缩)。
SztupY

35
@SztupY:显然可以将输出压缩为25个字节(解压缩算法= Pyth解释器,压缩算法=发布到PPCG)从这个网站上潜伏,看来Pyth是一种相当通用的压缩格式。
Ben Voigt 2015年

3
以我的经验,@ Gilles是真正的重量级人物!很高兴看到您向我们的小PPCG角提出了问题!我也很高兴看到与网络相关的问题。
Digital Trauma 2015年

5
这让我想起了关于SO的“迭代所有可能的GUID”的问题。
MikeTheLiar 2015年

Answers:


5

Pyth,21个字节

KJ^8CdWJj\:ct.H+K=tJ4

使用while循环J作为迭代器变量。使用初始化最大值8^chr(' ')。通过添加该初始值,转换为十六进制然后删除第一个字符来填充。


该代码看起来好像有人在他们的键盘上打喷嚏,然后试图清理它。
darksky '17

@darksky那是您的golflangs:P
Esolanging Fruit

50

Python 3,65个字节·0.8 = 52.0

from ipaddress import*
n=4**64
while n:n-=1;print(IPv6Address(n))

7
荡蟒!它总是有正确的方法!:D
MayorMonty 2015年

ipaddress仅限于python3。

@ Hurricane996,是的,我一直在PyPI的 Python 2中使用它,却没有意识到它只进入了Python 3中的标准库。因此,我已经以一个字节为代价将其切换到Python 3。
Anders Kaseorg'2

@MDXF Python没有++或-运算符
Draconis

14

Pyth,27 25 24字节

注意:该代码以前有一个错误,已修复,它节省了1个字节

J^4 64WJj\:c%"%032x"=tJ4

打印类似的地址

ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe
ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffd
ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc
...
0000:0000:0000:0000:0000:0000:0000:0003
0000:0000:0000:0000:0000:0000:0000:0002
0000:0000:0000:0000:0000:0000:0000:0001
0000:0000:0000:0000:0000:0000:0000:0000

使用pad运算符的前一版本(更复杂)(也为24个字节):

J^4 64WJj\:c.[\032.H=tJ4

说明

J^4 64                  set J to 2^128
WJ                     while J is not 0:
            =tJ               decrement J
    %"%032x"                 format to length-32 hex string
   c           4            split every 4 chars
j\:                        join by : and print

Pyth,21个字节(无效)

jmj\:c.[\032.Hd4^4 64

这不能自1运行),将消耗至少2个132字节(2个52的存储器yobibytes)和2)的解释不喜欢它(2 128不适合ssize_t,所以没有lists表示大小的) 。它将按字典顺序打印地址。您可以通过将数字最终更改为可用的数字来尝试算法。


1
那怎么办……“ 任何在“标准” PC上用尽内存的程序都将被取消资格。”
TessellatingHeckler

2
@TessellatingHeckler第一个不会,因为它会迭代运行。我已明确将第二个标记为无效。
PurkkaKoodari 2015年

12

C(具有GCC扩展名),76字节* 0.8 = 60.8

__uint128_t i;main(){char s[50];for(;inet_ntop(10,&i,s,49),puts(s),++i>0;);}

这使用128位整数GCC扩展名简单地从计数::ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffffinet_ntop()正确格式化每个地址,以便可以领取-20%的奖金。

输出量

使用sed输出每百万线可达1000万:

$ ./ipv6all | sed -n '1~1000000p;10000000q'
::
4042:f00::
8084:1e00::
c0c6:2d00::
9:3d00::
404b:4c00::
808d:5b00::
c0cf:6a00::
12:7a00::
4054:8900::
$ 

请注意,我使用的是低端x86_64机器,并且网络地址通常始终按网络顺序排列(大端),因此使用可以有效地交换字节序inet_ntop()。没关系-仍然会(最终)显示所有地址。


11

CJam,36 27字节

G32#{(_"%032x"e%4/':*oNo}h;

-9个字节,感谢@Dennis(我忘了​​CJam具有字符串格式)。打印地址小写和降序。

出于明显的原因,请使用Java解释器,而不要使用在线解释器。不过,您可以替换G32#一些较小的东西进行在线测试,例如,这是最后100个

说明

G32#             16^32 = 2^128. Call this n
{ ... }h;        While loop. The final ; is to pop n at the end
 (               Decrement n
 _               Copy n
 "%032x"e%       String format to hex, padded to 32 digits
 4/              Split into groups of 4
 ':*             Join with colons
 oNo             Output with newline

1
有趣的是,在线解释器除了无法处理当然的大小外,还会打印错误的结果。如果删除循环,仅打印第一个值,则打印0000:0000:0000:0000:0000:0000:ffff:ffff。看起来字符串格式在网上可能会有所不同。我确认它可以与脱机版本一起使用。
Reto Koradi 2015年

n是一样的oNoTIO
Esolanging Fruit

8

Python 2.7,67个字节

n=4**64
while n:n-=1;s='%032x'%n;exec"s=s[4:]+':'+s[:4];"*7;print s

作为用于插入冒号的方法的副作用,打印地址时,最右边的列显示在左侧:

ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
fffe:ffff:ffff:ffff:ffff:ffff:ffff:ffff
fffc:ffff:ffff:ffff:ffff:ffff:ffff:ffff
...
0003:0000:0000:0000:0000:0000:0000:0000
0002:0000:0000:0000:0000:0000:0000:0000
0001:0000:0000:0000:0000:0000:0000:0000

1
旋转真的很整齐!也迟来了,但是受到无政府状态的欢迎:)
Sp3000

3
如果您说最右边的列在左边,则显示无效的IPv6地址,但是如果这些列在正确的位置,则为[printing] the addresses in any order。;)
TessellatingHeckler 2015年

7

Verilog,335

我的第一个Verilog提交内容可能会使用更多的高尔夫球,但是我现在没有能力这样做。c是时钟,o是ASCII输出。由于填充为零而不是缩写,因此不符合格式化奖金的资格。

module b(output[0:38]o,input c);reg[127:0]a;wire[0:39]d;assign o=d[0:38];always @(posedge c) a<=a+(~(&a));genvar i,j;generate for(i=0;i<8;i=i+1) begin:q for(j=0;j<4;j=j+1) begin:r assign d[5*i+j]=a[16*i+4*j:16*i+4*j+7]>9?{4'h6,a[16*i+4*j:16*i+4*j+7]-9}:{4'h3,a[16*i+4*j:16*i+4*j+7]};end assign d[5*i+4]=8'h3A; end endgenerate endmodule

这是一个简单的迭代,然后进行一些位旋转以生成输出ASCII。我在最后一组之后用小技巧砍掉了结肠。在ISE 13.7 lin64上合成并似乎适用于xc3s500e-4ft256-4。


6

C,91-126字节

我的原始版本为119个字节。

long a[9],i;
f(long*x){if(65536&++*x)*x=0,f(x+1);}
main(){for(;!a[8];f(a))for(i=7;i+1;i--)printf(i?"%lx:":"%lx\n",a[i]);}

最佳高尔夫便携式版本,103字节(感谢@Dennis支持其中的某些概念)

long*p,a[9];
main(i){while(!a[8]){
for(i=8;i--;printf(i?"%lx:":"%lx\n",a[i]));
for(p=a;++*p>>16;*p++=0);}}

说明:算法本身相当简单。我使用long而不是unsigned int,因为它更短。在文件级别声明它们意味着所有内容都将以零进行预初始化。该f功能是带进位的简单增量,可对每个字的低16位进行操作。当循环进入第129位时,循环结束。

向后迭代printf意味着我们以“适当”的顺序打印地址,并且打印换行符的检查也短了几个字符。

这确实使用了一些非便携式构造。最好将其视为C的K&R方言,因为它使用隐式int返回类型,并且不包括stdio.h。而我对long的使用是从此得知的-在大多数现代系统上,int是足够的,因为它是32位。这可能在未经修改的PDP-11 Unix上运行。

但是,它可以更短。如果我们假设我们可以使用int(既可以是宽度大于16位的类型,也可以是具有各种属性的正好16位的类型,而这些属性在诸如二进制补码和算术翻转之类的许多系统上都是正确的),那么我们可以摆脱掉与使用时间长有关的东西。

大于16位,97字节的int版本。

a[9],*p;main(i){while(!a[8]){
for(i=8;i--;printf(i?"%x:":"%x\n",a[i]));
for(p=a;++*p>>16;*p++=0);}}

16位系统的版本,91字节。

a[9],*p;main(i){while(!a[8]){
for(i=8;i--;printf(i?"%x:":"%x\n",a[i]));
for(p=a;!++*p;p++);}}

奇怪的是,原始的K&R编译器实际上不支持不带int的声明(它可以很好地编译,但是将变量视为外部变量,因此在链接时未定义),因此需要额外的三个字节才能将声明更改为int*p,a[9];for总共94。

同样,如果假设在完成输出之前中断它的约束是硬约束,那么我们可以删除结束检查,节省五个字节。

奖励:完全ANSI便携式版本,126字节:

#include<stdio.h>
long*p,i,a[9];
int main(){while(!a[8]){
for(i=8;i--;printf(i?"%lx:":"%lx\n",a[i]));
for(p=a;++*p>>16;*p++=0);}}

为了便于阅读,所有版本中都插入了换行符,并且在不需要空格的位置插入了换行符,除了#includeANSI版本中的换行符之外,所有换行符均从字节数中排除。

除ANSI版本外,所有版本都位于main的末尾,因此可能会向操作系统返回虚假的退出代码。


1
在这里,可移植性通常不是问题。这适用于我的计算机:a[9];f(int*x){if(++*x>>16)*x=f(x+1);}main(i){for(;!a[8];f(a))for(i=8;i--;)printf(i?"%x:":"%x\n",a[i]);}
丹尼斯

你在这方面显然比我强得多。其中一些我感到非常惊讶的作品,但我确实应该想到i--状态检查。
Random832

当您对此进行测试时,您是否一直将其一直运行到进位?在您的版本中,我的机器将随机值放入a [0]中。
2015年

是。前6,553,601个IP地址已在我的机器上正确打印。
丹尼斯

Ideone不喜欢,要么,但它适用于键盘:包裹在a[0]包裹在a[1]
丹尼斯

5

AutoIt3,142个 231字节

For $a=0 To 2^32-1
For $b=0 To 2^32-1
For $c=0 To 2^32-1
For $d=0 To 2^32-1
$s=StringFormat("%08x%08x%08x%08x",$a,$b,$c,$d)
For $j=0 To 8
ConsoleWrite(StringMid($s,$j*4+1,4)&($j<7?":":""))
Next
ConsoleWrite(@LF)
Next
Next
Next
Next

说明

  • For $a=0 To 2^32-1:在0-2 ^ 32((2 ^ 32)^ 4 = 2 ^ 128)可能的组合上迭代4次。
  • $s=StringFormat("%08x%08x%08x%08x",$a,$b,$c,$d):将数字转换为长度为32(4 * 32)的十六进制字符串。
  • For $j=0 To 8:遍历字符串的所有8个部分。
  • ConsoleWrite(StringMid($s,$j*4+1,4)&($j<7?":":"")):从字符串中提取接下来的4个字符,并:在末尾添加一个冒号(),如果我们尚未到达最后一部分,则将所有内容输出到控制台
  • Next:结束内部for循环
  • ConsoleWrite(@LF):在行尾添加换行符
  • Next:结束外部for循环

预期的输出大小:(一行(39字节)+换行符(= 40字节)* 2 ^ 128 = 1.361 * 10 ^ 16 YB(约字节)


不是4^64 - 1
Anders Kaseorg

@AndersKaseorg显然我什至需要使用4个循环,直到2 ^ 32-1,因为AutoIt可以解析 4 ^ 64之类的大值,但不能将它们存储在循环中使用,因为整数最多只能上升2 ^ 32在AutoIt中为-1。
巨树2015年

5

肉桂胶,16个字节

0000000: 678b 36d0 b54c d44d 8bc5 455b 8d0c 0500  g.6..L.M..E[....                               .

在线尝试。(TIO限制输出)

说明

g模式将肉桂糖置于生成模式。字符串的其余部分解压缩到此正则表达式:

[0-9a-f][0-9a-f][0-9a-f][0-9a-f]:[0-9a-f][0-9a-f][0-9a-f][0-9a-f]:[0-9a-f][0-9a-f][0-9a-f][0-9a-f]:[0-9a-f][0-9a-f][0-9a-f][0-9a-f]:[0-9a-f][0-9a-f][0-9a-f][0-9a-f]:[0-9a-f][0-9a-f][0-9a-f][0-9a-f]:[0-9a-f][0-9a-f][0-9a-f][0-9a-f]:[0-9a-f][0-9a-f][0-9a-f][0-9a-f]

然后,它会创建一个与正则表达式匹配的所有可能字符串的生成器,并对其进行遍历,并打印出每个正则表达式。

有趣的是,高尔夫球手正则表达式([0-9a-f]{4,4}:){7,7}[0-9a-f]{4,4}实际上比上述正则表达式压缩到更长的字符串。


4

Commodore BASIC 2.0,339个字节

为了获得小写的十六进制数字,该程序以“移位模式”编写(按<SHIFT>+<C=>

1k=65535:a=0
2fOb=0tok:fOc=0tok:fOd=0tok:fOe=0tok:fOf=0tok:fOg=0tok:fOh=0tok
3x=a:goS6:?":";:x=b:goS6:?":";:x=c:goS6:?":";:x=d:goS6:?":";:x=e:goS6:?":";:x=f
4goS6:?":";:x=g:goS6:?":";:x=h:goS6:?
5nE:nE:nE:nE:nE:nE:nE:nE:a=a+1:ifa<65536tH2
6y=x/4096:goS7:y=x/256aN15:goS7:y=x/16aN15:goS7:y=xaN15:goS7:reT
7?mI("0123456789abcdef",y+1,1);:reT

由于内存,屏幕大小,数据大小和其他限制,仅在Commodore 64上进行这项工作是一个挑战。我考虑过使用缩写表示法,但是其他限制(例如,未记录的无法使用数组元素作为循环索引)意味着它将使程序的长度增加大约1000个字节。

第7行是HEX$()Commodore BASIC 2.0缺少的实现。我不能DEF FN为此使用a ,因为它们只能返回数字,而不能返回字符串。第6行是将其应用于一组四位数字的子例程,如果函数可以返回字符串,则本来会短很多。

第2行和第5行是八个嵌套循环,分别实现为七个“ for”循环和有条件的goto,因为八个“ for”循环与两个“ gosubs”组合以打印地址时,将溢出C64的小堆栈。

C64可以每秒打印约1.2个地址,估计运行时间为1.3 * 10 ^ 31年。


4

PowerShell(v4),193166162145103字节

TimmyD的无奖金版本(103字节):

$i=[bigint]::Pow(4,64);while($i-gt0){('{0:X32}'-f($i-=1)-replace'0(?=.{32})'-re‌​place'.{4}(?!$)','$0:')}

以前的奖励版本为145 * 0.8 = 116字节

从帮助TimmyDtomkandy,谁指出,0 -eq $false([bigint]0) -eq $true。因此,我以前的所有版本都不会终止。

$i=[bigint]::Pow(4,64);while($i-gt0){$i-=1;[IPAddress]::Parse((('{0:X32}'-f$i
)-replace'0(?=.{32})'-replace'.{4}(?!$)','$0:')).IPAddressToString}

以前是162,在某些正则表达式更改之前:

$i=[bigint]::Pow(4,64)
while($i){$i-=1;if(($x='{0:X32}'-f$i).Length-eq33){$x=$x.Substring(1)}
[IPAddress]::Parse(($x-replace'.{4}(?!$)','$0:')).IPAddressToString}

“ PowerShell应该具有合理竞争力的挑战!” -我,在我尝试之前。

说明

# PowerShell (PS) has no IP address arithmetic, e.g. IP + 1
#- PS has no 128 bit integers
#- PS has no automatic bignums

# Start from the top, with the BigInteger specialised Power()
$i = [BigInt]::pow(4,64)

# Loop 4**64 through 1, work with $i-1 for ff... -> ::0
while ($i) {
    # PS has no decrement operator for bignums
    # (no using $i-- in the while loop test)
    $i-=1

    # The Net.IPAddress class can't turn a BigInteger
    # into an IPv6 address directly. And because it mashes
    # IPv4 and IPv6 into one class, there's no obvious way 
    # to make a small number always cast to an IPv6 address.
    # Format the bignum as a string of 32 hex digits.
    $x = '{0:X32}' -f $i

    # The BigInteger often formats as /33/ hex digits, 
    # with a leading zero (to avoid unintentional +/- sign bits)
    # ( https://msdn.microsoft.com/library/dd268287 )
    # So remove the leading 0, if there is one
    if (($x).Length-eq33){$x=$x.Substring(1)}

    # I can't always remove the leading zero, because it 
    # can't parse FFFFF... into an address without colons
    # and this regex replace into groups of 4 with colons
    # would go wrong at length 31. No : after the last group
    # This is still better than split/join ... because there
    # isn't a split-into-groups-of-N that I know of.
    $x = ($x -replace '.{4}(?!$)', '$1:'

    # Woo! * 0.8 bonus! 45 characters to save 38! :D
    [IPAddress]::Parse($x).IPAddressToString

}

95没有奖金。感谢你们两个给我介绍[bigint],这非常方便(因为我本来不应该在豪华的环境中做的事情……)for($g=[bigint]::pow(2,128);$g;$g-=1){'{0:X32}'-f$g-replace'(?=(.{4})+$)',':'-replace'^0+:',''}
tomkandy

抱歉应该是for($g=[bigint]::pow(2,120);$g;$g-=1){'{0:X32}'-f$g-replace'(?=(.{4})+$)',':'-replace'^0*:',''}
tomkandy 2015年

for($g=[bigint]::pow(2,128);$g-gt0;$g-=1){'{0:X32}'-f$g-replace'(?=(.{4})+$)',':'-replace'^\d*:',''}是的,第一个地址是错误的,但不会在末尾重复。另外请注意,while($i)在你将不会停止在零- [boolean][bigint]0评估为真
tomkandy

@tomkandy哦,我必须只通过将$ i = 5设置为int来测试结尾。(复数0也不是$ false……也不是空字符串。我应该更加注意“它不是Python”)。谢谢!(而且您的这个脚本不再摆脱领导0::/)
TessellatingHeckler,2015年

@TessellatingHeckler不幸的是,奖金不足13个字节$i=[bigint]::Pow(4,64);while($i-gt0){('{0:X32}'-f($i-=1)-replace'0(?=.{32})'-replace'.{4}(?!$)','$0:')}-103 ...
AdmBorkBork 2015年

3

AutoIt3,137字节

For $i=0 To 4^64
$s=StringFormat("%032x",$i)
For $j=0 To 7
ConsoleWrite(StringMid($s,$j*4+1,4)&($j<7?':':''))
Next
ConsoleWrite(@LF)
Next

我知道,但是我是新来的:(
rav_kr 2015年

只要确保您知道。谢谢。
mbomb007

不是4^64 - 1
Anders Kaseorg

2

Python 2,95个字节

def i(p=0):
 while p<4**64:print':'.join(hex(p)[2:].zfill(32)[4*s:4*s+4]for s in range(8));p+=1

只需遍历从0到2 ^ 128的每个数字。首先它将当前数字转换为十六进制字符串,然后剥离'0x'该函数给出的数字。接下来,将字符串调整为在前面具有32个零,然后将其分成四个一组。最后,它用冒号将四人一组连接起来,打印出来并在当前数上加1。具有额外的奖励,如果您给它一个值,则可以以任何值启动它,但不需要输入。


如果您的答案是一个函数,则无需调用它:)
Beta Decay

@BetaDecay那是我的误会。固定!谢谢。
状态

2

哈斯克尔111

s[]=[[]]
s(a:b)=[y:z|z<-s b,y<-a]
r=replicate
main=mapM putStrLn$s$tail$concat$r 8$":":r 4"0123456789abcdef"

使用我自己的序列功能,s它不再泄漏内存,但是不再感到打高尔夫球。


您如何编译它以使其不会耗尽内存?随着我的ghc v7.10.2和性病。编译选项会泄漏内存。
nimi 2015年

2

CBM BASIC v7.0(166个字符)

a=65535
fOi=0toa:fOj=0toa:fOk=0toa:fOl=0toa:fOm=0toa:fOn=0toa:fOo=0toa:fOp=0toa:?hE(i)":"hE(j)":"hE(k)":"hE(l)":"hE(m)":"hE(n)":"hE(o)":"hE(p):nE:nE:nE:nE:nE:nE:nE:nE

Mark的答案是Commodore 64的BASIC 2.0,它缺少用于以十六进制打印数字的内置命令。但是,由于使用了HEX$()BASIC 7.0中的功能,Commodore 128版本要短得多。它不能放在单个逻辑行上(在C128上限制为160个字符),但仍可以在直接模式下作为两个单独的行输入。


看来您错过了一半的循环。IPv6地址是128位,而不是64位。
2015年

@Mark:感谢您指出这一点!我已经解决了这个问题。
Psychonaut

2

红宝石75

x=->s,n{n>0?65536.times{|m|x.(s+?:*(8<=>n)+m.to_s(16),n-1)}: p(s)};x.('',8)

这是一种递归解决方案,采用每个前缀并找到每个可能的后缀。递归地。


使用lambdas获得更短的函数定义:x=->s,n{...};x['',8]
门把手

0

Tcl 341 318 301

proc ip6 {p c} {
    set s %x:%x:%x:%x:%x:%x:%x:%x
    set p [scan $p $s]
    while {[set d 7]} {
        $c [format [string map {x 04x} $s] {*}$p]
        while {[set i [lindex $p $d]]==0xFFFF} {
            lset p $d 0
            if {!$d} return
            incr d -1
        }
        lset p $d [incr i]
    }
}
ip6 fFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:0000 puts
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.