programing

CIDR 서브넷에 IP 주소가 포함되어 있는지 확인합니다.

linuxpc 2023. 8. 4. 22:44
반응형

CIDR 서브넷에 IP 주소가 포함되어 있는지 확인합니다.

주어진 IP4 닷이 있는 쿼드 IP를 CIDR 표기법 마스크에 빠르게/간단하게 매칭할 수 있는 방법을 찾고 있습니다.

IP 범위와 일치하는지 확인해야 하는 IP가 여러 개 있습니다.

예:

$ips = array('10.2.1.100', '10.2.1.101', '10.5.1.100', '1.2.3.4');

foreach ($ips as $IP) {
    if (cidr_match($IP, '10.2.0.0/16') == true) {
        print "you're in the 10.2 subnet\n"; 
    }
}

을 무슨일까 입니? ▁what까니 ▁would무?cidr_match()처럼 보이십니까?

간단할 필요는 없지만, 빠른 것이 좋을 것 같습니다.기본 제공/공통 기능만 사용하는 모든 것은 보너스입니다(한 사람이 이 기능을 수행하는 배에서 무언가를 보여주도록 할 가능성이 높지만 내 코드가 배포된 곳에 배나 해당 패키지가 설치되어 있는지에 의존할 수는 없습니다).

IPv4만 사용하는 경우:

  • 사용하다ip2long()IP와 서브넷 범위를 긴 정수로 변환합니다.
  • /xx를 서브넷 마스크로 변환
  • 'and'(예: ip & mask)를 조금 실행하고 'result = subnet'을 확인합니다.

다음과 같은 것이 작동해야 합니다.

function cidr_match($ip, $range)
{
    list ($subnet, $bits) = explode('/', $range);
    if ($bits === null) {
        $bits = 32;
    }
    $ip = ip2long($ip);
    $subnet = ip2long($subnet);
    $mask = -1 << (32 - $bits);
    $subnet &= $mask; # nb: in case the supplied subnet wasn't correctly aligned
    return ($ip & $mask) == $subnet;
}

비슷한 상황에서 저는 symphony/http-foundation을 사용하게 되었습니다.

이 패키지를 사용할 때 코드는 다음과 같습니다.

$ips = array('10.2.1.100', '10.2.1.101', '10.5.1.100', '1.2.3.4');

foreach($ips as $IP) {
    if (\Symfony\Component\HttpFoundation\IpUtils::checkIp($IP, '10.2.0.0/16')) {
        print "you're in the 10.2 subnet\n";
    }
}

또한 IPv6도 처리합니다.

링크: https://packagist.org/packages/symfony/http-foundation

저는 PHP 5.2 이후에 이러한 많은 방법들이 깨지는 것을 발견했습니다.그러나 다음 솔루션은 버전 5.2 이상에서 작동합니다.

function cidr_match($ip, $cidr)
{
    list($subnet, $mask) = explode('/', $cidr);

    if ((ip2long($ip) & ~((1 << (32 - $mask)) - 1) ) == ip2long($subnet))
    { 
        return true;
    }

    return false;
}

예제 결과

