📖
특정 IP 주소가 주어진 서브넷(CIDR) 범위 안에 있는지를 확인하는 함수(IPv4 + IPv6 지원) + 그누보드용 IP 접근 제어 모듈

페이지 정보

본문

IPv4와 IPv6 모두 지원하는 is_ip_in_subnet() 함수의 개선된 버전입니다.
비트마스크 방식을 사용하여 CIDR 계산 정확도를 높이고, IPv6 확장도 함께 반영했습니다.
✅ 개선된 is_ip_in_subnet() 함수 (IPv4 + IPv6 지원)[code]/**
 * IPv4 또는 IPv6 주소가 서브넷 범위에 있는지 확인
 *
 * @param string $ip 검사할 IP 주소
 * @param string $subnet 서브넷 주소 (예: 192.168.1.0 또는 2001:db8::)
 * @param int $cidr CIDR 마스크 (예: 24, 64 등)
 * @return bool
 */
function is_ip_in_subnet($ip, $subnet, $cidr) {
    $ip_bin = inet_pton($ip);
    $subnet_bin = inet_pton($subnet);

    if ($ip_bin === false || $subnet_bin === false) {
        return false; // 유효하지 않은 IP 또는 서브넷
    }

    // 주소 유형에 따라 바이트 수 결정 (IPv4=4, IPv6=16)
    $len = strlen($ip_bin);
    $max_bits = $len * 8;

    if ($cidr > $max_bits) {
        return false; // 잘못된 CIDR
    }

    // CIDR 비트 수만큼 마스크 생성
    $bin_mask = str_repeat("\xff", $cidr >> 3); // 정수 바이트 마스크
    if ($cidr % 8 !== 0) {
        $bin_mask .= chr(0xff << (8 - $cidr % 8));
    }
    $bin_mask = str_pad($bin_mask, $len, "\0"); // 나머지는 0으로 패딩

    // 비트마스크 연산으로 비교
    return ($ip_bin & $bin_mask) === ($subnet_bin & $bin_mask);
}[/code]
✅ 사용 예시
IPv4 테스트[code]<?php
$testIp = "192.168.1.5";
$subnet = "192.168.1.0";
$cidr = 24;

echo is_ip_in_subnet($testIp, $subnet, $cidr)
    ? "$testIp 는 $subnet/$cidr 서브넷 내에 있습니다.\n"
    : "$testIp 는 $subnet/$cidr 서브넷 밖입니다.\n";[/code]
✅ PHP 버전 요구사항
inet_pton() 함수는 PHP 5.0 이상에서 지원됩니다.
이 방식은 IPv4/IPv6 모두 대응하며, CIDR 마스크가 정확하게 적용됩니다.

🔒 추가 제안 (보안 및 신뢰성)
filter_var()를 사용하여 IP 주소 형식 검증을 추가할 수 있습니다.[code]if (!filter_var($ip, FILTER_VALIDATE_IP) || !filter_var($subnet, FILTER_VALIDATE_IP)) {
    return false;
}[/code]
💎 아래는 IPv4 및 IPv6를 모두 지원하며, **여러 서브넷(CIDR 목록)**에 대해 IP가 포함되는지 확인할 수 있는 클래스 형태의 PHP 코드입니다.[code]<?php
class IPSubnetChecker
{
    /**
    * IP가 하나 이상의 서브넷에 포함되는지 확인
    *
    * @param string $ip 검사할 IP 주소
    * @param array $cidrList CIDR 목록 (예: ['192.168.1.0/24', '2001:db8::/32'])
    * @return bool
    */
    public static function isIpInSubnets(string $ip, array $cidrList): bool
    {
        foreach ($cidrList as $cidr) {
            if (self::isIpInSubnet($ip, $cidr)) {
                return true;
            }
        }
        return false;
    }

