사용자 도구

사이트 도구


kb:cidrnetworkmask

CIDR Network Mask

“58.17.128.0/17”과 같은 형식의 주소 지정 방식. 라우터 같은 곳에서 많이 사용한다. 특정 IP에서의 접속을 막아달라고 이 형식의 리스트가 올 때도 있다.

CIDR 방식의 주소 목록 조회하기

특정 주소가 목록에 들어있는지 알아내기

“58.17.128.0/17” 형식의 문자열은 시작 IP와 끝 IP 사이의 범위로 변환할 수 있다. 이를 컬렉션에다 집어넣어둔 다음, 입력으로 들어온 IP를 포함하는 범위가 있는지 체크하면 된다. 아래의 구현은 그냥 배열로 목록을 관리하고 있으나, IntervalTree 같은 데이터 구조를 이용하면 좀 더 나은(?) 프로그램을 만들 수 있다.

class cCidrMask
{
private:
    struct MASK
    {
        unsigned int StartIP; ///< 시작 IP
        unsigned int EndIP;   ///< 끝 IP
    };
 
    std::vector<MASK> m_MaskArray; ///< CIDR 마스크의 배열
 
 
public:
    /// \brief 생성자
    cCidrMask() {}
 
    /// \brief 소멸자
    ~cCidrMask() { m_MaskArray.clear(); }
 
 
public:
    /// \brief CIDR 마스크를 추가한다.
    /// \param cidr "58.14.0.0/16" 같은 형식의 문자열
    /// \return bool 무사히 추가했다면 true, 잘못된 문자열이라면 false
    bool Add(const std::string& cidr)
    {
        bool success = false;
 
        size_t pos = cidr.find_first_of('/');
        if (pos != std::string::npos)
        {
            std::string elements[2] = { cidr.substr(0, pos), cidr.substr(pos+1) };
 
            unsigned int ip        = IP2Int(elements[0].c_str());
            int          bits      = atoi(elements[1].c_str());
            unsigned int mask      = ~(0xFFFFFFFF >> bits); 
            unsigned int network   = ip & mask;
            unsigned int broadcast = network + ~mask; 
            unsigned int usable    = (bits > 30) ? 0 : (broadcast - network - 1);
 
            if (usable > 0)
            {
                MASK mask;
                mask.StartIP = network + 1;
                mask.EndIP = broadcast - 1;
                m_MaskArray.push_back(mask);
                success = true;
            }
        }
 
        return success;
    }
 
    /// \brief 주어진 IP가 추가한 마스크 중의 하나에 포함되는지를 체크한다.
    /// \param address 체크할 IP 주소 문자열 "58.14.0.0"
    /// \return bool 포함되어 있다면 true, 포함되어 있지 않다면 false
    bool Exist(const std::string& address) const
    {
        unsigned int converted = IP2Int(address.c_str());
 
        bool exist = false;
 
        for (size_t i=0; i<m_MaskArray.size(); ++i)
        {
            if (m_MaskArray[i].StartIP <= converted && converted <= m_MaskArray[i].EndIP)
            {
                exist = true;
                break;
            }
        }
 
        return exist;
    }
 
 
private:    
    /// \brief 문자열 형태의 IP 주소를 4바이트 숫자로 변환
    unsigned int IP2Int(const std::string& ip)
    {
        char buf[256] = {0, };
        strcpy_s(buf, ARRAYSIZE(buf), ip.c_str());
 
        unsigned int converted = 0;
        unsigned int count = 0;
        unsigned int bits = 24;
 
        LPSTR context = NULL;
        LPSTR token = strtok_s(buf, ".", &context);
        while (token && count < 4)
        {
            converted += (static_cast<unsigned int>(atoi(token))) << bits;
 
            bits -= 8;
            count += 1;
 
            token = strtok_s(NULL, ".", &context);
        }
 
        return converted;        
    }
};
cCidrMask mask;
mask.Add("58.17.128.0/17");
bool a = mask.Exist("58.17.127.1");
bool b = mask.Exist("58.17.128.1");
bool c = mask.Exist("58.17.128.2");

링크

kb/cidrnetworkmask.txt · 마지막으로 수정됨: 2014/11/06 19:11 (바깥 편집)