Riduce un elenco di IPv4 al CIDR più basso comune

5

Ho una lunga lista di indirizzi IP che mostrano alcuni schemi di vicinanza

Esempio:

XX.249.91.16  
XX.249.91.21  
XX.249.91.32  
XX.249.91.160  
XX.249.91.165  
XX.249.92.15  
XX.249.92.25  
XX.249.92.51  
XX.249.92.234  

ea volte un whois rivela un intervallo come questo

XX.163.224.0 - XX.163.239.255

Vorrei creare un elenco di CIDR che mi dà il numero più basso comune

Sembra che Python abbia già una cosa del genere - iprange_to_cidrs - ma ne ho bisogno in JavaScript

XX.249.90.0/16

se è ciò che gestirà

XX.249.91.0 - XX.249.92.255  

idem XX.163.200.0 / nn per gestire

XX.163.224.0 - XX.163.239.255

Una calcolatrice che può fare un intervallo alla volta in cui gioco con la maschera è qui link

La mia lingua preferita è JavaScript e ho il seguente avvio ma ho bisogno dell'algoritmo che fa la corrispondenza e la trasformazione

var list = [
    [1234,"10.249.91.16"],
    [5678,"10.249.91.21"],
    [123,"10.249.91.32"],
    [456,"10.249.91.160"],
    [789,"10.249.91.165"],
    [3456,"10.249.92.15"],
    [7890,"10.249.92.25"],
    [1234,"10.249.92.51"],
    [5432,"10.249.92.234"]
]
function dec2bin(ip) { 
    return ip.split(".").map(function(num) { 
      return ("00000000"+parseInt(num,10).toString(2)).slice(-8); 
    }).join(".");
}
$(function() {
    $res = $("#res");
    $.each(list,function(_,arr) {
        $res.append('<br/>'+dec2bin(arr[1])+" - "+arr); 
    });
});

UPDATE dopo aver esaminato una risposta

FIDDLE

function getDec(ip) {
  var octet = ip.split(".");
  return (octet[0] << 24) | (octet[1] << 16) | (octet[2] << 8) | octet[3];
}
var res = document.getElementById("res");

var adr1 = "111.163.224.0";
var adr2 = "111.163.239.255"
var XOR = getDec(adr1)^getDec(adr2);

// now what?

Aggiornamento 2:

il risultato della gamma 111.163.224.0 - 111.163.239.255 potrebbe essere 111.163.224.0/20 ? dato che abbiamo

01101111.10100011.11100000.00000000 - 0,111.163.224.0
01101111.10100011.11101111.11111111 - 0,111.163.239.255
    
posta mplungjan 30.06.2014 - 16:12
fonte

2 risposte

1

La soluzione era più semplice del previsto. Apprezzo il tempo e la spiegazione di Blrfl ma l'intera cosa ridotta al numero da usare sono i due indirizzi ANDed mascherati dal numero di primi 0 nella rappresentazione binaria dei due indirizzi XORed

var adr1 = "111.163.224.0",
    adr2 = "111.163.239.255",
    AND  = dot2dec(adr1)&dot2dec(adr2), 
    XOR  = num2dot(dot2dec(adr1)^dot2dec(adr2)),
    mask = dec2bin(XOR).replace(/\./g,"").indexOf("1");

in questo caso 111.163.224.0/20

    
risposta data 08.07.2014 - 14:04
fonte
6

Quello che stai cercando è un insieme di bit contigui di ordine elevato nell'indirizzo che non cambiano nell'intero insieme di indirizzi. Gli indirizzi IPv4 sono, al loro interno, numeri interi senza segno a 32 bit. La notazione a punti tratteggiata è una comodità per gli umani. È meglio affrontarli in quella forma. La conversione è semplice:

integer_ip = (octet1 << 24) | (octet2 << 16) | (octet3 << 8) | octet4

Una volta che hai numeri interi, lo strumento giusto per determinare quali cambiano è esclusivo bit per bit o ( ^ in molte lingue derivate da C). Questo perché rileva il cambiamento, restituendo un 1 bit se il bit corrispondente nei due valori differisce e un 0 altrimenti.

Utilizzerò le quantità a 8 bit negli esempi per tenerlo leggibile, ma ciò si applica esattamente ai numeri a 32 bit che otterresti da un indirizzo IP.

Dobbiamo iniziare con un numero intero i cui bit indicano quali bit sono stati modificati, ovvero nessuno di essi:

changed_bits = 0x00

Per ciascun indirizzo dopo il primo, gli elementi XOR n e n-1 , risultando nell'insieme di bit che sono cambiati tra i due. Quelli possono essere ordinati con il nostro set di bit modificati da aggiungere al set:

a[0] = 0x10
a[1] = 0x11    0x10 ^ 0x11 = 0x01    changed_bits = 0x00 | 0x01 = 0x01
a[2] = 0x1f    0x11 ^ 0x1f = 0x0e    changed bits = 0x01 | 0x0e = 0x0f

Il valore finale di changed_bits , 0x0f , indica che durante tutti i confronti, i quattro bit superiori non sono cambiati (sono tutti zeri) e i quattro bit inferiori hanno fatto (tutti). Quindi tutto ciò che devi fare è contare il numero di bit invariati (zero), a partire dal più significativo:

cidr_size = 0;
for ( bit=0 ; bits < 8 ; ++bits ) {   // Use 32 for IPs
    if ( changed_bits & 0x80 ) {      // Use 0x800000 for IPs
        break;  // Stop when we hit the first bit that changed.
    }
    ++cidr_size;
    changed_bits = changed_bits << 1;  // Rotate the next bit into the high spot
}

A questo punto, cidr_size manterrà il numero di bit che i tuoi indirizzi hanno in comune. Quindi puoi usarlo per costruire una maschera con il numero corretto di bit

mask = 0xff << (8 - cidr_size)  // Use 0xffffffff and 32 for IPs

Con quello in mano, puoi usarlo contro uno qualsiasi dei numeri presenti nel tuo elenco per trovare il blocco CIDR:

cidr_block = a[0] & mask

Converti cidr_block in ottetti, aggiungi una barra, sputa cidr_size e sei in affari.

Addendum:

In questa risposta otterrai il CIDR più basso per un intero elenco di indirizzi.

Dato solo IP, non esiste un algoritmo magico per determinare il CIDR da cui provengono. Sulla base di ciò che hanno in comune, gli IP utilizzati nella domanda potrebbero essere inclusi in uno qualsiasi dei 13 blocchi CIDR grandi come 10.0.0.0/8 o piccoli come 10.249.88.0/20 . (Sono possibili anche blocchi superiori a /8 , ma la realtà pratica è che nessun blocco più grande di quello è mai stato emesso.)

Per raggruppare correttamente gli IP, è necessario un database dei CIDR che sono stati emessi e che potrebbero essere uniti agli IP che hai, raggruppati per CIDR e aggregati per ottenere un conteggio. L'unica altra cosa che puoi farla franca è conoscere la maschera di rete che accompagna ogni IP, cosa che non accadrà perché la parte ricevente non la vede.

    
risposta data 01.07.2014 - 06:03
fonte

Leggi altre domande sui tag