cidr_match ("1.2.3.4", "0.0.0/0": truecidr_match("127.0.0.1", "127.0.0.1/32"): truecidr_match("127.0.0.1", "127.0.0.2/32"): false

출처 http://www.php.net/manual/en/function.ip2long.php#82397 .

일부 기능이 변경되었습니다.

  • 폭발하여 갈라진.

function cidr_match($ip, $range)
{
    list ($subnet, $bits) = explode('/', $range);
    $ip = ip2long($ip);
    $subnet = ip2long($subnet);
    $mask = -1 << (32 - $bits);
    $subnet &= $mask; 
    return ($ip & $mask) == $subnet;
}

여기 빠른 64비트 기능이 하나 있는데, 필요 없는 리턴 라인에 댓글을 달아주세요.유효한 CIDR 라우팅 접두사가 있거나 없는 유효한 Ipv4 수락(: 63.161.156.0/24 또는 63.161.156.0)

<?php
function cidr2range($ipv4){
if ($ip=strpos($ipv4,'/'))
{$n_ip=(1<<(32-substr($ipv4,1+$ip)))-1;   $ip_dec=ip2long(substr($ipv4,0,$ip)); }
else
{$n_ip=0;                                   $ip_dec=ip2long($ipv4);             }
$ip_min=$ip_dec&~$n_ip;
$ip_max=$ip_min+$n_ip;
#Array(2) of Decimal Values Range
return [$ip_min,$ip_max];
#Array(2) of Ipv4 Human Readable Range
return [long2ip($ip_min),long2ip($ip_max)];
#Array(2) of Ipv4 and Subnet Range
return [long2ip($ip_min),long2ip(~$n_ip)];
#Array(2) of Ipv4 and Wildcard Bits
return [long2ip($ip_min),long2ip($n_ip)];
#Integer Number of Ipv4 in Range
return ++$n_ip;
}

지정된 ipv4가 지정된 CIDR과 일치하는지 빠르게 확인하려면 이 예와 같이 인라인으로 수행할 수 있습니다.

<?php
$given_cidr='55.55.55.0/24';
$given_ipv4='55.55.55.55';
if(($range=cidr2range($given_cidr)) &&
($check=ip2long($given_ipv4))!==false &&
$check>=$range[0] && $check<=$range[1])
{
echo 'Yes, '.$given_ipv4.' is included in '.$given_cidr;
}
else
{
echo 'No, '.$given_ipv4.' is not included in '.$given_cidr;
}

지정된 IP(CIDR 라우팅 접두사 사용 여부와 상관없이)의 어레이로 전체 범위를 가져오려면 다음 코드를 사용할 수 있지만, 예를 들어 25.25.25/16은 65536개의 요소가 포함된 어레이를 반환하고 더 작은 라우팅 접두사를 사용하여 쉽게 메모리가 부족해질 수 있기 때문에 주의해야 합니다.

<?php
$result=cidr2range($ipv4);
for($ip_dec=$result[0];$ip_dec<=$result[1];$ip_dec++)
$full_range[$ip_dec]=long2ip($ip_dec);
print_r($full_range);

지정된 ipv4가 지정된 IP 어레이(CIDR 라우팅 접두사 사용 또는 사용 안 함)와 일치하는지 빠른 확인

<?php
#This code is checking if a given ip belongs to googlebot
$given_ipv4='74.125.61.208';
$given_cidr_array=['108.59.93.43/32','108.59.93.40/31','108.59.93.44/30','108.59.93.32/29','108.59.93.48/28','108.59.93.0/27','108.59.93.64/26','108.59.93.192/26','108.59.92.192/27','108.59.92.128/26','108.59.92.96/27','108.59.92.0/27','108.59.94.208/29','108.59.94.192/28','108.59.94.240/28','108.59.94.128/26','108.59.94.16/29','108.59.94.0/28','108.59.94.32/27','108.59.94.64/26','108.59.95.0/24','108.59.88.0/22','108.59.81.0/27','108.59.80.0/24','108.59.82.0/23','108.59.84.0/22','108.170.217.128/28','108.170.217.160/27','108.170.217.192/26','108.170.217.0/25','108.170.216.0/24','108.170.218.0/23','108.170.220.0/22','108.170.208.0/21','108.170.192.0/20','108.170.224.0/19','108.177.0.0/17','104.132.0.0/14','104.154.0.0/15','104.196.0.0/14','107.167.160.0/19','107.178.192.0/18','125.17.82.112/30','125.16.7.72/30','74.125.0.0/16','72.14.192.0/18','77.109.131.208/28','77.67.50.32/27','66.102.0.0/20','66.227.77.144/29','66.249.64.0/19','67.148.177.136/29','64.124.98.104/29','64.71.148.240/29','64.68.64.64/26','64.68.80.0/20','64.41.221.192/28','64.41.146.208/28','64.9.224.0/19','64.233.160.0/19','65.171.1.144/28','65.170.13.0/28','65.167.144.64/28','65.220.13.0/24','65.216.183.0/24','70.32.132.0/23','70.32.128.0/22','70.32.136.0/21','70.32.144.0/20','85.182.250.128/26','85.182.250.0/25','80.239.168.192/26','80.149.20.0/25','61.246.224.136/30','61.246.190.124/30','63.237.119.112/29','63.226.245.56/29','63.158.137.224/29','63.166.17.128/25','63.161.156.0/24','63.88.22.0/23','41.206.188.128/26','12.234.149.240/29','12.216.80.0/24','8.34.217.24/29','8.34.217.0/28','8.34.217.32/27','8.34.217.64/26','8.34.217.128/25','8.34.216.0/24','8.34.218.0/23','8.34.220.0/22','8.34.208.128/29','8.34.208.144/28','8.34.208.160/27','8.34.208.192/26','8.34.208.0/25','8.34.209.0/24','8.34.210.0/23','8.34.212.0/22','8.35.195.128/28','8.35.195.160/27','8.35.195.192/26','8.35.195.0/25','8.35.194.0/24','8.35.192.0/23','8.35.196.0/22','8.35.200.0/21','8.8.8.0/24','8.8.4.0/24','8.6.48.0/21','4.3.2.0/24','23.236.48.0/20','23.251.128.0/19','216.239.32.0/19','216.252.220.0/22','216.136.145.128/27','216.33.229.160/29','216.33.229.144/29','216.34.7.176/28','216.58.192.0/19','216.109.75.80/28','216.74.130.48/28','216.74.153.0/27','217.118.234.96/28','208.46.199.160/29','208.44.48.240/29','208.21.209.0/28','208.184.125.240/28','209.185.108.128/25','209.85.128.0/17','213.200.103.128/26','213.200.99.192/26','213.155.151.128/26','199.192.112.224/29','199.192.112.192/27','199.192.112.128/26','199.192.112.0/25','199.192.113.176/28','199.192.113.128/27','199.192.113.192/26','199.192.113.0/25','199.192.115.80/28','199.192.115.96/27','199.192.115.0/28','199.192.115.128/25','199.192.114.192/26','199.192.114.0/25','199.223.232.0/21','198.108.100.192/28','195.16.45.144/29','192.104.160.0/23','192.158.28.0/22','192.178.0.0/15','206.160.135.240/28','207.223.160.0/20','203.222.167.144/28','173.255.125.72/29','173.255.125.80/28','173.255.125.96/27','173.255.125.0/27','173.255.125.128/25','173.255.124.240/29','173.255.124.232/29','173.255.124.192/27','173.255.124.128/29','173.255.124.144/28','173.255.124.160/27','173.255.124.48/29','173.255.124.32/28','173.255.124.0/27','173.255.124.64/26','173.255.126.0/23','173.255.122.128/26','173.255.122.64/26','173.255.123.0/24','173.255.121.128/26','173.255.121.0/25','173.255.120.0/24','173.255.117.32/27','173.255.117.64/26','173.255.117.128/25','173.255.116.192/27','173.255.116.128/26','173.255.116.0/25','173.255.118.0/23','173.255.112.0/22','173.194.0.0/16','172.102.8.0/21','172.253.0.0/16','172.217.0.0/16','162.216.148.0/22','162.222.176.0/21','180.87.33.64/26','128.177.109.0/26','128.177.119.128/25','128.177.163.0/25','130.211.0.0/16','142.250.0.0/15','146.148.0.0/17'];
echo '<pre>';
$in_range=false;
if (($given_ipv4_dec=ip2long($given_ipv4))!==false)
{
foreach($given_cidr_array as $given_cidr){
if(($range=cidr2range($given_cidr)) &&
$given_ipv4_dec>=$range[0] && $given_ipv4_dec<=$range[1])
{
$in_range=true;
echo $given_ipv4.' matched '.$given_cidr.' ('.join(array_map('long2ip',$range),' - ').")\n";
}
}
}
echo $given_ipv4.' is probably'.($in_range?'':' not').' a Googlebot IP';

빠르게 실행하려면 함수가 입력을 확인하지 않지만 공식적으로 다음 정규식과 일치하는 문자열이어야 합니다.

#^(?:((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))\.((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))\.((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))\.((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))(?:/((?:(?:0)|(?:3[0-2])|(?:[1-2]?[0-9]))))?)$#

기능을 사용하기 전에 입력을 확인하려는 경우

<?php
if (is_string($ipv4) && preg_match('#^(?:((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))\.((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))\.((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))\.((?:0)|(?:2(?:(?:[0-4][0-9])|(?:5[0-5])))|(?:1?[0-9]{1,2}))(?:/((?:(?:0)|(?:3[0-2])|(?:[1-2]?[0-9]))))?)$#',$ipv4))
{
#This is a valid ipv4 with or without CIDR Routing Prefix
$result=cidr2range($ipv4);
print_r($result);
}

그렇다면 당신의 질문에 대한 공식적인 대답은 다음과 같습니다.

<?php
#Requiring cidr2range shown above function
function cidr_match($mixed_ip,$mixed_cidr){
if (!is_array($mixed_ip)){
$string_mode=true;
$mixed_ip=[$mixed_ip=>0];
}
else $mixed_ip=array_fill_keys($mixed_ip,0);
if (!is_array($mixed_cidr)) $mixed_cidr=[$mixed_cidr];
foreach($mixed_ip   as $ip => &$result)
foreach($mixed_cidr as $cidr)
{
if(($range=cidr2range($cidr)) &&
($check=ip2long($ip))!==false &&
$check>=$range[0] && $check<=$range[1]){
$result=$cidr;
break;
}
}
$mixed_ip=array_filter($mixed_ip);
return $string_mode?($mixed_ip?true:false):$mixed_ip;
}

print '<pre>';

#Your example
$ips = array('10.2.1.100', '10.2.1.101', '10.5.1.100', '1.2.3.4');

foreach ($ips as $IP) {
    if (cidr_match($IP, '10.2.0.0/16') == true) {
        print "you're in the 10.2 subnet\n"; 
    }
}


#Also working with IP array and/or CIDR array
#If IP array is given then return an array containing IP (keys) matching CIDR (values)
$result=cidr_match($ips,['20.2.0.0/16','10.2.0.0/15']);
foreach($result as $ip => $cidr){
print "$ip is in the $cidr subnet\n"; 
}

다음 예제를 사용하여 자체 함수를 컴파일할 수 있습니다. 이 몇 줄이 도움이 되었기를 바랍니다.

제 기술은 서브넷과 마스크를 사용하여 비트 대 비트 매칭을 사용합니다.

function cidr_match($ip, $range){
    list ($subnet, $bits) = explode('/', $range);
    $ip = substr(IP2bin($ip),0,$bits) ;
    $subnet = substr(IP2Bin($subnet),0,$bits) ;
    return ($ip == $subnet) ;
}

function IP2Bin($ip){
    $ipbin = '';
    $ips = explode(".",$ip) ;
    foreach ($ips as $iptmp){
        $ipbin .= sprintf("%08b",$iptmp) ;
    }
    return $ipbin ;
}

또한 IP를 CIDR 마스크에 대해 테스트해야 했습니다.나는 완벽하게 작동하는 훌륭한 설명과 소스 코드를 가진 웹사이트를 찾았습니다.

웹사이트 http://pgregg.com/blog/2009/04/php-algorithms-determining-if-an-ip-is-within-a-specific-range/

웹사이트가 언젠가는 존재하지 않을 수 있기 때문에, 여기 코드가 있습니다.

<?php

/*
 * ip_in_range.php - Function to determine if an IP is located in a
 *                   specific range as specified via several alternative
 *                   formats.
 *
 * Network ranges can be specified as:
 * 1. Wildcard format:     1.2.3.*
 * 2. CIDR format:         1.2.3/24  OR  1.2.3.4/255.255.255.0
 * 3. Start-End IP format: 1.2.3.0-1.2.3.255
 *
 * Return value BOOLEAN : ip_in_range($ip, $range);
 *
 * Copyright 2008: Paul Gregg <pgregg@pgregg.com>
 * 10 January 2008
 * Version: 1.2
 *
 * Source website: http://www.pgregg.com/projects/php/ip_in_range/
 * Version 1.2
 *
 * This software is Donationware - if you feel you have benefited from
 * the use of this tool then please consider a donation. The value of
 * which is entirely left up to your discretion.
 * http://www.pgregg.com/donate/
 *
 * Please do not remove this header, or source attibution from this file.
 */


// decbin32
// In order to simplify working with IP addresses (in binary) and their
// netmasks, it is easier to ensure that the binary strings are padded
// with zeros out to 32 characters - IP addresses are 32 bit numbers
Function decbin32 ($dec) {
  return str_pad(decbin($dec), 32, '0', STR_PAD_LEFT);
}

// ip_in_range
// This function takes 2 arguments, an IP address and a "range" in several
// different formats.
// Network ranges can be specified as:
// 1. Wildcard format:     1.2.3.*
// 2. CIDR format:         1.2.3/24  OR  1.2.3.4/255.255.255.0
// 3. Start-End IP format: 1.2.3.0-1.2.3.255
// The function will return true if the supplied IP is within the range.
// Note little validation is done on the range inputs - it expects you to
// use one of the above 3 formats.
Function ip_in_range($ip, $range) {
  if (strpos($range, '/') !== false) {
    // $range is in IP/NETMASK format
    list($range, $netmask) = explode('/', $range, 2);
    if (strpos($netmask, '.') !== false) {
      // $netmask is a 255.255.0.0 format
      $netmask = str_replace('*', '0', $netmask);
      $netmask_dec = ip2long($netmask);
      return ( (ip2long($ip) & $netmask_dec) == (ip2long($range) & $netmask_dec) );
    } else {
      // $netmask is a CIDR size block
      // fix the range argument
      $x = explode('.', $range);
      while(count($x)<4) $x[] = '0';
      list($a,$b,$c,$d) = $x;
      $range = sprintf("%u.%u.%u.%u", empty($a)?'0':$a, empty($b)?'0':$b,empty($c)?'0':$c,empty($d)?'0':$d);
      $range_dec = ip2long($range);
      $ip_dec = ip2long($ip);

      # Strategy 1 - Create the netmask with 'netmask' 1s and then fill it to 32 with 0s
      #$netmask_dec = bindec(str_pad('', $netmask, '1') . str_pad('', 32-$netmask, '0'));

      # Strategy 2 - Use math to create it
      $wildcard_dec = pow(2, (32-$netmask)) - 1;
      $netmask_dec = ~ $wildcard_dec;

      return (($ip_dec & $netmask_dec) == ($range_dec & $netmask_dec));
    }
  } else {
    // range might be 255.255.*.* or 1.2.3.0-1.2.3.255
    if (strpos($range, '*') !==false) { // a.b.*.* format
      // Just convert to A-B format by setting * to 0 for A and 255 for B
      $lower = str_replace('*', '0', $range);
      $upper = str_replace('*', '255', $range);
      $range = "$lower-$upper";
    }

    if (strpos($range, '-')!==false) { // A-B format
      list($lower, $upper) = explode('-', $range, 2);
      $lower_dec = (float)sprintf("%u",ip2long($lower));
      $upper_dec = (float)sprintf("%u",ip2long($upper));
      $ip_dec = (float)sprintf("%u",ip2long($ip));
      return ( ($ip_dec>=$lower_dec) && ($ip_dec<=$upper_dec) );
    }

    echo 'Range argument is not in 1.2.3.4/24 or 1.2.3.4/255.255.255.0 format';
    return false;
  }

}
?>

(저는 이것을 개발하지 않았습니다; 이것은 Paul Gregg에 의해 개발되었습니다. http://pgregg.com/)

최근에 IP 주소를 CIDR 마스크와 일치시켜야 했는데 이 기사를 보게 되었습니다.아래는 위의 아이디어에 기반한 약간 다른 접근 방식이며 CIDR 입력에 대한 확인을 포함합니다.잘못된 CIDR 형식이 제출되면 함수가 false를 반환합니다.

저는 테스트를 거친 턴키 기능이 필요한 사람들을 위해 이 솔루션을 게시했습니다.

/**
 * Validates subnet specified by CIDR notation.of the form IP address followed by 
 * a '/' character and a decimal number specifying the length, in bits, of the subnet
 * mask or routing prefix (number from 0 to 32).
 *
 * @param $ip - IP address to check
 * @param $cidr - IP address range in CIDR notation for check
 * @return bool - true match found otherwise false
 */
function cidr_match($ip, $cidr) {
    $outcome = false;
    $pattern = '/^(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5])\/(\d{1}|[0-2]{1}\d{1}|3[0-2])$/';
    if (preg_match($pattern, $cidr)){
        list($subnet, $mask) = explode('/', $cidr);
        if (ip2long($ip) >> (32 - $mask) == ip2long($subnet) >> (32 - $mask)) {
            $outcome = true;
        }
    }
    return $outcome;
}

테스트 데이터는 아래 이미지에 표시됩니다.

Test Results IP Checks

function cidr_match($ipStr, $cidrStr) {
  $ip = ip2long($ipStr);
  $cidrArr = split('/',$cidrStr);
  $maskIP = ip2long($cidrArr[0]);
  $maskBits = 32 - $cidrArr[1];
  return (($ip>>$maskBits) == ($maskIP>>$maskBits));
}

참고로 알니탁의 대답은 32/64비트로 작동합니다.

다음은 모든 곳에서 얻을 수 있는 국가 IP 목록을 기반으로 한 신속한 스팸 방지를 위해 요리된 버전입니다. 국가 IP 목록 또는 국가 IP 블록에 대한 구글(여기에 하나를 제공해야 합니다. 해당 사이트 페이지 탐색에서 찾기가 정말 어렵습니다.국가 ip 블록 생성기)

$cidrs 문자열에 cidrs 목록을 복사하여 붙여넣습니다.그리고 이 코드를 html 페이지 바로 앞에, 아마도 머리글에 넣으십시오.php 파일.

국가별 페이지 템플릿에서 광고 감지 사용을 필터링하는 데도 사용할 수 있습니다.

이것은 한밤중의 긴급한 해결책일 뿐입니다.때때로 어제 고객을 위해 이런 것을 빨리 생각해내야 할 때가 있습니다.

//++++++++++++++++++++++
//COUNTRY SPAM PROTECTOR
//speed: ~5ms @ 2000 cidrs
//comments start with #
//++++++++++++++++++++++
$cidrs=
'
#yourcountry
1.3.4.5/21
#mycountry
6.7.8.9/20
';
//$cidrs.="\n".'123.12.12.12/32';//test, your ip
$cidrs_ar=preg_split('/\s+/',$cidrs,-1,PREG_SPLIT_NO_EMPTY);
$ip=@$_SERVER['REMOTE_ADDR'];
$iplong=ip2long($ip);
//var_export($cidrs_ar);var_export($ip);var_export($iplong);
if($iplong)
  foreach($cidrs_ar as $cidr)
    {
    $ar=explode ('/', $cidr);
    $netiplong=ip2long($ar[0]);
    if($netiplong===false) continue;
    $mask=intval(@$ar[1]);
    if(!$mask) continue;
    $bitmask=-1 <<(32-$mask);
    if(($iplong & $bitmask) == ($netiplong & $bitmask))
        {
        header('Location: http://www.someotherwebsite.com/',true,303);
        exit;
        }
    }

Net_도 사용할 수 있습니다.IPv4 PEAR 라이브러리.

function cidr_match($ip, $net){
  include_once("Net/IPv4.php");
  $objIP = new Net_IPv4();
  return $objIP->ipInNetwork($ip, $net);
}

아마도 그것은 누군가에게 유용할 것입니다.

비트 마스크를 IP 마스크로 변환:

// convert 12 => 255.240.0.0
// ip2long('255.255.255.255') == -1
$ip = long2ip((-1 << (32 - $bit)) & -1);

IP 마스크를 비트 마스크로 변환:

// convert 255.240.0.0 => 12

// is valid IP
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) {
    throw new \InvalidArgumentException(sprintf('Invalid IP "%s".', $ip));
}

// convert decimal to binary
$mask = '';
foreach (explode('.', $ip) as $octet) {
    $mask .= str_pad(decbin($octet), 8, '0', STR_PAD_LEFT);
}

// check mask
if (strpos('01', $mask) !== false) {
    // valid   11111111111111111111111100000000 -> 255.255.255.0
    // invalid 11111111111111111111111100000001 -> 255.255.255.1
    throw new \InvalidArgumentException(sprintf('IP mask "%s" is not valid.', $ip));
}

$bit = substr_count($mask, '1'); // bit mask

제 몇 줄을 봐주셨으면 합니다.사람들이 나보다 먼저 제안한 사례들은 효과가 없는 것 같습니다.제가 이해하는 한 가지 이유는 CIDR 마스크 비트는 이진수이기 때문에 비트 이동은 이진수에서 수행되어야 한다는 것입니다.긴 IP를 바이너리로 변환하려고 했지만 최대 바이너리 수 제한에 부딪혔습니다.좋아요, 여기 내 몇 마디...당신의 의견을 기다리겠습니다.

function cidr_match($ipStr, $cidrStr) {

$ipStr = explode('.', $ipStr);
foreach ($ipStr as $key => $val) {
    $ipStr[$key] = str_pad(decbin($val), 8, '0', STR_PAD_LEFT);
    }
$ip = '';
foreach ($ipStr as $binval) {
    $ip = $ip . $binval;
    }

$cidrArr = explode('/',$cidrStr);

$maskIP = explode('.', $cidrArr[0]);
foreach ($maskIP as $key => $val) {
    $maskIP[$key] = str_pad(decbin($val), 8, '0', STR_PAD_LEFT);
    }
$maskIP = '';
foreach ($ipStr as $binval) {
    $maskIP = $maskIP . $binval;
    }
$maskBits = 32 - $cidrArr[1];
return (($ip>>$maskBits) == ($maskIP>>$maskBits));  
}

저는 결국 @A.R.를 사용하게 되었습니다.비트 투 비트 매칭 서브넷 및 마스크가 포함된 NasirQureshi의 솔루션은 "2006:"과 같은 일부 이상한 경우를 효과적으로 처리하는 다른 솔루션이 et_pton에 언급되지 않았기 때문에 IPv6도 처리하도록 확장했습니다.BCAA:64FF:: 복잡할 수 있는 "." 또는 ":"로 나누는 대신:104.121.140.212"!

function cidr_match($ip, $range){
  list($subnet, $bits) = explode('/', $range);

  //add 128-32=96 for IPv4 range bits
  if(filter_var($subnet, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)){ $bits += 96; }

  // compare bits of the 2 strings of 128 0 & 1 like 11000010101100
  $subnet = substr( IP2Bin($subnet), 0, $bits);
  $ip = substr( IP2Bin($ip), 0, $bits);

  return $ip == $subnet;
}
function IP2Bin($ip){
  $IPbin = ''; $bin = inet_pton($ip);
  if($bin===false){return str_repeat('0',128);} //in case of invalid IP

  //split into 4-char hexadecimal parts (just to avoid issues with hexdec for larger hex, but you can choose more)
  $arr = str_split( current( unpack('H*', $bin) ) , 4 );

  //each char is 4 bits so 4 chars == 16 bits
  foreach($arr as $p){ $IPbin .= sprintf("%016b", hexdec($p) ); }

  //always get 128 chars string of 1s & 0s
  return str_pad( $IPbin, 128, '0', STR_PAD_LEFT );
}

비교는 항상 "128비트"(1281s 및 0s라고도 함)와 함께 수행되기 때문에 IP와 범위가 모두 동일한 유형(IPv4 또는 IPv6)인지 여부와 유형(IPv4 대 IPv6 또는 그 반대)이 서로 다른 경우에도 작동합니다.

최근에 IP 주소를 네트워크 목록과 일치시켜야 했고 이 질문을 발견했습니다.아래는 이전에 게시된 모든 아이디어와 주소, 서브넷 및 마스크의 IPv6 지원 및 검증을 통합한 변형입니다.잘못된 CIDR 형식이 제출되거나 IPv4 주소를 IPv6 네트워크와 일치시키려고 시도하거나 그 반대의 경우 이 함수는 false를 반환합니다.

/*
  Checks if $ip belongs to $cidr.
  cidr_match('1.2.3.4', '1.2.3.5/24') == true
  cidr_match('::1.2.3.4', '::1.2.3.0/125') == true
  cidr_match('::1.2.3.4', '::1.2.3.0/126') == false
*/
function cidr_match($ip, $cidr)
{
    if (!filter_var($ip, FILTER_VALIDATE_IP)) return false;
    $p = unpack('N*', inet_pton($ip)); $ps = count($p);

    list ($subnet, $bits) = [$cidr, '128'];
    if (strstr($cidr, '/')) list ($subnet, $bits) = explode('/', $cidr, 2);
    if (!filter_var($subnet, FILTER_VALIDATE_IP)) return false;
    if (!preg_match('/^[1-9][0-9]*$/', $bits)) return false;
    $s = unpack('N*', inet_pton($subnet));
    if (count($s) != $ps) return false;
    $bits = intval($bits);

    $m = [];
    for ($i = 1; $i <= $ps; $i++)
        $m[$i] = ($i*32 - $bits) < 0 ? -1 : -1 << ($i*32 - $bits);

    for ($i = 1; $i <= $ps; $i++)
        if (($p[$i] & $m[$i]) != ($s[$i] & $m[$i]))
            return false;

    return true;
}

/*
  Returns first matching CIDR in $netlist or null if none match.
  net_match('1.2.3.4', ['1.2.3.5/24']) == '1.2.3.5/24'
  net_match('::1.2.3.4', ['::1.2.3.0/126', '::1.2.3.0/125']) ==  '::1.2.3.0/125'
*/
function net_match($ip, $netlist)
{
    foreach ($netlist as $cidr)
        if (cidr_match($ip, $cidr))
            return $cidr;
    return null;
}

언급URL : https://stackoverflow.com/questions/594112/check-whether-or-not-a-cidr-subnet-contains-an-ip-address

반응형