2015-10-30 3 views
3

Я пытаюсь преобразовать диапазон IP-адресов в нотацию CIDR в Java. Может ли кто-нибудь привести пример того, как это можно достичь?Как преобразовать диапазон IP-адресов в CIDR в Java?

Я использовал SubnetUtils для преобразования диапазона CIDR в IP-адрес, но я не могу понять наоборот.

Например: (используя http://ip2cidr.com/)

Вход 1: 5.10.64.0
вход 2: 5.10.127.255
Результат: 5.10.64.0/18

Thanks, Dhava л

+0

Я думаю, что вы найдете информацию, которую вы ищете в этом посте: http://networkengineering.stackexchange.com/ Вопросы/3697/the-slash-after-an-ip-address-cidr-notation –

+0

Реальный способ сделать это - «адрес и маска», чтобы получить адрес подсети и «подсеть + NOT маска», чтобы получить широковещательный адрес , И IP-адрес, и маска - это 32-разрядные целые числа без знака, и вам нужно использовать их для обработки IP-адресов. –

+1

Если вы всегда уверены, что у вас будет первый (0) адрес и последний (широковещательный адрес), тогда вы можете получить однозначный ответ на это. Но если вы просто дадите ему произвольный диапазон, вы получите более одного ответа. – RealSkeptic

ответ

1

В случае, если вы не поняли из моих комментариев:

IP математика должна быть сделана в двоичной системе. IP-адреса и маски представляют собой целые числа без знака (32 бита для IPv4, 128 бит для IPv6). Все, что вам нужно знать, это адрес и маска, и вы можете понять все остальное.

Это алгоритм для того, что вы хотите выполнить, и он применим как к IPv4, так и к IPv6.

На основании вашего вопроса вам дается подсеть (вход 1) и последний адрес (вход 2).

  1. Вычесть целое число без знака входа 1 от целого числа без знака ввода 2. В результате обратная маска подсети. Обратная маска подсети должна быть 0 или маску подсети обратной плюс 1 должна быть сила 2, иначе у Вас есть ошибка в одном из входов (СТОП ВХОД ERROR).
  2. Обратная маска NOT (результат этапа 1) представляет собой маску подсети.
  3. Если Input 1 AND маска подсети не равно Input 1, у вас есть ошибка в одном из входов (STOP, ошибка ввода).
  4. Длина маски (номер CIDR) - это номер 1 бит в маске подсети . Есть несколько способов, чтобы вычислить количество 1 битов в виде двоичного числа, но если маска подсети является максимальным целым числом (или обратная маска 0), то длина маски 32 (IPv4) или 128 (IPv6).Вы можете цикл, подсчет количества циклов и смещение маски подсети влево, пока она не равно 0, петля подсчета количества циклов и смещение обратной маски к вправо, пока он не станет равным 0 затем добавляя 1 к общему и вычитания из общей 32 (IPv4) или 128 (IPv6), или вычесть показатель мощности 2 от общей обратной маски плюс 1 от 32 (IPv4) или 128 (IPv6).
  5. На данный момент у вас есть подтвержденный вход 1 (подсеть), вход 2 (последний адрес ) и рассчитанная длина маски (номер CIDR).
  6. Конечным результатом будет <Input 1>/<Mask Length>.

Ваш пример:

Шаг 1 (5.10.127.255 - 5.10.64.0 = 0.0.64.127):

101000010100111111111111111 - 01000010100100000000000000 = 11111111111111 

Шаг 2 (NOT 0.0.64.255 = 255.255.192.0 является степенью двух):

NOT 00000000000000000011111111111111 = 11111111111111111100000000000000 

Шаг 3 (5.10.64.0 AND 255.255.192.0 = 5.10.64.0):

01000010100100000000000000 AND 11111111111111111100000000000000 = 01000010100100000000000000 

Шаг 4 (0.0.64.255 + 1 = 0.0.65.0 = 2^14, exponent of 2^14 = 14, 32 - 14 = 18):

00000000000000000011111111111111 + 1 = 00000000000000000100000000000000 = 2^14, exponent of 2^14 = 14, 32 - 14 = 18 

Шаг 5 (вход 1 = 5.10.64.0, вход 2 = 5.10.127.255, маска Длина = 18)

Шаг 6 (Конечный результат = 5.10.64.0/18)

+0

Это довольно проницательно. Спасибо за подробную запись! –

+0

Это обрабатывает канонические случаи. Но не объясняет, как обрабатывать диапазон таких как 5.10.64.1 к 5.10.127.255, что приводит к 14 CIDRs: 5.10.64.1/32 5.10.64.2/31 5.10.64.4/30 5.10.64.8/29 5.10.64.16/28 5.10.64.32/27 5.10.64.64/26 5.10.64.128/25 5.10.65.0/24 5.10.66.0/23 5.10.68.0/22 ​​ 5.10.72.0/21 5,10. 80.0/20 5.10.96.0/19 – GreatAndPowerfulOz

+0

Ваш пример не относится к исходному вопросу, на что я отвечал. –

2

Итак, я смог найти код Java здесь: In Java, given an IP Address range, return the minimum list of CIDR blocks that covers the range

public class IP2CIDR { 

    public static void main(String[] args) { 
     System.out.println(range2cidrlist("5.104.109.160", "5.104.109.191")); 
    } 

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

Спасибо всем за понимание и помощь!

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

public class RangeToCidr { 
    public static List<String> range2cidrlist(String startIp, String endIp) { 
     // check parameters 
     if (startIp == null || startIp.length() < 8 || 
      endIp == null || endIp.length() < 8) return null; 
     long start = ipToLong(startIp); 
     long end = ipToLong(endIp); 
     // check parameters 
     if (start > end) return null; 

     List<String> result = new ArrayList<String>(); 
     while (start <= end) { 
      // identify the location of first 1's from lower bit to higher bit of start IP 
      // e.g. 00000001.00000001.00000001.01101100, return 4 (100) 
      long locOfFirstOne = start & (-start); 
      int maxMask = 32 - (int) (Math.log(locOfFirstOne)/Math.log(2)); 

      // calculate how many IP addresses between the start and end 
      // e.g. between 1.1.1.111 and 1.1.1.120, there are 10 IP address 
      // 3 bits to represent 8 IPs, from 1.1.1.112 to 1.1.1.119 (119 - 112 + 1 = 8) 
      double curRange = Math.log(end - start + 1)/Math.log(2); 
      int maxDiff = 32 - (int) Math.floor(curRange); 

      // why max? 
      // if the maxDiff is larger than maxMask 
      // which means the numbers of IPs from start to end is smaller than mask range 
      // so we can't use as many as bits we want to mask the start IP to avoid exceed the end IP 
      // Otherwise, if maxDiff is smaller than maxMask, which means number of IPs is larger than mask range 
      // in this case we can use maxMask to mask as many as IPs from start we want. 
      maxMask = Math.max(maxDiff, maxMask); 

      // Add to results 
      String ip = longToIP(start); 
      result.add(ip + "/" + maxMask); 
      // We have already included 2^(32 - maxMask) numbers of IP into result 
      // So the next round start must add that number 
      start += Math.pow(2, (32 - maxMask)); 
     } 
     return result; 
    } 

    private static long ipToLong(String strIP) { 
     String[] ipSegs = strIP.split("\\."); 
     long res = 0; 
     for (int i = 0; i < 4; i++) { 
      res += Long.valueOf(ipSegs[i]) << (8 * (3 - i)); 
     } 
     return res; 
    } 

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

     return sb.toString(); 
    } 
} 
+0

Я просто заменяю длинный статический массив int стартом & - start, который является короткой, чтобы найти первый. –

0

что-то короткое и сладкое в Python:

#!/usr/bin/env python 
import ipaddress 
import math 

ip_from = '5.10.64.0' 
ip_to = '5.10.127.255' 
ip_from_long = int(ipaddress.ip_address(unicode(ip_from))) 
ip_to_long = int(ipaddress.ip_address(unicode(ip_to))) 
ip_range = ip_to_long - ip_from_long 
ip_range +=1 
# the clever line of code 
cidr_range = math.log(4294967296/ip_range)/math.log(2) 
# test for a zero/non-zero fractional part 
if cidr_range % 1 == 0: 
    # the output will be: 5.10.64.0/18 
    print ip_from + '/' + str(int(cidr_range)) 
else: 
    print "Error: Not an exact CIDR range - " + str(cidr_range) 
0
public static int log2(int i) { 
    int count = 0; 
    i >>= 1; 
    while(i > 0) { 
     count++; 
     i >>= 1; 
    } 
    return count; 
} 

public static List<String> range2CIDR(String startIp, String endIp) { 
    List<String> res = new ArrayList<>(); 
    try { 
     int start = ipS2I(startIp); 
     int end = ipS2I(endIp); 
     while(start <= end) { 
      int firstNonZero = start & -start; 
      int maxMask = 32 - log2(firstNonZero); 
      maxMask = Math.max(maxMask, 32 - log2(end - start + 1)); 
      res.add(ipI2S(start) + "/" + maxMask); 
      start += 1 << (32 - maxMask); 
     } 
    }catch(Exception e) { 
     return res; 
    } 

    return res; 
} 

public static int ipS2I(String ip) throws Exception { 
    String[] sa = ip.split("\\."); 
    if (sa.length != 4) { 
     throw new Exception("Bad ip address"); 
    } 
    int res = 0; 
    for (int i = 0; i < 4; i++) { 
     int t = Integer.valueOf(sa[i]); 
     if (t < 0 || t > 255) { 
      throw new Exception("Bad ip address"); 
     } 
     res += t << ((3-i) << 3); 
    } 
    return res; 
} 

public static String ipI2S(int ip) { 
    StringBuilder sb = new StringBuilder(); 
    sb.append((ip>>24) & 0xFF).append(".").append((ip>>16)&0xFF).append(".").append((ip>>8) & 0xFF).append(".").append(ip & 0xFF); 
    return sb.toString(); 
} 
Смежные вопросы