プログラムで抽出する簡単な方法を探しています。プライベートコンピュータのIPv4アドレス。
似たようなものこの問題ただし、プライベートIP専用です。
たとえば、次のものを抽出できます。みんな次のコマンドを使用します。
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
答え1
そこには何もありません。プライベートIPスペース常に3つのIPアドレスブロックのうちの1つから始めてください。
- 24ビットブロック - 10.XXX
- 20ビットブロック - 172.16.XX - 172.31.XX
- 16ビットブロック - 192.168.XX
したがって、上記のタイプの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
使用するものは正規表現を使用します。この場合、私たちは次のパターンを探しています。
- 192.168
- 10.
- 172.1[6789]。
- 172.2[0-9]。
- 172.3[01]。
また、これらのパターンの1つで始まる数字だけが明示的に一致します。 Anchor(^
)は私たちにこれらの能力を提供しています。
その他の例
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
答え2
プライベート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]\.)'
答え3
IPv4は、32ビットシステムが広く普及していた時期に作成されました。 IPv4ドットで区切られた10進アドレスは、32ビット符号なし整数で格納でき、ネットワークハードウェアはビット単位の操作を効率的に実行できます。 172.16.0.0/12 CIDRのビットマスクは、シングル左シフトとシングルビットANDを使用したアドレス解決で構成できます。
RFC-1918は3つの「プライベート」ネットワークアドレス範囲を定義します。
- CIDR / 8、(A)単一の大規模ネットワーク、(24ビット、16M)アドレス範囲
10.x.y.z/8
- CIDR / 12、(B)16個の連続ネットワーク(20ビット、1M)アドレス範囲
172.16+x.y.z/12
、x in [0..15]
- CIDR / 16、(C)256連続ネットワーク(16ビット、64K)アドレス範囲
192.168.y.z/16
また、事業者網のセグメンテーションのため、
- CIDR / 10、(A)単一の大規模ネットワーク、(24ビット、16M)アドレス範囲
100.64+x.y.z/10
、x in [0..63]
リンク - ローカルアドレスの場合
- CIDR/16, (B) 単一ネットワーク (16 ビット, 64K) アドレス範囲
169.254.y.z/16
ビット操作をサポートする言語を使用すると、ドットで区切られた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アドレスが次のいずれかであることを確認するのは簡単です。
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つに属しているかどうかを直接確認できます。シェルや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); }
答え4
次のスクリプトを使用して出力をフィルタリングできます(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