    /**
    * IP가 단일 서브넷에 포함되는지 확인
    *
    * @param string $ip 검사할 IP
    * @param string $cidr CIDR 표현 (예: 192.168.1.0/24)
    * @return bool
    */
    public static function isIpInSubnet(string $ip, string $cidr): bool
    {
        // CIDR을 주소와 마스크로 분리
        if (strpos($cidr, '/') === false) return false;
        [$subnet, $maskBits] = explode('/', $cidr, 2);

        // 유효성 검사
        if (!filter_var($ip, FILTER_VALIDATE_IP) || !filter_var($subnet, FILTER_VALIDATE_IP)) {
            return false;
        }

        $ipBin = inet_pton($ip);
        $subnetBin = inet_pton($subnet);
        if ($ipBin === false || $subnetBin === false) return false;

        $len = strlen($ipBin);        // IPv4: 4 / IPv6: 16
        $maxBits = $len * 8;
        $maskBits = (int)$maskBits;

        if ($maskBits < 0 || $maskBits > $maxBits) return false;

        // 마스크 생성
        $mask = str_repeat("\xff", intdiv($maskBits, 8));
        if ($maskBits % 8 !== 0) {
            $mask .= chr(0xff << (8 - $maskBits % 8));
        }
        $mask = str_pad($mask, $len, "\0");

        // 비교
        return ($ipBin & $mask) === ($subnetBin & $mask);
    }
}[/code]
✅ 사용 예시[code]<?php
$ip = "2001:db8::1234";

$cidrList = [
    "192.168.1.0/24",
    "10.0.0.0/8",
    "2001:db8::/32"
];

if (IPSubnetChecker::isIpInSubnets($ip, $cidrList)) {
    echo "$ip 는 CIDR 목록 중 하나에 포함됩니다.\n";
} else {
    echo "$ip 는 어떤 CIDR 범위에도 포함되지 않습니다.\n";
}[/code]
✅ 결과 예시[code]2001:db8::1234 는 CIDR 목록 중 하나에 포함됩니다.[/code]
💎 아래는 **그누보드5(GNUBoard5)**에 쉽게 통합할 수 있는 IP 접근 제어 모듈입니다.
특정 IP 또는 CIDR 대역 목록에 따라 페이지 접근을 차단하거나 허용할 수 있으며,
관리자 페이지나 특정 스크립트에서 손쉽게 사용할 수 있습니다.

✅ 1. ip_block_check.php (모듈 파일)
/bbs/ip_block_check.php 경로에 저장하세요.[code]<?php
// IP 접근 제어 클래스 정의
class IPSubnetChecker
{
    public static function isIpInSubnets(string $ip, array $cidrList): bool
    {
        foreach ($cidrList as $cidr) {
            if (self::isIpInSubnet($ip, $cidr)) return true;
        }
        return false;
    }

    public static function isIpInSubnet(string $ip, string $cidr): bool
    {
        if (strpos($cidr, '/') === false) return false;
        [$subnet, $maskBits] = explode('/', $cidr, 2);

        if (!filter_var($ip, FILTER_VALIDATE_IP) || !filter_var($subnet, FILTER_VALIDATE_IP)) {
            return false;
        }

        $ipBin = inet_pton($ip);
        $subnetBin = inet_pton($subnet);
        if ($ipBin === false || $subnetBin === false) return false;

        $len = strlen($ipBin);
        $maxBits = $len * 8;
        $maskBits = (int)$maskBits;

        if ($maskBits < 0 || $maskBits > $maxBits) return false;

        $mask = str_repeat("\xff", intdiv($maskBits, 8));
        if ($maskBits % 8 !== 0) {
            $mask .= chr(0xff << (8 - $maskBits % 8));
        }
        $mask = str_pad($mask, $len, "\0");

        return ($ipBin & $mask) === ($subnetBin & $mask);
    }
}

// ✅ 차단 또는 허용할 IP 목록 지정 (CIDR 지원)
$block_cidrs = [
    '192.168.0.0/16',
    '10.0.0.0/8',
    '2001:db8::/32'
];

