2014-09-19 14 views
5

Vorrei scoprire tutte le reti IPv4 in notazione CIDR tra queste due reti:algoritmo per trovare reti IPv4 in notazione CIDR tra due indirizzi IPv4

10.11.3.64-10.11.3.127 
10.11.52.0-10.11.52.255 

reti IPv4 dovrebbero avere più breve subnet-mask come possibile.

È abbastanza facile convertire 10.11.3.127 in binario, aggiungere 1 e riconvertire in decimale per ottenere il primo indirizzo della rete. Quindi convertire 10.11.52.0 in binario, sottrarre 1 e riconvertire in decimale per ottenere l'ultimo indirizzo della rete. Tuttavia, qualche suggerimento che l'algoritmo è intelligente da usare per scoprire i blocchi CIDR all'interno dell'intervallo 10.11.3.128-10.11.51.255? Solo un suggerimento in quale direzione dovrei pensare dovrebbe essere abbastanza :)

+0

Spiega 'Le reti IPv4 dovrebbero avere una maschera di sottorete più corta possibile. – hek2mgl

+0

@ hek2mgl Ciò significa che i prefissi IPv4 dovrebbero essere il più grandi possibile. Per esempio l'intervallo di rete '10.11.3.128-10.11.51.255' può essere presentato in notazione CIDR con' 10.11.3.128/25' e quindi da '10.11.4.0/24' a' 10.11.51.0/24' usando/24 prefissi mentre in realtà quelli '/ 24' possono essere aggregati. – Martin

+0

o da '10.11.3.128/0' a' 10.11.51.255/0' usando un prefisso di 32 bit che è in realtà il più grande prefisso possibile per IPV4 .. è per questo che sto chiedendo .. – hek2mgl

risposta

2

Se si desidera che le maschere più corte (reti più grandi) siano disponibili, iniziare con l'indirizzo più basso (10.11.3.128) e mettere la maschera più piccola possibile, iniziare presso l'indirizzo successivo e mettere sulla più piccola maschera possibile, ecc Basta non superare la più grande indirizzo della serie:

  1. 10.11.3.128/25 (10.11.3.128 a 10.11.3.255) qualcosa di più piccolo non è valido
  2. 10.11.4.0/22 ​​(10.11.4.0 a 10.11.7.255) qualsiasi cosa più piccola non è valida
  3. 10.11.8.0/21 (10.11.8.0 a 10.11.15.255) anyt Hing più piccolo non è valido
  4. 10.11.16.0/20 (10.11.16.0 a 10.11.31.255) qualcosa di più piccolo non è valido
  5. 10.11.32.0/20 (10.11.32.0 a 10.11.47.255)/19 è valido, ma sarebbe andato troppo
  6. 10.11.48.0/22 ​​(10.11.48.0 a 10.11.51.255)/20 e/21 sono validi, ma sarebbe andare troppo lontano

Guardando a questo in binario, diventa evidente. Le maschere sono ANDed con la sottorete (qualsiasi posizione con uno zero nella subnet o nella maschera diventa uno zero, una posizione deve averne uno sia nella subnet che nella maschera per averne uno). Se tu E una sottorete e una maschera, e non è uguale alla sottorete, non è valida.

Tutti i calcoli degli indirizzi IP devono essere eseguiti in binario. La notazione decimale puntata va bene per la leggibilità umana, ma non deve essere utilizzata per provare a eseguire calcoli sugli indirizzi IP.

2

Mi piace molto questo problema, ho dato un'occhiata ieri sera e ho deciso di provarlo. A questo punto ho un proof of concept script script che funziona.

responsabilità:

  1. Questa è una prova di concetto solo
  2. I tipi di reinventato la ruota qui come non ho usato qualsiasi libreria TCP/IP
  3. non ha attuato input validation
  4. Questo codice potrebbe essere molto più veloce se scritto in un linguaggio di programmazione piuttosto che bash, sebbene per questo specifico intervallo di rete non sia così lento

Un altro aspetto degno di nota è che la mia comprensione:

IPv4 networks should have as short subnet-mask as possible.

è che dovremmo cercare da bit riservati collegare in rete fino al più grande cidr fornito, in questo caso .

OK, vediamo lo script in azione:

[[email protected] tmp]# time bash ip.sh 10.11.3.64/25 10.11.52.0/24 
10.11.3.128/25 
10.11.4.0/22 
10.11.8.0/21 
10.11.16.0/20 
10.11.32.0/20 
10.11.48.0/22 

real 0m48.376s 
user 0m6.174s 
sys  0m34.644s 

sotto il codice:

#! /bin/bash 

function split_octet { 
    sed -re "s/\./ /g" <<< "$1" 
} 

function dec2bin { 
    perl -e 'printf "%0'"$1"'b\n",'"$2"';' 
} 

function bin2dec { 
    perl -le 'print 0b'"$1"';' 
} 

