在Java中,给定IP地址范围,返回覆盖范围的CIDR块的最小列表

Ste*_*hen 5 java ip cidr

我在将IP地址范围转换为CIDR块列表时遇到了一些逻辑问题.我相信这个网站做得很好:http://ip2cidr.com/

我想传入一个起始IP地址和一个结束IP地址,并让java吐出所需的最小CIDR块列表,仅覆盖传入的范围,仅此而已.

例如,如果我传入1.1.1.111的起始地址和1.1.1.120的结束地址,我希望得到回报:1.1.1.111/32 1.1.1.112/29 1.1.1.120/32

(使用/ 32表示单个地址.)

Ste*_*hen 11

我的最后一个答案有一些错误,当IP地址的第一个八位字节太大时就会出现这些错误.这个更好用.几乎完全取自这里:http://facedroid.blogspot.com/2010/06/ip-range-to-cidr.html

import java.util.ArrayList;
import java.util.List;

public class RangeToCidr {
    public static List<String> range2cidrlist( String startIp, String endIp ) {         
        long start = ipToLong(startIp);         
        long end = ipToLong(endIp);           

        ArrayList<String> pairs = new ArrayList<String>();         
        while ( end >= start ) {             
            byte maxsize = 32;             
            while ( maxsize > 0) {                 
                long mask = CIDR2MASK[ maxsize -1 ];                 
                long maskedBase = start & mask;                 

                if ( maskedBase != start ) {                     
                    break;                 
                }                 

                maxsize--;             
            }               
            double x = Math.log( end - start + 1) / Math.log( 2 );             
            byte maxdiff = (byte)( 32 - Math.floor( x ) );             
            if ( maxsize < maxdiff) {                 
                maxsize = maxdiff;             
            }             
            String ip = longToIP(start);             
            pairs.add( ip + "/" + maxsize);             
            start += Math.pow( 2, (32 - maxsize) );         
        }         
        return pairs;     
    }       

    public static final int[] CIDR2MASK = new int[] { 0x00000000, 0x80000000,             
        0xC0000000, 0xE0000000, 0xF0000000, 0xF8000000, 0xFC000000,             
        0xFE000000, 0xFF000000, 0xFF800000, 0xFFC00000, 0xFFE00000,             
        0xFFF00000, 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,             
        0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, 0xFFFFF800,             
        0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0,             
        0xFFFFFFE0, 0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE,             
        0xFFFFFFFF };       

    private static long ipToLong(String strIP) {         
        long[] ip = new long[4];         
        String[] ipSec = strIP.split("\\.");         
        for (int k = 0; k < 4; k++) {             
            ip[k] = Long.valueOf(ipSec[k]);         
        }         

        return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];     
    }       

    private static String longToIP(long longIP) {         
        StringBuffer sb = new StringBuffer("");         
        sb.append(String.valueOf(longIP >>> 24));         
        sb.append(".");         
        sb.append(String.valueOf((longIP & 0x00FFFFFF) >>> 16));         
        sb.append(".");         
        sb.append(String.valueOf((longIP & 0x0000FFFF) >>> 8));         
        sb.append(".");         
        sb.append(String.valueOf(longIP & 0x000000FF));   

        return sb.toString();     
    } 
}
Run Code Online (Sandbox Code Playgroud)


Paŭ*_*ann 5

你需要了解二进制数,仅此而已.

CIDR块只不过是一系列具有公共前缀所有可能后缀的二进制数.假设下面的例子我们有8位IP地址,类/1,...到/8.

在您的情况下(暂时忽略1.1.1),我们将您的数字写为二进制数:

 1101111   - 111
 1110000   - 112
 1110001   - 113
   ...
 1110110   - 118
 1110111   - 119
 1111000   - 120
Run Code Online (Sandbox Code Playgroud)

您将看到所有数字都有一个共同的11前缀,但我们的列表不包含所有这些数字.所以我们必须将它分成两个列表 - 一个带有110,一个带有111.第一个只包含一个数字,所以我们从中创建一个/8块(111/8).

另一个列表(从112到120)不包含所有数字111(从那时起它将达到127),所以我们再次拆分 - 一个列表1110,另一个列表1111.第一个现在是完整的块1110????(或112/4),第二个只是一个地址,即11111000(或120/8).

所以,现在只扩展到32位而不是8位,并在Java中实现,你已经准备好了.

在数学术语中,一个块总是从x*2 ^ n变为(x + 1)*2 ^ n - 1,然后我们使用32-n作为块大小后缀.所以你只需要找到两个幂的下一个倍数.