2013-02-08 30 views
3

什麼是從IPv6字符串中列出第一個IPv6 IP地址的簡單而優雅的方式。從IPv6字符串中增加單個IP地址(php)

例如,

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? 
} 
+1

注意到,隨着51 CIDR後綴IPv6地址描述了一系列的1,5111572745183E + 23的地址。你可以如下計算這個數字:'echo pow(2,(128 - 51));' – hek2mgl 2013-02-08 19:56:08

+0

hmmm,不是pow(2,65-51)?我認爲/ 64是最小的。 http://www.ripe.net/internet-coordination/press-centre/understanding-ip-addressing – 2013-02-08 19:58:29

+3

不,IPv6是128位。 – impl 2013-02-08 19:59:51

回答

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環路):

[email protected]:~$ ./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 
0

類似的東西(在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); 
}