“58.17.128.0/17”과 같은 형식의 주소 지정 방식. 라우터 같은 곳에서 많이 사용한다. 특정 IP에서의 접속을 막아달라고 이 형식의 리스트가 올 때도 있다.
특정 주소가 목록에 들어있는지 알아내기
“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");