function ip2bin { 
    str="" 
    for octet in $(split_octet $1); do 
     str="${str}$(dec2bin 8 $octet)" 
    done 
    echo "$str" 
} 

function bin2ip { 
    str="" 
    for octet in $(grep -Eo '.{8}' <<< $1); do 
     dec=$(bin2dec $octet) 
     str="${str}.${dec}" 
    done 
    echo "$str" | sed -re 's/^\.|\.$//g' 
} 

function ip2dec { 
    ip=$1 
    bin2dec $(ip2bin $ip) 
} 

function dec2ip { 
    dec=$1 
    bin2ip $(dec2bin 32 $dec) 
} 

function AND { 
    perl -e ' $a=0b'"$1"' & 0b'"$2"'; 
         printf "%032b\n",$a 
        ' 
} 

function OR { 
    perl -e ' $a=0b'"$1"' | 0b'"$2"'; 
         printf "%032b\n",$a 
        ' 
} 

function NOT { 
    perl -le ' $a= (~ 0b'"$1"') & 0xFFFFFFFF; 
          printf "%032b\n",$a 
        ' 
} 

function get_network { 
    ip=$1; mask=$2; 

    if [ -n "$ip" -a -n "$mask" ];then 
    echo $(bin2ip $(AND $(ip2bin $ip) $(ip2bin $mask))) 
     return 
    fi 

    grep -qP "\d+\.\d+\.\d+.\d+/\d+" <<< "$ip" 
    if [ "$?" == 0 ];then 
     ip=$(get_ip_from_cidr $1) 
     mask=$(get_mask_from_cidr $1) 
     echo $(bin2ip $(AND $(ip2bin $ip) $(ip2bin $mask))) 
    fi 
} 

function get_broadcast { 
    ip=$1; mask=$2; 

    if [ -n "$ip" -a -n "$mask" ];then 
     echo $(bin2ip $(OR $(ip2bin $ip) $(NOT $(ip2bin $mask)))) 
     return 
    fi 

    grep -qP "\d+\.\d+\.\d+.\d+/\d+" <<< "$ip" 
    if [ "$?" == 0 ];then 
     ip=$(get_ip_from_cidr $1) 
     mask=$(get_mask_from_cidr $1) 
     echo $(bin2ip $(OR $(ip2bin $ip) $(NOT $(ip2bin $mask)))) 
    fi 

} 

function get_ip_from_cidr { 
    awk -F/ '{print $1}' <<< "$1" 
} 

function get_mask_from_cidr { 
    mask=$(awk -F/ '{print $2}' <<< "$1") 
    mask=$(cidr $mask) 
    mask=$(bin2ip $mask) 
    echo $mask 
} 

function cidr { 
    perl -e ' 
         $n='"$1"'; 
         $diff=32-$n; 
         print "1"x$n . "0"x$diff; 
        ' 
} 


snet_cidr=$1 
enet_cidr=$2 

largest_cidr=$(echo -e "$snet_cidr\n$enet_cidr"| awk -F/ '{print $2}' | sort -rn | head -1) 

snet_dec=$(ip2dec $(get_ip_from_cidr $snet_cidr)) 
enet_dec=$(ip2dec $(get_ip_from_cidr $enet_cidr)) 

sbc_ip=$(get_broadcast $snet_cidr) 
ebc_ip=$(get_broadcast $enet_cidr) 

sbc_dec=$(ip2dec $sbc_ip) 
ebc_dec=$(ip2dec $ebc_ip) 

counter=$sbc_dec 

while [ $counter -lt $enet_dec ];do 
    tip=$(dec2ip $counter) 
    for cidr in $(seq 8 $largest_cidr) ; do 
     tnet_ip=$(get_network $tip/$cidr) 
     tnet_cidr=$tnet_ip/$cidr 
     tbc_ip=$(get_broadcast $tnet_cidr) 
     tnet_dec=$(ip2dec $(get_ip_from_cidr $tnet_cidr)) 
     tbc_dec=$(ip2dec $tbc_ip) 
     if [ $sbc_dec -lt $tnet_dec -a $enet_dec -gt $tbc_dec ];then 
      echo $tnet_cidr 
      counter=$tbc_dec 
      break 
     fi 
    done 
    let counter++ 
done 

Modifica E 'probabilmente una buona idea per spiegare quali siano tali variabili sono:

  1. snet_cidr: avvio netto in notazione Cidr
  2. enet_cidr: Rete fine a cidr
  3. snet_dec: net start in decimali
  4. enet_dec: netta di fine in decimali
  5. sbc_ip: Inizia trasmissione ip
  6. ebc_ip: fine trasmissione ip
  7. sbc_dec: inizio trasmissione ip
  8. ebc_dec: fine trasmissione ip

e dovunque si vede TNET o da confermare è al netto di temperatura, temperatura trasmissione, temperatura perché è insid e il ciclo.

Problemi correlati