// 현재 접속 IP
$client_ip = $_SERVER['REMOTE_ADDR'];

// ✅ 차단 동작 설정
if (IPSubnetChecker::isIpInSubnets($client_ip, $block_cidrs)) {
    header("HTTP/1.1 403 Forbidden");
    echo "<h2>접근이 차단되었습니다.</h2>";
    echo "<p>당신의 IP($client_ip)은 관리자에 의해 제한된 대역에 포함되어 있습니다.</p>";
    exit;
}[/code]
✅ 2. 원하는 페이지에 적용 예시
bbs/list.php나 bbs/write.php 또는 특정 plugin.php 파일 상단에 다음 한 줄을 추가하세요.[code]include_once(G5_PATH.'/bbs/ip_block_check.php');[/code]Tip: 전체 사이트에 적용하고 싶다면 common.php 상단에 include_once로 추가해도 됩니다. 단, 관리자 제외 조건도 추가해야 함.

✅ 3. 관리자 제외 처리 예시 (선택 사항)
관리자는 IP 차단에서 제외되도록 하려면 다음처럼 조건을 수정하세요.[code]if (!defined('G5_ADMIN') && !IS_ADMIN
    && IPSubnetChecker::isIpInSubnets($client_ip, $block_cidrs)) {
    header("HTTP/1.1 403 Forbidden");
    echo "<h2>접근이 차단되었습니다.</h2>";
    exit;
}[/code]
💎이번에는 그누보드용 IP 접근 제어 모듈을 "허용 리스트(CIDR 기준 화이트리스트)" 방식으로 구성해드리겠습니다.
즉, 지정된 IP 대역에 속하지 않은 IP는 모두 차단됩니다.

✅ 1. ip_allow_check.php — 화이트리스트 모듈 파일
/bbs/ip_allow_check.php 또는 /extend/ip_allow_check.php 등에 저장하세요.[code]<?php
// IP 허용 클래스
class IPSubnetChecker
{
    public static function isIpInSubnets(string $ip, array $cidrList): bool
    {
        foreach ($cidrList as $cidr) {
            if (self::isIpInSubnet($ip, $cidr)) return true;
        }
        return false;
    }

    public static function isIpInSubnet(string $ip, string $cidr): bool
    {
        if (strpos($cidr, '/') === false) return false;
        [$subnet, $maskBits] = explode('/', $cidr, 2);

        if (!filter_var($ip, FILTER_VALIDATE_IP) || !filter_var($subnet, FILTER_VALIDATE_IP)) {
            return false;
        }

        $ipBin = inet_pton($ip);
        $subnetBin = inet_pton($subnet);
        if ($ipBin === false || $subnetBin === false) return false;

        $len = strlen($ipBin);
        $maxBits = $len * 8;
        $maskBits = (int)$maskBits;

        if ($maskBits < 0 || $maskBits > $maxBits) return false;

        $mask = str_repeat("\xff", intdiv($maskBits, 8));
        if ($maskBits % 8 !== 0) {
            $mask .= chr(0xff << (8 - $maskBits % 8));
        }
        $mask = str_pad($mask, $len, "\0");

        return ($ipBin & $mask) === ($subnetBin & $mask);
    }
}

// ✅ 허용할 CIDR 목록 (화이트리스트)
$allow_cidrs = [
    '203.0.113.0/24',    // 회사 네트워크
    '45.112.80.0/23',    // 방송 서버
    '2001:db8::/32',      // IPv6 허용
];

// 현재 접속 IP
$client_ip = $_SERVER['REMOTE_ADDR'];

