In Java, given an IP Address range, return the minimum list of CIDR blocks that covers the range

后端 未结 5 1858
野趣味
野趣味 2021-01-03 02:04

I am having trouble with some of the logic in converting an IP Address range into a list of CIDR blocks. I do believe that this website is doing it right: http://ip2cidr.com

5条回答
  •  半阙折子戏
    2021-01-03 02:42

    I ended up repurposing some PHP code I had found and tweaking to my needs. Below is the class I ended up with.

    import java.util.ArrayList;
    import java.util.List;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class RangeToCidr {
        private static final String IP_ADDRESS = "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})";
        private static final Pattern addressPattern = Pattern.compile(IP_ADDRESS);
    
        public static List rangeToCidrList(String istart, String iend)  {       
            int start = toInteger(istart);
            int end = toInteger(iend);
    
            List result = new ArrayList();
    
            while (end >= start) {
                int maxsize = imaxblock( start, 32);
                double x = (Math.log(end - start + 1) / Math.log(2) ) ;
                int maxdiff = (int) (Math.floor(32 - Math.floor(x)));
    
                String ip = intToIP(start);
                if (maxsize < maxdiff) {
                    maxsize = maxdiff;
                }
                result.add( ip + "/" + (int)maxsize );
                start += Math.pow(2, (32-maxsize));
            }
            return result;
        }
    
        private static int toInteger(String address) {
            Matcher matcher = addressPattern.matcher(address);
            if (matcher.matches()) {
                return matchAddress(matcher);
            }
            else
                throw new IllegalArgumentException("Could not parse [" + address + "]");
        }
    
        private static int matchAddress(Matcher matcher) {
            int addr = 0;
            for (int i = 1; i <= 4; ++i) { 
                int n = (rangeCheck(Integer.parseInt(matcher.group(i)), -1, 255));
                addr |= ((n & 0xff) << 8*(4-i));
            }
            return addr;
        }
    
        private static int rangeCheck(int value, int begin, int end) {
            if (value > begin && value <= end) // (begin,end]
                return value;
    
            throw new IllegalArgumentException("Value [" + value + "] not in range ("+begin+","+end+"]");
        }
    
        private static String intToIP(int val) {
            int octets[] = new int[4];
            for (int j = 3; j >= 0; --j)
                octets[j] |= ((val >>> 8*(3-j)) & (0xff));
    
            StringBuilder str = new StringBuilder();
            for (int i =0; i < octets.length; ++i){
                str.append(octets[i]);
                if (i != octets.length - 1) {
                    str.append("."); 
                }
            }
            return str.toString();
        }
    
        private static long imask(int t)    {
            return (long)(Math.pow(2, 32) - Math.pow(2, 32-t) ) ;
        }
    
        private static int imaxblock(long ibase, int tbit)  {
            while (tbit > 0)    {
                long im = imask(tbit-1);
                long imand = ibase & im ;
                if (imand != ibase) {
                    break;
                }
                tbit--;
            }
            return tbit;
        }
    }
    

    I've got a few helper methods in there that, for the purposes of this question, clutter things up. But you can get the general idea.

提交回复
热议问题