【问题标题】:Increment individual IPs from IPv6 string (php)从 IPv6 字符串 (php) 增加单个 IP
【发布时间】:2013-01-24 15:12:07
【问题描述】:

从 IPv6 字符串中列出前 x 个 IPv6 IP 的简单、优雅的方法是什么?

例如,

listIPs("2600:f333:10:c000::0", 4)

回声

  • 2600:f333:10:c000::1
  • 2600:f333:10:c000::2
  • 2600:f333:10:c000::3
  • 2600:f333:10:c000::4

这是一个可能适用于 IPv4 的代码示例,因为它转换为 int:

$input = "2600:f333:10:c000::/51";
$max = 4;

list($block, $cidr) = explode("/", $input);

$first = inet_pton( $block );
echo inet_ntop($first) . "\n";

for ($i = 1; $i < $max; $i++) {
   //todo: die if it has exceeded block size based on $cidr
   echo inet_ntop($first + $i) . "\n"; //doesn't work, packed binary?
}

【问题讨论】:

  • 请注意,一个 CIDR 后缀为 51 的 ipv6 地址描述了 1,5111572745183E+23 个地址的范围。您可以按如下方式计算此数字:echo pow(2, (128 - 51));
  • 嗯,不是 pow(2, 64-51) ?我认为 /64 是最小的。 ripe.net/internet-coordination/press-centre/…
  • 没有 ipv6 使用 128 位地址。一个laaaaaarge地址空间:)
  • @divitiae:如果我计算正确,输出将约为 528 EiB(假设每行一个地址并且没有'::' 符号)。鉴于目前人类产生的信息估计为 12 EiB,它可能需要一些空间。
  • @hek2mgl 哦,伙计! facepalm 不知何故,我真的不敢相信我错过了。我知道对那个 linux 命令的原始调用有些困扰我,但逻辑是有道理的。从好的方面来说,我想我现在正在阅读逻辑而不是语法。我想它一定会在许多不同的语言之间发生跳跃。我的错! :P

标签: php ipv6


【解决方案1】:

类似的东西(在 PHP 中)。它接受一个 IPv4/IPv6 地址并按给定值递增:

// Takes an IPv4/IPv6 address in string format, and increments it by given value
function incrementIp($ip, $increment)
{
  $addr = inet_pton ( $ip );

  for ( $i = strlen ( $addr ) - 1; $increment > 0 && $i >= 0; --$i )
  {
    $val = ord($addr[$i]) + $increment;
    $increment = $val / 256;
    $addr[$i] = chr($val % 256);
  }

  return inet_ntop ( $addr );
}

【讨论】:

    【解决方案2】:

    这是一个用 C 编写的示例程序(因为我不懂 C++)。它相当快,但我对此并不满意。也许有人可以帮助我改进它。

    编辑:显然,我在它变成一个仅限 PHP 的问题之前写了这个。将其转换为 PHP 留给读者作为练习 (ew)。

    #include <arpa/inet.h>
    #include <string.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <stdio.h>
    #include <ctype.h>
    
    /*
     * Syntax: ./ipv6_list <ip>/<cidr-prefix>
     */
    int main(int argc, char **argv) {
        uint8_t start[16];
        uint8_t address[16];
        uint8_t mask[16] = { 0 };
    
        uint8_t prefix = 128;
        char *prefix_location;
    
        int i;
    
        /* This is the octet that, when changed, will result in <IP> & <mask> != <start IP> */
        int mask_check_octet = 0;
    
        if(argc != 2)
            return 1;
    
        /* Find prefix */
        if((prefix_location = strstr(argv[1], "/")) != NULL) {
            char *prefix_search = prefix_location + 1;
            char *prefix_remaining;
            long prefix_test;
    
            if(!isdigit(*prefix_search))
                return 2;
    
            errno = 0;
            prefix_test = strtol(prefix_search, &prefix_remaining, 10);
            if(errno == ERANGE || prefix_test < 0 || prefix_test > 128 || strcmp(prefix_remaining, "") != 0)
                return 2;
    
            prefix = (uint8_t)prefix_test;
            *prefix_location = '\0'; /* So we can just pass argv[1] into inet_pton(3) */
        }
    
        /* Convert prefix into mask */
        for(i = 0; i < 16; i++) {
            if(prefix == 0)
                break;
    
            mask_check_octet = i;
            if(prefix < 8) {
                mask[i] = ~((1 << (8 - prefix)) - 1);
                break;
            }
            else
                mask[i] = UINT8_MAX;
    
            prefix -= 8;
        }
    
        /* Find address */
        if(inet_pton(AF_INET6, argv[1], start) != 1)
            return 3;
    
        /* Start at the beginning of the network */
        for(i = 0; i < 16; i++) {
            start[i] &= mask[i];
            address[i] = start[i];
        }
    
        /* Iterate */
        while((address[mask_check_octet] & mask[mask_check_octet]) == start[mask_check_octet]) {
            char address_str[INET6_ADDRSTRLEN];
            inet_ntop(AF_INET6, address, address_str, sizeof(address_str));
            printf("%s\n", address_str);
    
            /* Add one to the address */
            for(i = 15; i >= 0; i--) {
                if(address[i] != UINT8_MAX)
                    break;
            }
            address[i]++;
            for(i++; i < 16; i++)
                address[i] = 0;
        };
    
        return 0;
    }
    

    你可以使用标准的shell命令来限制它的输出(或者只是修改while循环):

    nfontes@brioche:~$ ./ipv6_list '2607:fc50:0:d00::0/106' | head -n 200
    2607:fc50:0:d00::
    2607:fc50:0:d00::1
    2607:fc50:0:d00::2
    2607:fc50:0:d00::3
    2607:fc50:0:d00::4
    2607:fc50:0:d00::5
    2607:fc50:0:d00::6
    2607:fc50:0:d00::7
    2607:fc50:0:d00::8
    2607:fc50:0:d00::9
    2607:fc50:0:d00::a
    2607:fc50:0:d00::b
    2607:fc50:0:d00::c
    2607:fc50:0:d00::d
    2607:fc50:0:d00::e
    [...]
    2607:fc50:0:d00::c0
    2607:fc50:0:d00::c1
    2607:fc50:0:d00::c2
    2607:fc50:0:d00::c3
    2607:fc50:0:d00::c4
    2607:fc50:0:d00::c5
    2607:fc50:0:d00::c6
    2607:fc50:0:d00::c7
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-10
      • 2013-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-03
      相关资源
      最近更新 更多