// ✅ 관리자 제외 + 허용 목록 이외 차단
if (!defined('G5_ADMIN') && !IS_ADMIN
    && !IPSubnetChecker::isIpInSubnets($client_ip, $allow_cidrs)) {

    header("HTTP/1.1 403 Forbidden");
    echo "<h2>Access Denied</h2>";
    echo "<p>Your IP ($client_ip) is not authorized to access this service.</p>";
    exit;
}[/code]
✅ 2. 적용 방법
모든 접속을 제한하고 싶다면 common.php 상단에 다음 코드를 추가하세요.[code]include_once(G5_PATH.'/bbs/ip_allow_check.php');[/code]단, 관리자 페이지나 로그인 페이지는 예외 처리할 수도 있습니다. 예:[code]if (!defined('G5_ADMIN') && G5_IS_MOBILE !== true) {
    include_once(G5_PATH.'/bbs/ip_allow_check.php');
}[/code]✅ 결과 동작
지정된 IP 대역(CIDR) 목록에 포함된 IP만 사이트 접근 가능
그 외 모든 외부 접속은 403 Forbidden으로 차단됨
관리자(IS_ADMIN)는 항상 허용

💥그누보드5에서는 /extend/ 폴더에 PHP 파일을 두면, 별도 include 없이 자동 실행됩니다.
✅ extend 폴더의 역할
G5_PATH/extend/ 폴더 안의 .php 파일들은 common.php 실행 시 자동으로 include 됩니다.
즉, 사이트 전체 공통 적용에 적합합니다.
파일명 순서대로 로딩되므로 파일명 앞에 00_, 99_ 등 붙이면 실행 순서 조정 가능.

✅ 적용 요약
예를 들어, IP 허용 체크를 extend로 자동 적용하고 싶다면:
1. ip_allow_check.php 파일을 G5_PATH/extend/ip_allow_check.php 로 저장
(또는 실행 순서 조정 위해 00_ip_allow_check.php 등으로)
2. 그누보드 전체에 자동 적용됨
(단, 관리자 페이지나 로그인 페이지는 조건 추가로 제외 가능)

✅ 관리자 제외 조건 포함한 예시[code]<?php
// extend/00_ip_allow_check.php

if (defined('G5_ADMIN')) return;
if (defined('_LOGIN')) return;

class IPSubnetChecker { /* ...생략 (위 코드 참조)... */ }

$allow_cidrs = [
    '203.0.113.0/24',
    '45.112.80.0/23',
    '2001:db8::/32',
];

$client_ip = $_SERVER['REMOTE_ADDR'];

if (!IS_ADMIN && !IPSubnetChecker::isIpInSubnets($client_ip, $allow_cidrs)) {
    header("HTTP/1.1 403 Forbidden");
    echo "<h2>접근이 제한되었습니다</h2>";
    echo "<p>당신의 IP($client_ip)은 허용되지 않았습니다.</p>";
    exit;
}[/code]defined('_LOGIN')는 로그인 시도 중 차단되지 않게 하기 위한 예시입니다.
필요에 따라 $_SERVER['SCRIPT_NAME'] 체크도 가능.

✅ 추가 팁
개발 도중 본인 IP가 차단되면 접속 불가 → 꼭 본인 IP는 먼저 CIDR에 추가하세요.
extend 안의 파일 변경 시 즉시 적용됨 (캐시 없음)
로그인이 필요한 페이지만 보호하고 싶다면 if (!defined('_GNUBOARD_')) return; 조건도 활용 가능

댓글목록

등록된 댓글이 없습니다.


자료 목록
번호 제목 날짜
199
🫧
05-23
📖
🫧
05-23
197
🫧
05-23
196
🫧
05-23
195
🫧
05-22
194
🫧
05-22
193
🫧
05-22
192
🫧
05-22
191
🫧
05-21
190
🫧
05-16
189
🫧
05-15
188
🫧
05-14
187
🫧
05-11
186
🫧
05-10
185
🫧
05-10

🔍 검색

회사소개 개인정보처리방침 서비스이용약관
Copyright © rainbowgarden.shop All rights reserved.