diff --git a/src/filterparserthread.h b/src/filterparserthread.h index ee0107106..3ad6c2594 100644 --- a/src/filterparserthread.h +++ b/src/filterparserthread.h @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -46,376 +45,336 @@ using namespace std; // P2B Stuff #include #ifdef Q_WS_WIN - #include +#include #else - #include +#include #endif // End of P2B stuff class FilterParserThread : public QThread { Q_OBJECT - private: - session *s; - ip_filter filter; - bool abort; - QString filePath; - - protected: - void run(){ - qDebug("Processing filter file"); - if(filePath.endsWith(".dat", Qt::CaseInsensitive)) { - // eMule DAT file - parseDATFilterFile(filePath); +private: + session *s; + ip_filter filter; + bool abort; + QString filePath; + +protected: + void run(){ + qDebug("Processing filter file"); + if(filePath.endsWith(".dat", Qt::CaseInsensitive)) { + // eMule DAT file + parseDATFilterFile(filePath); + } else { + if(filePath.endsWith(".p2p", Qt::CaseInsensitive)) { + // PeerGuardian p2p file + parseP2PFilterFile(filePath); } else { - if(filePath.endsWith(".p2p", Qt::CaseInsensitive)) { - // PeerGuardian p2p file - parseP2PFilterFile(filePath); + if(filePath.endsWith(".p2b", Qt::CaseInsensitive)) { + // PeerGuardian p2b file + parseP2BFilterFile(filePath); } else { - if(filePath.endsWith(".p2b", Qt::CaseInsensitive)) { - // PeerGuardian p2b file - parseP2BFilterFile(filePath); - } else { - // Default: eMule DAT format - parseDATFilterFile(filePath); - } + // Default: eMule DAT format + parseDATFilterFile(filePath); } } - s->set_ip_filter(filter); - qDebug("IP Filter thread: finished parsing, filter applied"); - } - - public: - FilterParserThread(QObject* parent, session *s) : QThread(parent), s(s), abort(false) { - - } - - ~FilterParserThread(){ - abort = true; - wait(); } - - // Parser for eMule ip filter in DAT format - void parseDATFilterFile(QString filePath) { - const QRegExp is_ipv6(QString::fromUtf8("^[0-9a-f]{4}(:[0-9a-f]{4}){7}$"), Qt::CaseInsensitive, QRegExp::RegExp); - const QRegExp is_ipv4(QString::fromUtf8("^(([0-1]?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))(\\.(([0-1]?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))){3}$"), Qt::CaseInsensitive, QRegExp::RegExp); - QString strStartIP, strEndIP; - bool IPv4 = true; - QFile file(filePath); - if (file.exists()){ - if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ - std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl; - return; + s->set_ip_filter(filter); + qDebug("IP Filter thread: finished parsing, filter applied"); + } + +public: + FilterParserThread(QObject* parent, session *s) : QThread(parent), s(s), abort(false) { + + } + + ~FilterParserThread(){ + abort = true; + wait(); + } + + // Parser for eMule ip filter in DAT format + void parseDATFilterFile(QString filePath) { + QFile file(filePath); + if (file.exists()){ + if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ + std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl; + return; + } + unsigned int nbLine = 0; + while (!file.atEnd() && !abort) { + ++nbLine; + QByteArray line = file.readLine(); + // Ignoring empty lines + line = line.trimmed(); + if(line.isEmpty()) continue; + // Ignoring commented lines + if(line.startsWith('#') || line.startsWith("//")) continue; + + // Line should be splitted by commas + QList partsList = line.split(','); + const uint nbElem = partsList.size(); + + // IP Range should be splitted by a dash + QList IPs = partsList.first().split('-'); + if(IPs.size() != 2) { + qDebug("Ipfilter.dat: line %d is malformed.", nbLine); + qDebug("Line was %s", line.constData()); + continue; } - unsigned int nbLine = 0; - while (!file.atEnd() && !abort) { - ++nbLine; - QByteArray line = file.readLine(); - // Ignoring empty lines - line = line.trimmed(); - if(line.isEmpty()) continue; - // Ignoring commented lines - if(line.startsWith('#') || line.startsWith("//")) continue; - // Line is not commented - QList partsList = line.split(','); - unsigned int nbElem = partsList.size(); - // IP Range can be splitted by a dash or a comma... - // Check if there is a dash in first part - QByteArray firstPart = partsList.at(0); - int nbAccess = 0; - if(firstPart.contains('-')) { - // Range is splitted by a dash - QList IPs = firstPart.split('-'); - if(IPs.size() != 2) { - qDebug("Ipfilter.dat: line %d is malformed.", nbLine); - continue; - } - strStartIP = IPs.at(0).trimmed(); - strEndIP = IPs.at(1).trimmed(); - // Check if IPs are correct - if(strStartIP.contains(is_ipv4) && strEndIP.contains(is_ipv4)) { - IPv4 = true; - } else { - if(strStartIP.contains(is_ipv6) && strEndIP.contains(is_ipv6)) { - IPv4 = false; - } else { - // Could not determine IP format - qDebug("Ipfilter.dat: line %d is malformed.", nbLine); - continue; - } - } - // Check if there is an access value (apparently not mandatory) - if(nbElem > 1) { - // There is possibly one - bool ok; - nbAccess = partsList.at(1).trimmed().toInt(&ok); - if(!ok){ - nbAccess = 0; - } - } - } else { - // Range is probably splitted by a comma - unsigned int nbElem = partsList.size(); - if(nbElem > 1) { - strStartIP = firstPart.trimmed(); - strEndIP = partsList.at(1).trimmed(); - // Check if IPs are correct - if(strStartIP.contains(is_ipv4) && strEndIP.contains(is_ipv4)) { - IPv4 = true; - } else { - if(strStartIP.contains(is_ipv6) && strEndIP.contains(is_ipv6)) { - IPv4 = false; - } else { - // Could not determine IP format - qDebug("Ipfilter.dat: line %d is malformed.", nbLine); - continue; - } - } - // Check if there is an access value (apparently not mandatory) - if(nbElem > 2) { - // There is possibly one - bool ok; - nbAccess = partsList.at(2).trimmed().toInt(&ok); - if(!ok){ - nbAccess = 0; - } - } - } - } - if(nbAccess > 127) { - // Ignoring this rule because access value is too high - continue; - } - // Now Add to the filter - QStringList IP; - try { - if(IPv4) { - //IPv4 addresses - IP = strStartIP.split('.'); - if(IP.size() != 4) - throw exception(); - address_v4 start((IP.at(0).toUInt() << 24) + (IP.at(1).toUInt() << 16) + (IP.at(2).toUInt() << 8) + IP.at(3).toUInt()); - IP = strEndIP.split('.'); - if(IP.size() != 4) - throw exception(); - address_v4 last((IP.at(0).toUInt() << 24) + (IP.at(1).toUInt() << 16) + (IP.at(2).toUInt() << 8) + IP.at(3).toUInt()); - // Apply to bittorrent session - filter.add_rule(start, last, ip_filter::blocked); - } else { - // IPv6, ex : 1fff:0000:0a88:85a3:0000:0000:ac1f:8001 - IP = strStartIP.split(':'); - address_v6 start = address_v6::from_string(strStartIP.remove(':', 0).toLocal8Bit().data()); - IP = strEndIP.split(':'); - address_v6 last = address_v6::from_string(strEndIP.remove(':', 0).toLocal8Bit().data()); - // Apply to bittorrent session - filter.add_rule(start, last, ip_filter::blocked); - } - }catch(exception){ - qDebug("Bad line in filter file, avoided crash..."); - } + + boost::system::error_code ec; + const QString strStartIP = IPs.at(0).trimmed(); + libtorrent::address startAddr = libtorrent::address::from_string(qPrintable(strStartIP), ec); + if(ec) { + qDebug("Ipfilter.dat: line %d is malformed.", nbLine); + qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP)); + continue; } - file.close(); - } - } - - // Parser for PeerGuardian ip filter in p2p format - void parseP2PFilterFile(QString filePath) { - const QRegExp is_ipv4(QString::fromUtf8("^(([0-1]?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))(\\.(([0-1]?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))){3}$"), Qt::CaseInsensitive, QRegExp::RegExp); - QFile file(filePath); - QStringList IP; - if (file.exists()){ - if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ - std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl; - return; + const QString strEndIP = IPs.at(1).trimmed(); + libtorrent::address endAddr = libtorrent::address::from_string(qPrintable(strEndIP), ec); + if(ec) { + qDebug("Ipfilter.dat: line %d is malformed.", nbLine); + qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP)); + continue; } - unsigned int nbLine = 0; - while (!file.atEnd() && !abort) { - ++nbLine; - QByteArray line = file.readLine(); - // Ignoring empty lines - line = line.trimmed(); - if(line.isEmpty()) continue; - // Ignoring commented lines - if(line.startsWith('#') || line.startsWith("//")) continue; - // Line is not commented - QList partsList = line.split(':'); - if(partsList.size() < 2){ - qDebug("p2p file: line %d is malformed.", nbLine); - continue; - } - // Get IP range - QList IPs = partsList.last().split('-'); - if(IPs.size() != 2) { - qDebug("p2p file: line %d is malformed.", nbLine); - continue; - } - QString strStartIP = IPs.at(0).trimmed(); - QString strEndIP = IPs.at(1).trimmed(); - // Check IPs format (IPv4 only) - if(strStartIP.contains(is_ipv4) && strEndIP.contains(is_ipv4)) { - // IPv4 - IP = strStartIP.split('.'); - address_v4 start((IP.at(0).toUInt() << 24) + (IP.at(1).toUInt() << 16) + (IP.at(2).toUInt() << 8) + IP.at(3).toUInt()); - IP = strEndIP.split('.'); - address_v4 last((IP.at(0).toUInt() << 24) + (IP.at(1).toUInt() << 16) + (IP.at(2).toUInt() << 8) + IP.at(3).toUInt()); - // Apply to bittorrent session - filter.add_rule(start, last, ip_filter::blocked); - } else { - qDebug("p2p file: line %d is malformed.", nbLine); - continue; - } + if(startAddr.is_v4() != endAddr.is_v4()) { + qDebug("Ipfilter.dat: line %d is malformed.", nbLine); + qDebug("One IP is IPv4 and the other is IPv6!"); + continue; + } + + // Check if there is an access value (apparently not mandatory) + int nbAccess = 0; + if(nbElem > 1) { + // There is possibly one + nbAccess = partsList.at(1).trimmed().toInt(); + } + + if(nbAccess > 127) { + // Ignoring this rule because access value is too high + continue; + } + // Now Add to the filter + try { + filter.add_rule(startAddr, endAddr, ip_filter::blocked); + }catch(exception){ + qDebug("Bad line in filter file, avoided crash..."); } - file.close(); } + file.close(); } - - int getlineInStream(QDataStream& stream, string& name, char delim) { - char c; - int total_read = 0; - int read; - do { - read = stream.readRawData(&c, 1); - total_read += read; - if(read > 0) { - if(c != delim) { - name += c; - } else { - // Delim found - return total_read; - } + } + + // Parser for PeerGuardian ip filter in p2p format + void parseP2PFilterFile(QString filePath) { + QFile file(filePath); + QStringList IP; + if (file.exists()){ + if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ + std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl; + return; + } + unsigned int nbLine = 0; + while (!file.atEnd() && !abort) { + ++nbLine; + QByteArray line = file.readLine().trimmed(); + if(line.isEmpty()) continue; + // Ignoring commented lines + if(line.startsWith('#') || line.startsWith("//")) continue; + // Line is splitted by : + QList partsList = line.split(':'); + if(partsList.size() < 2){ + qDebug("p2p file: line %d is malformed.", nbLine); + continue; } - } while(read > 0); - return total_read; - } - - // Parser for PeerGuardian ip filter in p2p format - void parseP2BFilterFile(QString filePath) { - QFile file(filePath); - if (file.exists()){ - if(!file.open(QIODevice::ReadOnly)){ - std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl; - return; + // Get IP range + QList IPs = partsList.last().split('-'); + if(IPs.size() != 2) { + qDebug("p2p file: line %d is malformed.", nbLine); + qDebug("line was: %s", line.constData()); + continue; } - QDataStream stream(&file); - // Read header - char buf[7]; - unsigned char version; - if( - !stream.readRawData(buf, sizeof(buf)) || - memcmp(buf, "\xFF\xFF\xFF\xFFP2B", 7) || - !stream.readRawData((char*)&version, sizeof(version)) - ) { - std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl; - return; + boost::system::error_code ec; + QString strStartIP = IPs.at(0).trimmed(); + libtorrent::address startAddr = libtorrent::address::from_string(qPrintable(strStartIP), ec); + if(ec) { + qDebug("p2p file: line %d is malformed.", nbLine); + qDebug("Start IP is invalid: %s", qPrintable(strStartIP)); + continue; } - - if(version==1 || version==2) { - qDebug ("p2b version 1 or 2"); - unsigned int start, end; - - string name; - while(getlineInStream(stream, name, '\0') && !abort) { - if( + QString strEndIP = IPs.at(1).trimmed(); + libtorrent::address endAddr = libtorrent::address::from_string(qPrintable(strEndIP), ec); + if(ec) { + qDebug("p2p file: line %d is malformed.", nbLine); + qDebug("End IP is invalid: %s", qPrintable(strStartIP)); + continue; + } + if(startAddr.is_v4() != endAddr.is_v4()) { + qDebug("p2p file: line %d is malformed.", nbLine); + qDebug("Line was: %s", line.constData()); + continue; + } + try { + filter.add_rule(startAddr, endAddr, ip_filter::blocked); + } catch(std::exception&) { + qDebug("p2p file: line %d is malformed.", nbLine); + qDebug("Line was: %s", line.constData()); + continue; + } + } + file.close(); + } + } + + int getlineInStream(QDataStream& stream, string& name, char delim) { + char c; + int total_read = 0; + int read; + do { + read = stream.readRawData(&c, 1); + total_read += read; + if(read > 0) { + if(c != delim) { + name += c; + } else { + // Delim found + return total_read; + } + } + } while(read > 0); + return total_read; + } + + // Parser for PeerGuardian ip filter in p2p format + void parseP2BFilterFile(QString filePath) { + QFile file(filePath); + if (file.exists()){ + if(!file.open(QIODevice::ReadOnly)){ + std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl; + return; + } + QDataStream stream(&file); + // Read header + char buf[7]; + unsigned char version; + if( + !stream.readRawData(buf, sizeof(buf)) || + memcmp(buf, "\xFF\xFF\xFF\xFFP2B", 7) || + !stream.readRawData((char*)&version, sizeof(version)) + ) { + std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl; + return; + } + + if(version==1 || version==2) { + qDebug ("p2b version 1 or 2"); + unsigned int start, end; + + string name; + while(getlineInStream(stream, name, '\0') && !abort) { + if( !stream.readRawData((char*)&start, sizeof(start)) || !stream.readRawData((char*)&end, sizeof(end)) - ) { - std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl; - return; - } - // Network byte order to Host byte order - // asio address_v4 contructor expects it - // that way - address_v4 first(ntohl(start)); - address_v4 last(ntohl(end)); - // Apply to bittorrent session - filter.add_rule(first, last, ip_filter::blocked); - } - } - else if(version==3) { - qDebug ("p2b version 3"); - unsigned int namecount; - if(!stream.readRawData((char*)&namecount, sizeof(namecount))) { + ) { std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl; return; } - namecount=ntohl(namecount); - // Reading names although, we don't really care about them - for(unsigned int i=0; iget_ip_filter(); - if(isRunning()) { - // Already parsing a filter, abort first - abort = true; - wait(); - } - abort = false; - filePath = _filePath; - // Run it - start(); + } + + // Process ip filter file + // Supported formats: + // * eMule IP list (DAT): http://wiki.phoenixlabs.org/wiki/DAT_Format + // * PeerGuardian Text (P2P): http://wiki.phoenixlabs.org/wiki/P2P_Format + // * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format + void processFilterFile(QString _filePath){ + // First, import current filter + filter = s->get_ip_filter(); + if(isRunning()) { + // Already parsing a filter, abort first + abort = true; + wait(); } + abort = false; + filePath = _filePath; + // Run it + start(); + } - static void processFilterList(session *s, QStringList IPs) { - // First, import current filter - ip_filter filter = s->get_ip_filter(); - foreach(const QString &ip, IPs) { - qDebug("Manual ban of peer %s", ip.toLocal8Bit().constData()); - boost::system::error_code ec; - address_v4 addr = address_v4::from_string(ip.toLocal8Bit().constData(), ec); - Q_ASSERT(!ec); - if(!ec) - filter.add_rule(addr, addr, ip_filter::blocked); - } - s->set_ip_filter(filter); + static void processFilterList(session *s, QStringList IPs) { + // First, import current filter + ip_filter filter = s->get_ip_filter(); + foreach(const QString &ip, IPs) { + qDebug("Manual ban of peer %s", ip.toLocal8Bit().constData()); + boost::system::error_code ec; + address_v4 addr = address_v4::from_string(ip.toLocal8Bit().constData(), ec); + Q_ASSERT(!ec); + if(!ec) + filter.add_rule(addr, addr, ip_filter::blocked); } + s->set_ip_filter(filter); + } }; diff --git a/src/properties/peeraddition.h b/src/properties/peeraddition.h index 320ad9161..33e29c69f 100644 --- a/src/properties/peeraddition.h +++ b/src/properties/peeraddition.h @@ -34,6 +34,7 @@ #include #include #include +#include #include "ui_peer.h" #include @@ -70,16 +71,15 @@ public: libtorrent::asio::ip::tcp::endpoint ep; PeerAdditionDlg dlg; if(dlg.exec() == QDialog::Accepted) { - const QRegExp is_ipv6(QString::fromUtf8("[0-9a-f]{4}(:[0-9a-f]{4}){7}"), Qt::CaseInsensitive, QRegExp::RegExp); - const QRegExp is_ipv4(QString::fromUtf8("(([0-1]?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))(\\.(([0-1]?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))){3}"), Qt::CaseInsensitive, QRegExp::RegExp); - QString IP = dlg.getIP(); - if(is_ipv4.exactMatch(IP)) { - // IPv4 - ep = libtorrent::asio::ip::tcp::endpoint(libtorrent::asio::ip::address_v4::from_string(IP.toLocal8Bit().data()), dlg.getPort()); - } else { - // IPv6 - ep = libtorrent::asio::ip::tcp::endpoint(libtorrent::asio::ip::address_v6::from_string(IP.toLocal8Bit().data()), dlg.getPort()); + QString ip = dlg.getIP(); + boost::system::error_code ec; + libtorrent::address addr = libtorrent::address::from_string(qPrintable(ip), ec); + if(ec) { + qDebug("Unable to parse the provided IP: %s", qPrintable(ip)); + return ep; } + qDebug("Provided IP is correct"); + ep = libtorrent::asio::ip::tcp::endpoint(addr, dlg.getPort()); } return ep; } @@ -87,21 +87,13 @@ public: protected slots: void validateInput() { - const QRegExp is_ipv6(QString::fromUtf8("[0-9a-f]{4}(:[0-9a-f]{4}){7}"), Qt::CaseInsensitive, QRegExp::RegExp); - const QRegExp is_ipv4(QString::fromUtf8("(([0-1]?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))(\\.(([0-1]?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))){3}"), Qt::CaseInsensitive, QRegExp::RegExp); - QString IP = getIP(); - if(is_ipv4.exactMatch(IP)) { - qDebug("Detected IPv4 address: %s", IP.toLocal8Bit().data()); - accept(); + QHostAddress ip(getIP()); + if(ip.isNull()) { + QMessageBox::warning(this, tr("Invalid IP"), + tr("The IP you provided is invalid."), + QMessageBox::Ok); } else { - if(is_ipv6.exactMatch(IP)) { - qDebug("Detected IPv6 address: %s", IP.toLocal8Bit().data()); - accept(); - } else { - QMessageBox::warning(this, tr("Invalid IP"), - tr("The IP you provided is invalid."), - QMessageBox::Ok); - } + accept(); } } };