int CIPFilter::AddFromFile(LPCTSTR pszFilePath, bool bShowResponse) { DWORD dwStart = GetTickCount(); FILE* readFile = _tfsopen(pszFilePath, _T("r"), _SH_DENYWR); if (readFile != NULL) { enum EIPFilterFileType { Unknown = 0, FilterDat = 1, // ipfilter.dat/ip.prefix format PeerGuardian = 2, // PeerGuardian text format PeerGuardian2 = 3 // PeerGuardian binary format } eFileType = Unknown; setvbuf(readFile, NULL, _IOFBF, 32768); TCHAR szNam[_MAX_FNAME]; TCHAR szExt[_MAX_EXT]; _tsplitpath(pszFilePath, NULL, NULL, szNam, szExt); if (_tcsicmp(szExt, _T(".p2p")) == 0 || (_tcsicmp(szNam, _T("guarding.p2p")) == 0 && _tcsicmp(szExt, _T(".txt")) == 0)) eFileType = PeerGuardian; else if (_tcsicmp(szExt, _T(".prefix")) == 0) eFileType = FilterDat; else { VERIFY( _setmode(fileno(readFile), _O_BINARY) != -1 ); static const BYTE _aucP2Bheader[] = "\xFF\xFF\xFF\xFFP2B"; BYTE aucHeader[sizeof _aucP2Bheader - 1]; if (fread(aucHeader, sizeof aucHeader, 1, readFile) == 1) { if (memcmp(aucHeader, _aucP2Bheader, sizeof _aucP2Bheader - 1)==0) eFileType = PeerGuardian2; else { (void)fseek(readFile, 0, SEEK_SET); VERIFY( _setmode(fileno(readFile), _O_TEXT) != -1 ); // ugly! } } } int iFoundRanges = 0; int iLine = 0; if (eFileType == PeerGuardian2) { // Version 1: strings are ISO-8859-1 encoded // Version 2: strings are UTF-8 encoded uint8 nVersion; if (fread(&nVersion, sizeof nVersion, 1, readFile)==1 && (nVersion==1 || nVersion==2)) { while (!feof(readFile)) { CHAR szName[256]; int iLen = 0; for (;;) // read until NUL or EOF { int iChar = getc(readFile); if (iChar == EOF) break; if (iLen < sizeof szName - 1) szName[iLen++] = (CHAR)iChar; if (iChar == '\0') break; } szName[iLen] = '\0'; uint32 uStart; if (fread(&uStart, sizeof uStart, 1, readFile) != 1) break; uStart = ntohl(uStart); uint32 uEnd; if (fread(&uEnd, sizeof uEnd, 1, readFile) != 1) break; uEnd = ntohl(uEnd); iLine++; // (nVersion == 2) ? OptUtf8ToStr(szName, iLen) : AddIPRange(uStart, uEnd, DFLT_FILTER_LEVEL, CStringA(szName, iLen)); iFoundRanges++; } } } else { CStringA sbuffer; CHAR szBuffer[1024]; while (fgets(szBuffer, _countof(szBuffer), readFile) != NULL) { iLine++; sbuffer = szBuffer; // ignore comments & too short lines if (sbuffer.GetAt(0) == '#' || sbuffer.GetAt(0) == '/' || sbuffer.GetLength() < 5) { sbuffer.Trim(" \t\r\n"); DEBUG_ONLY( (!sbuffer.IsEmpty()) ? TRACE("IP filter: ignored line %u\n", iLine) : 0 ); continue; } if (eFileType == Unknown) { // looks like html if (sbuffer.Find('>') > -1 && sbuffer.Find('<') > -1) sbuffer.Delete(0, sbuffer.ReverseFind('>') + 1); // check for <IP> - <IP> at start of line UINT u1, u2, u3, u4, u5, u6, u7, u8; if (sscanf(sbuffer, "%u.%u.%u.%u - %u.%u.%u.%u", &u1, &u2, &u3, &u4, &u5, &u6, &u7, &u8) == 8) { eFileType = FilterDat; } else { // check for <description> ':' <IP> '-' <IP> int iColon = sbuffer.Find(':'); if (iColon > -1) { CStringA strIPRange = sbuffer.Mid(iColon + 1); UINT u1, u2, u3, u4, u5, u6, u7, u8; if (sscanf(strIPRange, "%u.%u.%u.%u - %u.%u.%u.%u", &u1, &u2, &u3, &u4, &u5, &u6, &u7, &u8) == 8) { eFileType = PeerGuardian; } } } } bool bValid = false; uint32 start = 0; uint32 end = 0; UINT level = 0; CStringA desc; if (eFileType == FilterDat) bValid = ParseFilterLine1(sbuffer, start, end, level, desc); else if (eFileType == PeerGuardian) bValid = ParseFilterLine2(sbuffer, start, end, level, desc); // add a filter if (bValid) { AddIPRange(start, end, level, desc); iFoundRanges++; } else { sbuffer.Trim(" \t\r\n"); DEBUG_ONLY( (!sbuffer.IsEmpty()) ? TRACE("IP filter: ignored line %u\n", iLine) : 0 ); } } } fclose(readFile); // sort the IP filter list by IP range start addresses qsort(m_iplist.GetData(), m_iplist.GetCount(), sizeof(m_iplist[0]), CmpSIPFilterByStartAddr); // merge overlapping and adjacent filter ranges int iDuplicate = 0; int iMerged = 0; if (m_iplist.GetCount() >= 2) { // On large IP-filter lists there is a noticeable performance problem when merging the list. // The 'CIPFilterArray::RemoveAt' call is way too expensive to get called during the merging, // thus we use temporary helper arrays to copy only the entries into the final list which // are not get deleted. // Reserve a byte array (its used as a boolean array actually) as large as the current // IP-filter list, so we can set a 'to delete' flag for each entry in the current IP-filter list. char* pcToDelete = new char[m_iplist.GetCount()]; memset(pcToDelete, 0, m_iplist.GetCount()); int iNumToDelete = 0; SIPFilter* pPrv = m_iplist[0]; int i = 1; while (i < m_iplist.GetCount()) { SIPFilter* pCur = m_iplist[i]; if ( pCur->start >= pPrv->start && pCur->start <= pPrv->end // overlapping || pCur->start == pPrv->end+1 && pCur->level == pPrv->level) // adjacent { if (pCur->start != pPrv->start || pCur->end != pPrv->end) // don't merge identical entries { //TODO: not yet handled, overlapping entries with different 'level' if (pCur->end > pPrv->end) pPrv->end = pCur->end; //pPrv->desc += _T("; ") + pCur->desc; // this may create a very very long description string... iMerged++; } else { // if we have identical entries, use the lowest 'level' if (pCur->level < pPrv->level) pPrv->level = pCur->level; iDuplicate++; } delete pCur; //m_iplist.RemoveAt(i); // way too expensive (read above) pcToDelete[i] = 1; // mark this entry as 'to delete' iNumToDelete++; i++; continue; } pPrv = pCur; i++; } // Create new IP-filter list which contains only the entries from the original IP-filter list // which are not to be deleted. if (iNumToDelete > 0) { CIPFilterArray newList; newList.SetSize(m_iplist.GetCount() - iNumToDelete); int iNewListIndex = 0; for (int i = 0; i < m_iplist.GetCount(); i++) { if (!pcToDelete[i]) newList[iNewListIndex++] = m_iplist[i]; } ASSERT( iNewListIndex == newList.GetSize() ); // Replace current list with new list. Dump, but still fast enough (only 1 memcpy) m_iplist.RemoveAll(); m_iplist.Append(newList); newList.RemoveAll(); m_bModified = true; } delete[] pcToDelete; } if (thePrefs.GetVerbose()) { DWORD dwEnd = GetTickCount(); AddDebugLogLine(false, _T("Loaded IP filters from \"%s\""), pszFilePath); AddDebugLogLine(false, _T("Parsed lines/entries:%u Found IP ranges:%u Duplicate:%u Merged:%u Time:%s"), iLine, iFoundRanges, iDuplicate, iMerged, CastSecondsToHM((dwEnd-dwStart+500)/1000)); } AddLogLine(bShowResponse, GetResString(IDS_IPFILTERLOADED), m_iplist.GetCount()); } return m_iplist.GetCount(); }
// ==> IP Filter White List [Stulle] - Stulle void CIPFilter::AddFromFileWhite(LPCTSTR pszFilePath) { FILE* readFile = _tfsopen(pszFilePath, _T("r"), _SH_DENYWR); if (readFile != NULL) { _setmode(fileno(readFile), _O_TEXT); int iLine = 0; CStringA sbuffer; CHAR szBuffer[1024]; while (fgets(szBuffer, _countof(szBuffer), readFile) != NULL) { iLine++; sbuffer = szBuffer; // ignore comments & too short lines if (sbuffer.GetAt(0) == '#' || sbuffer.GetAt(0) == '/' || sbuffer.GetLength() < 5) { sbuffer.Trim(" \t\r\n"); DEBUG_ONLY( (!sbuffer.IsEmpty()) ? TRACE("IP filter (white): ignored line %u\n", iLine) : 0 ); continue; } bool bValid = false; uint32 start = 0; uint32 end = 0; UINT level = 0; CStringA desc; bValid = ParseFilterLine1(sbuffer, start, end, level, desc); // add a filter if (bValid) { AddIPRangeWhite(start, end, level, desc); DEBUG_ONLY( TRACE("Added White Entry - start: %u end: %u level: %u desc: %s\n", start, end, level, desc)); } else { sbuffer.Trim(" \t\r\n"); DEBUG_ONLY( (!sbuffer.IsEmpty()) ? TRACE("IP filter (white list): ignored line %u\n", iLine) : 0 ); } } fclose(readFile); // sort the IP filter list by IP range start addresses qsort(m_iplist_White.GetData(), m_iplist_White.GetCount(), sizeof(m_iplist_White[0]), CmpSIPFilterByStartAddr); // merge overlapping and adjacent filter ranges if (m_iplist_White.GetCount() >= 2) { // On large IP-filter lists there is a noticeable performance problem when merging the list. // The 'CIPFilterArray::RemoveAt' call is way too expensive to get called during the merging, // thus we use temporary helper arrays to copy only the entries into the final list which // are not get deleted. // Reserve a byte array (its used as a boolean array actually) as large as the current // IP-filter list, so we can set a 'to delete' flag for each entry in the current IP-filter list. char* pcToDelete = new char[m_iplist_White.GetCount()]; memset(pcToDelete, 0, m_iplist_White.GetCount()); int iNumToDelete = 0; SIPFilter* pPrv = m_iplist_White[0]; int i = 1; while (i < m_iplist_White.GetCount()) { SIPFilter* pCur = m_iplist_White[i]; if ( pCur->start >= pPrv->start && pCur->start <= pPrv->end // overlapping || pCur->start == pPrv->end+1 && pCur->level == pPrv->level) // adjacent { if (pCur->start != pPrv->start || pCur->end != pPrv->end) // don't merge identical entries { //TODO: not yet handled, overlapping entries with different 'level' if (pCur->end > pPrv->end) pPrv->end = pCur->end; //pPrv->desc += _T("; ") + pCur->desc; // this may create a very very long description string... } else { // if we have identical entries, use the lowest 'level' if (pCur->level < pPrv->level) pPrv->level = pCur->level; } delete pCur; //m_iplist_White.RemoveAt(i); // way too expensive (read above) pcToDelete[i] = 1; // mark this entry as 'to delete' iNumToDelete++; i++; continue; } pPrv = pCur; i++; } // Create new IP-filter list which contains only the entries from the original IP-filter list // which are not to be deleted. if (iNumToDelete > 0) { CIPFilterArray newList; newList.SetSize(m_iplist_White.GetCount() - iNumToDelete); int iNewListIndex = 0; for (int i = 0; i < m_iplist_White.GetCount(); i++) { if (!pcToDelete[i]) newList[iNewListIndex++] = m_iplist_White[i]; } ASSERT( iNewListIndex == newList.GetSize() ); // Replace current list with new list. Dump, but still fast enough (only 1 memcpy) m_iplist_White.RemoveAll(); m_iplist_White.Append(newList); newList.RemoveAll(); m_bModified = true; } delete[] pcToDelete; } } if(m_iplist_White.GetCount()>0) AddLogLine(false, GetResString(IDS_IPFILTERWHITELOADED), m_iplist_White.GetCount()); return; }