O IPv4 foi criado no momento em que os sistemas de 32 bits eram predominantes. O endereço decimal pontilhado IPv4 pode ser armazenado em um inteiro não assinado de 32 bits e as operações bit a bit são desempenhadas com eficiência pelo hardware de rede. Uma máscara de bits para o CIDR 172.16.0.0/12 pode ser formada a partir de um único deslocamento à esquerda e verificada em relação a um endereço com um único bit a bit e.
Existem três intervalos de endereços de rede 'privados' definidos pelo RFC-1918.
- CIDR / 8, (A) rede grande única, intervalo de endereços (24 bits, 16M) em
10.x.y.z/8
- CIDR / 12, (B) 16 intervalos de endereços de redes contíguas (20 bits, 1M) em
172.16+x.y.z/12
, em que x in [0..15]
- CIDR / 16, (C) 256 intervalos de endereços de redes contíguas (16 bits, 64K) em
192.168.y.z/16
Além disso, para subdivisão da rede de operadoras,
- CIDR / 10, (A) rede grande e única, intervalo de endereços (24 bits, 16M) em
100.64+x.y.z/10
, em que x in [0..63]
E para endereços locais de links,
- CIDR / 16, (B) um único intervalo de endereços de rede (16 bits, 64K) em
169.254.y.z/16
Com uma linguagem que suporta operações bit a bit, você pode converter um endereço decimal pontuado em um inteiro facilmente,
//assume x[0],x[1],x[2],x[3] are the parts of a dotted ip address
unsigned int ipv4 = (( (( (x[0]<<8) |x[1])<<8) |x[2])<<8) |x[3]
Suponha que você tenha definido constantes para os endereços listados acima,
CIDR8 = (( (( (10<<8) |0xff)<<8) |0xff)<<8) |0xff
CIDR12 = (( (( (172<<8) |16 |0xf)<<8) |0xff)<<8) |0xff
CIDR16 = (( (( (192<<8) |168)<<8) |0xff)<<8) |0xff
CIDR10 = (( (( (100<<8) |64 |0x3f)<<8) |0xff)<<8) |0xff
CIDRLL = (( (( (169<<8) |254)<<8) |0xff)<<8) |0xff
Verificar se seu endereço IPv4 é um desses endereços é simples,
ipv4 == (ipv4 & CIDR8) //10.0.0.0/8
ipv4 == (ipv4 & CIDR12) //172.16.0.0/12
ipv4 == (ipv4 & CIDR16) //192.168.0.0/16
ipv4 == (ipv4 & CIDR10) //100.64.0.0/10
ipv4 == (ipv4 & CIDRLL) //169.254.0.0/16
Em vez de verificar 16 diferentes redes 172.16.0.0/12, pode-se usar a abordagem de máscara de bits acima para verificar diretamente se um endereço ipv4 faz parte de uma dessas redes privadas (NAT). Escolhendo perl (python ou ruby também funcionam), em vez de shell ou awk, e usando um único bit-wise e a operação reduz consideravelmente o trabalho.
sub isprivate
{
my($inet) = @_;
if( $inet =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/ ) {
if( $1==10 ) { return 10; }
if( $1==172 && (($2 & 0x1f) == $2) ) { return 172; }
if( $1==192 && ($2==168) ) { return 192; }
}
return 0;
};
sub iscarrier
{
my($inet) = @_;
if( $inet =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/ ) {
if( $1==100 && (($2 & 0x7f) == $2) ) { return 100; }
}
return 0;
};
sub islinklocal
{
my($inet) = @_;
if( $inet =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/ ) {
if( $1==169 && ($2==254) ) { return 169; }
}
return 0;
};
Como você deseja classificar os endereços?
sub ipaddr
{
my($inet) = @_;
{
if( isprivate($inet)>0 ) { $kind = "private"; }
elsif( isloop($inet)>0 ) { $kind = "loopback"; }
elsif( iscarrier($inet)>0 ) { $kind = "carrier"; }
elsif( islinklocal($inet)>0 ) { $kind = "linklocal"; }
else { $kind = ""; }
print "$iface: $inet $netmask $broadcast ($flagsdesc) $kind\n";
}
};
Execute o ifconfig dentro de um script perl,
$found = 0;
open($fh,"/sbin/ifconfig|");
while($line=<$fh>)
{
chomp($line); $line =~ s/^\s+//;
if( $line =~ /(\w+):\s+flags=(\d+)\s*\<(.*)\>\s+mtu\s+(\d+)\b/ ) {
if( $found ) { ipaddr($inet); }
$found = 1;
($iface,$flags,$flagsdesc,$mtu) = ($1,$2,$3,$4);
}
if( $line =~ /inet\s+(\d+\.\d+\.\d+\.\d+)\b/ ) {
($inet,$netmask,$broadcast) = ($1,"","");
if( $line =~ /netmask\s+([\d+\.]+)\b/ ) { ($netmask) = ($1); }
if( $line =~ /broadcast\s+([\d\.]+)\b/ ) { ($broadcast) = ($1); }
}
}
if( $found ) { ipaddr($inet); }