...私の 5 セント:
私見の根底にある質問は、「IPアドレスがネットワークに属しているかどうかを確認する方法」です。
答えは単純なバイナリです: IP_address AND network_mask EQUALS network_address.
たとえば、IP アドレス 10.1.2.3 は、ネットマスク 255.0.0.0 のネットワーク 10.0.0.0 に属していますか? 10.1.2.3 & 255.0.0.0 は 10.0.0.0 なので、答えは「はい」です。
バイナリで見やすい:
00001010 00000001 00000010 00000011 ( 10.1.2.3) ip address
& 11111111 00000000 00000000 00000000 (255.0.0.0) network mask
= 00001010 00000000 00000000 00000000 ( 10.0.0.0) network address
必要なネットワークについて確認する必要があります(ループバック、リンクローカルなどを含むかどうか):
function _isPrivate($long_ip) {
return ( ($long_ip & 0xFF000000) === 0x0A000000 ) || //Private A network: 00001010 ....
( ($long_ip & 0xFFF00000) === 0xAC100000 ) || //Private B network: 10101100 0001....
( ($long_ip & 0xFFFF0000) === 0xC0A80000 ) || //Private C network: 11000000 10101000 ....
//Link-local and loopback are NOT private range, so the function in the question yield right results to "is in private range?". Seems it was not the desired behaviour... Those cases can also be checked:
( ($long_ip & 0xFFFF0000) === 0xA9FE0000 ) || //Link-local : 10101001 11111110 ....
( ($long_ip & 0xFFFF0000) === 0x7F000000 ) || //Loopback : 01111111 ....
//...and add all the fancy networks that you want...
( ($long_ip & 0xFFFFFF00) === 0xC0AF3000 ) || //Direct Delegation AS112 Service 192.175.48.0/24...
( ($long_ip & 0xF0000000) === 0xF0000000 ); //Reserved 240.0.0.0/4
}
興味深い点は、戻り値の否定です。返された値は、指定された IP がプライベート ネットワークにあることを実際には意味しませんが、否定は実際には、指定された IP が「パブリック IP アドレス」(共通/通常の IP アドレス) であることを意味します。
IPv6
同じことがIPv6でも機能します。「プライベート ネットワーク」アドレス (正式には「Unique-Local」、RFC 4193 ) は「fc00::/7」です。したがって、ip_address & 0xFE00.. === 0xFC00.. は「プライベート ネットワーク」です。
上記の回答を採用し、IANA からの最新情報を含める...
http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
http://www.iana.org/assignments/iana-ipv4-special-registry/iana -ipv4-special-registry.xhtml
...次のようなもう少し一般的な関数を作成できます。
function isPublicAddress($ip) {
// returns false on failure.
// negative if it's a private or special address (-4:IPv4, -16:IPv6)
// positive if it's a common IP public address (4:IPv4, 16:IPv6)
$networks = array(
'4' => array('0.0.0.0/8',
'10.0.0.0/8',
'100.64.0.0/10',
'127.0.0.0/8',
'169.254.0.0/16',
'172.16.0.0/12',
'192.0.0.0/24',
'192.0.0.0/29',
'192.0.0.8/32',
'192.0.0.9/32',
'192.0.0.170/32',
'192.0.0.170/32',
'192.0.2.0/24',
'192.31.196.0/24',
'192.52.193.0/24',
'192.88.99.0/24',
'192.168.0.0/16',
'192.175.48.0/24',
'198.18.0.0/15',
'198.51.100.0/24',
'203.0.113.0/24',
'240.0.0.0/4',
'255.255.255.255/32')
,
'16' => array('::1/128',
'::/128',
'::ffff:0:0/96',
'64:ff9b::/96',
'100::/64',
'2001::/23',
'2001::/32',
'2001:1::1/128',
'2001:2::/48',
'2001:3::/32',
'2001:4:112::/48',
'2001:5::/32',
'2001:10::/28',
'2001:20::/28',
'2001:db8::/32',
'2002::/16',
'2620:4f:8000::/48',
'fc00::/7',
'fe80::/10')
);
$ip = inet_pton($ip);
if( $ip === false ) return false;
$space='16';
if (strlen($ip) === 4) {
$space='4';
}
//Is the IP in a private or special range?
foreach($networks[$space] as $network) {
//split $network in address and mask
$parts=explode('/',$network);
$network_address = inet_pton($parts[0]);
$network_mask = inet_pton( _mask( $ip , $parts[1] ) );
if (($ip & $network_mask) === $network_address){
return -1*$space;
}
}
//Success!
return $space;
}
function _mask($ip,$nbits){
$mask='';
$nibble=array('0','8','C','E');
$f_s= $nbits >> 2 ;
if( $f_s > 0 ) $mask.=str_repeat('F',$f_s);
if( $nbits % 4 ) $mask.= $nibble[$nbits % 4];
if( strlen($ip) === 4 ){
if( strlen($mask) < 8 ) $mask.=str_repeat('0', 8 - strlen($mask) );
long2ip('0x'.$mask);
$mask=long2ip('0x'.$mask);
}else{
if( strlen($mask) < 32 ) $mask.=str_repeat('0', 32 - strlen($mask) );
$mask=rtrim(chunk_split($mask,4,':'),':');
}
return $mask;
}
私が今疑問に思っているのは、「IPv4 マップ アドレス」の IPv6 アドレスは、IPv4 の「通常の」IP アドレスであったとしても、IPv6 の「特別な」アドレスであるということです。::ffff:0:0/96 内の IPv4 私用ネットワークに一致するサブネットを「私的使用」と見なす必要がありますか?
最後のコメントを説明する編集:
IPv6 ネットワーク ::ffff:0:0/96 は、IPv4 アドレスごとに IPv6 アドレスにマップされます。これらの IPv6 アドレスは、IANA レジストリ (「特別目的」) の単一のセットにありますが、マップされた IPv4 アドレスは、IPv4 のあらゆる種類のセット (プライベート ネットワーク、ループバック、ブロードキャスト、パブリック...) にあります。アドレス」は常に「特別な IPv6 アドレス」です。IPv4 プライベート ネットワークに一致する ::ffff:0:0/96 の範囲の IPv6 アドレスを使用してネットワークをセットアップする場合... プライベート ネットワーク アドレスを使用していますか?