3

IPv6文字列からIPv6IPの最初のx個をリストするためのシンプルでエレガントな方法は何ですか。

例えば、

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

これは、intに変換されたIPv4で機能した可能性のあるコードのサンプルです。

$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?
}
4

2 に答える 2

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;
}

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
于 2013-02-08T22:57:02.400 に答える
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 );
}
于 2013-05-14T19:49:39.933 に答える