コンピューターのprivateIPv4アドレスをプログラムで抽出する簡単な方法を探しています。
この質問 に似ていますが、プライベートIPに制限されています。
例として、次のコマンドでIPv4アドレスを抽出allできます。
ifconfig | grep 'inet addr' | cut -d ':' -f 2 | awk '{ print $1 }'
出力例:
6.11.71.78
10.0.2.15
127.0.0.1
同様に、プライベートアドレス空間でIPのみを取得したいと思います。したがって、同じ例を参照すると、出力は次のようになります。
10.0.2.15
プライベートIPスペース のすべては、常に3つのIPアドレスブロックのいずれかで始まります。
したがって、上記のタイプのIPアドレスに対してgrepを実行するだけです。
$ ifconfig | grep 'inet addr' | cut -d ':' -f 2 | awk '{ print $1 }' | \
grep -E '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.)'
192.168.1.20
私が使用しているgrep
は、正規表現を使用しています。この場合、次のパターンを探します。
さらに、これらのパターンのいずれかで始まる一致する数字のみが明示されています。アンカー(^
)がこの機能を提供しています。
grep
をテストするためだけに次の行をファイルに追加するとします。
$ cat afile
192.168.0.1
10.11.15.3
1.23.3.4
172.16.2.4
その後、次のようにテストできます。
$ cat afile | grep -E '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.)'
192.168.0.1
10.11.15.3
172.16.2.4
IPv4は、32ビットシステムが普及したときに作成されました。 IPv4のドット付き10進アドレスは32ビットの符号なし整数に格納でき、ビット単位の演算はネットワークハードウェアによって効率的に実行されます。 172.16.0.0/12 CIDRのビットマスクは、単一の左シフトから形成でき、単一のビット単位ANDを使用してアドレスに対してチェックできます。
RFC-1918で定義された3つの「プライベート」ネットワークアドレス範囲があります。
10.x.y.z/8
172.16+x.y.z/12
での16の隣接するネットワーク(20ビット、1M)アドレス範囲、ここでx in [0..15]
192.168.y.z/16
また、キャリアネットワークの細分化については、
100.64+x.y.z/10
、ここでx in [0..63]
リンクローカルアドレスの場合、
169.254.y.z/16
での単一ネットワーク(16ビット、64K)アドレス範囲ビット演算をサポートする言語を使用すると、ドット付き10進アドレスを整数に簡単に変換できます。
//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]
上記のアドレスに定数を定義したとします。
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
Ipv4アドレスがこれらのアドレスの1つであるかどうかの確認は簡単です。
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
16の異なる172.16.0.0/12ネットワークをチェックする代わりに、上記のビットマスクアプローチを使用して、ipv4アドレスがこれらのプライベート(NAT)ネットワークの1つに含まれているかどうかを直接チェックできます。 Shellまたはawkの代わりにPerl(pythonまたはRubyも機能))を選択し、単一のビット単位の操作を使用すると、作業が大幅に削減されます。
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;
};
住所をどのように分類しますか?
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";
}
};
Perlスクリプト内からifconfigを実行します。
$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); }
プライベートIPを表示
ip -o addr show | \
grep -v 'inet6' | \
grep -v 'scope Host' | \
awk '{print $4}' | \
cut -d '/' -f 1 | \
grep -E '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.)'
パブリックIPを表示
ip -o addr show | \
grep -v 'inet6' | \
grep -v 'scope Host' | \
awk '{print $4}' | \
cut -d '/' -f 1 | \
grep -vE '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.)'
出力(IPごとに1行)は、次のスクリプトでフィルタリングできます。
#!/bin/sh
PATTERN='^10\.' # 10.0.0.0/8
PATTERN+='|^192\.168\.' # 192.168.0.0/16
PATTERN+='|^169\.254\.' # not strictly private range, but link local
for i in $(seq 16 31) ; do # 172.16.0.0/12
PATTERN+="|^172\.$i\."
done
egrep "$PATTERN"
exit 0
使用例:
ifconfig | grep 'inet addr' | cut -d ':' -f 2 | awk '{ print $1 }' | ./filter_private_ips