deCloudflare/tool/PGListUtil/src/common/CIpList.cpp

356 lines
8.2 KiB
C++

#include <stdio.h>
#include <string.h>
#include "CIpList.h"
namespace pglu {
namespace ip {
namespace {
inline void Ip_Swap(CIp **ipA, CIp **ipB) {
CIp *ip = *ipA;
*ipA = *ipB;
*ipB = ip;
}
void Ip_SortByIpQuick(CIp **ipBegin, CIp **ipEnd) {
CIp **ipA;
CIp **ipB;
int nGap = ipEnd - ipBegin;
if(nGap < 64)
return;
ipA = ipBegin + ((int)(nGap / 2));
if((*ipBegin)->ip64 > (*ipA)->ip64)
Ip_Swap(ipBegin, ipA);
if((*ipBegin)->ip64 > (*ipEnd)->ip64)
Ip_Swap(ipBegin, ipEnd);
if((*ipA)->ip64 > (*ipEnd)->ip64)
Ip_Swap(ipA, ipEnd);
ulong ip64 = (*ipA)->ip64;
ipB = ipEnd - 1;
Ip_Swap(ipA, ipB);
ipA = ipBegin;
for(; ; ) {
while((*(++ipA))->ip64 < ip64);
while((*(--ipB))->ip64 > ip64);
if(ipA > ipB)
break;
Ip_Swap(ipA, ipB);
}
Ip_Swap(ipA, ipEnd - 1);
Ip_SortByIpQuick(ipBegin, ipB);
Ip_SortByIpQuick(ipA + 1, ipEnd);
}
void Ip_SortByIpInsert(CIp **ipBegin, CIp **ipEnd) {
CIp **ipA = ipBegin + 1;
CIp **ipB;
CIp **ipAEnd = ipEnd + 1;
CIp **ipBEnd = ipBegin - 1;
ulong ip64;
for(; ipA != ipAEnd; ++ipA) {
ip64 = (*ipA)->ip64;
for(ipB = ipA - 1; ipB != ipBEnd && (*ipB)->ip64 > ip64; --ipB)
Ip_Swap(ipB, ipB + 1);
}
}
void Ip_SortByIp(CIp **ipBegin, CIp **ipEnd) {
Ip_SortByIpQuick(ipBegin, ipEnd);
Ip_SortByIpInsert(ipBegin, ipEnd);
}
CIp * Ip_SortByCaption(CIp *ipHeadA) {
if(!ipHeadA || !(ipHeadA->next))
return ipHeadA;
// split ipBを2倍で進めることでipAを中間位置に持っていく
CIp *ipA = ipHeadA;
CIp *ipB = ipHeadA->next->next;
while(ipB) {
ipA = ipA->next;
ipB = ipB->next;
if(ipB)
ipB = ipB->next;
}
CIp *ipHeadB = ipA->next;
ipA->next = NULL;
ipHeadA = Ip_SortByCaption(ipHeadA);
ipHeadB = Ip_SortByCaption(ipHeadB);
// merge
CIp ipMerged;
ipA = &ipMerged;
while(ipHeadA || ipHeadB) {
if(((ipHeadA && ipHeadB) && stricmp(ipHeadA->caption, ipHeadB->caption) <= 0) || !ipHeadB) {
ipA->next = ipHeadA;
ipHeadA = ipHeadA->next;
} else {
ipA->next = ipHeadB;
ipHeadB = ipHeadB->next;
}
ipA = ipA->next;
}
ipA->next = NULL;
return ipMerged.next;
}
} // namespace
//--------------------------------------
// CIpList class
//--------------------------------------
CIpList::CIpList() :
m_poolIp(sizeof(CIp)),
m_ipFoot(&m_ipHead),
m_count(0),
m_countDisabled(0)
{
m_ipHead.caption = NULL;
m_ipHead.ip64 = 0L;
m_ipHead.next = NULL;
}
CIpList::~CIpList() {
Clear();
}
void CIpList::Clear() {
for(CIp *ip = m_ipHead.next; ip; ip = ip->next)
delete[] ip->caption;
m_poolIp.purge_memory();
m_ipHead.next = NULL;
m_ipFoot = &m_ipHead;
m_count = 0;
m_countDisabled = 0;
UnSetFilter();
}
void CIpList::SetFilter(const char *filter, const filter::EFilterMode mode, const bool del) {
m_filter.Assign(filter, mode, del);
}
void CIpList::UnSetFilter() {
m_filter.Clear();
}
CIp * CIpList::CreateIp(boost::xpressive::cmatch & match) {
CIp *ip = (CIp*)m_poolIp.malloc();
const char *capBegin = match.prefix().first;
const char *capEnd = match[9].first;
size_t lenCap = capEnd - capBegin;
char *chunk = new char[lenCap + 1];
memcpy(chunk, capBegin, lenCap);
*(chunk + lenCap) = '\0';
ip->caption = chunk;
uchar *ip8 = ip->ip8;
ip8[4] = ParseDigit3(match[4].first, match[4].second);
ip8[5] = ParseDigit3(match[3].first, match[3].second);
ip8[6] = ParseDigit3(match[2].first, match[2].second);
ip8[7] = ParseDigit3(match[1].first, match[1].second);
if(*(match[10].first) == '-') {
ip8[0] = ParseDigit3(match[8].first, match[8].second);
ip8[1] = ParseDigit3(match[7].first, match[7].second);
ip8[2] = ParseDigit3(match[6].first, match[6].second);
ip8[3] = ParseDigit3(match[5].first, match[5].second);
} else {
ip->ip32[0] = ip->ip32[1] | (0xFFFFFFFF >> ParseDigit3(match[11].first, match[11].second));
}
return ip;
}
bool CIpList::LoadListFile(const char *path) {
char buf[PGLU_LENGTH_FILELINE];
char colon;
char *colon_p;
using namespace boost::xpressive;
static cmatch match;
static mark_tag tagIp1(1), tagIp2(2), tagIp3(3), tagIp4(4), tagIp5(5), tagIp6(6), tagIp7(7), tagIp8(8);
static mark_tag tagColon(9), tagSep(10), tagMask(11);
static cregex reSyntax = // bos >> (tag = *_) >> // slower
(tagColon = as_xpr(':')) >> *_s >>
(tagIp1 = repeat<1, 3>(_d)) >> as_xpr('.') >>
(tagIp2 = repeat<1, 3>(_d)) >> as_xpr('.') >>
(tagIp3 = repeat<1, 3>(_d)) >> as_xpr('.') >>
(tagIp4 = repeat<1, 3>(_d)) >>
*_s >> (tagSep = as_xpr('-')) >> *_s >>
(tagIp5 = repeat<1, 3>(_d)) >> as_xpr('.') >>
(tagIp6 = repeat<1, 3>(_d)) >> as_xpr('.') >>
(tagIp7 = repeat<1, 3>(_d)) >> as_xpr('.') >>
(tagIp8 = repeat<1, 3>(_d)) >>
*_s >> (_ln | eos);
static cregex reSyntaxRestorable =
(tagColon = !as_xpr(':')) >> *_s >>
(tagIp1 = repeat<1, 3>(_d)) >> (set = '.', ',') >>
(tagIp2 = repeat<1, 3>(_d)) >> (set = '.', ',') >>
(tagIp3 = repeat<1, 3>(_d)) >> (set = '.', ',') >>
(tagIp4 = repeat<1, 3>(_d)) >> *_s >> (
(tagSep = +as_xpr('-')) >> *_s >>
(tagIp5 = repeat<1, 3>(_d)) >> (set = '.', ',') >>
(tagIp6 = repeat<1, 3>(_d)) >> (set = '.', ',') >>
(tagIp7 = repeat<1, 3>(_d)) >> (set = '.', ',') >>
(tagIp8 = repeat<1, 3>(_d))
|
(tagSep = +(set = '/', '\\')) >> *_s >>
(tagMask = repeat<1, 2>(_d))
) >> *_s >> (_ln | eos);
FILE *fp = fopen(path, "r");
if(fp == NULL)
return false;
CIp *ip = m_ipFoot;
if(m_filter.IsEmpty()) {
while(fgets(buf, PGLU_LENGTH_FILELINE, fp)) {
if(regex_search(buf, match, reSyntax) || regex_search(buf, match, reSyntaxRestorable)) {
++m_count;
ip->next = CreateIp(match);
ip = ip->next;
}
#ifdef __MINGW32__
ZeroString(buf);
#endif
}
} else {
while(fgets(buf, PGLU_LENGTH_FILELINE, fp)) {
if(regex_search(buf, match, reSyntax) || regex_search(buf, match, reSyntaxRestorable)) {
colon_p = (char*)(match[9].first);
colon = *colon_p;
*colon_p = '\0';
if(m_filter.IsMatch(buf)) {
++m_count;
ip->next = CreateIp(match);
ip = ip->next;
}
*colon_p = colon;
}
#ifdef __MINGW32__
ZeroString(buf);
#endif
}
}
fclose(fp);
ip->next = NULL;
m_ipFoot = ip;
return true;
}
bool CIpList::SaveListFile(const char *path, const bool append) {
uchar *ip8;
FILE *fp = fopen(path, (append ? "a" : "w"));
if(fp == NULL)
return false;
for(CIp *ip = m_ipHead.next; ip; ip = ip->next) {
// IPが0Lなら書き出さない
if(ip->ip64 != 0L) {
ip8 = ip->ip8;
fprintf(fp,
"%s:%u.%u.%u.%u-%u.%u.%u.%u\n",
ip->caption,
ip8[7], ip8[6], ip8[5], ip8[4],
ip8[3], ip8[2], ip8[1], ip8[0]
);
}
}
fclose(fp);
return true;
}
void CIpList::CheckAndSort(const bool sortCap, const bool sortIp, const bool delDupIp) {
CIp **ipBegin;
CIp **ipEnd;
CIp *ip;
if(m_count < 2)
return;
if(sortIp || delDupIp) {
// リストから配列を複製
CIp **ipSort = new CIp*[m_count];
ipBegin = ipSort;
for(ip = m_ipHead.next; ip; ip = ip->next)
*(ipBegin++) = ip;
// 配列をソート
Ip_SortByIp(ipSort, ipSort + m_count - 1);
if(delDupIp) {
// すでにIPが0Lなものを無効としてカウント
ipBegin = ipSort;
ipEnd = ipBegin + m_count;
for(; ipBegin != ipEnd && (*ipBegin)->ip64 == 0L; ++ipBegin)
++m_countDisabled;
if(ipBegin == ipEnd)
goto END_SORT; // 全てのIPが0L
// 重複したIPは0Lにして無効としてカウント
for(--ipEnd; ipBegin != ipEnd; ++ipBegin)
if((*ipBegin)->ip64 == (*(ipBegin + 1))->ip64) {
(*ipBegin)->ip64 = 0L;
++m_countDisabled;
}
}
if(sortIp) {
// 配列の中身を連結
ipBegin = ipSort;
ipEnd = ipSort + m_count;
ip = &m_ipHead;
while(ipBegin != ipEnd) {
ip->next = *(ipBegin++);
ip = ip->next;
}
ip->next = NULL;
}
END_SORT:
delete[] ipSort;
}
if(sortCap)
m_ipHead.next = Ip_SortByCaption(m_ipHead.next);
if(sortIp || sortCap) {
// m_ipFootを再設定
ip = m_ipHead.next;
if(ip) {
for(; ip->next; ip = ip->next);
m_ipFoot = ip;
} else {
m_ipFoot = &m_ipHead;
}
}
}
int CIpList::Count() {
return m_count;
}
int CIpList::CountDisabled() {
return m_countDisabled;
}
} // namespace ip
} // namespace pglu