From f77a7f9a1e282dba6e39f6b7f0685971cfac7747 Mon Sep 17 00:00:00 2001 From: Alex Borisov Date: Mon, 12 Dec 2011 03:57:23 +0200 Subject: Proxifier config parsing --- client/Dialog.cpp | 34 +++--- client/Dialog.h | 4 +- client/Proxifier.cpp | 310 +++++++++++++++++++++++++++++++++++++++++++++++ client/Proxifier.h | 114 +++++++++++++++++ client/Proxy.h | 1 + client/UpdatedConfig.cpp | 2 +- client/client.pro | 8 +- 7 files changed, 453 insertions(+), 20 deletions(-) create mode 100644 client/Proxifier.cpp create mode 100644 client/Proxifier.h diff --git a/client/Dialog.cpp b/client/Dialog.cpp index 4ce48be..dfb280d 100644 --- a/client/Dialog.cpp +++ b/client/Dialog.cpp @@ -5,6 +5,7 @@ #include "client.h" #include "UpdatedConfig.h" #include "Dialog.h" +#include "Proxifier.h" #include "Proxy.h" using namespace std; @@ -12,7 +13,12 @@ using namespace std; ProxyDialog::ProxyDialog(QWidget *parent): QDialog(parent) { UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); - + Proxifier *proxifier = Proxifier::GetInstance(); + if (!proxifier->IsValid()) + { + Logger::Fatal("No valid proxifier configuration file found!\n"); + } + /* generic proxy panel */ topLabel = new QLabel(QString::fromLocal8Bit(cfg->TopPanelText.c_str())); topLabel->setObjectName("topLabel"); @@ -29,14 +35,14 @@ ProxyDialog::ProxyDialog(QWidget *parent): QDialog(parent) countryBox->addItem(country); } countryBox->setCurrentIndex(-1); - + connect(countryBox, SIGNAL(activated(int)), this, SLOT(CountryActivated(int))); connect(stateBox, SIGNAL(activated(int)), this, SLOT(StateActivated(int))); connect(cityBox, SIGNAL(activated(int)), this, SLOT(CityActivated(int))); - + topPanelLayout = new QGridLayout; topPanelLayout->setSpacing(5); topPanelLayout->addWidget(countryBox, 0, 0); @@ -44,7 +50,7 @@ ProxyDialog::ProxyDialog(QWidget *parent): QDialog(parent) topPanelLayout->addWidget(cityBox, 2, 0); genericProxyGroup = new QButtonGroup; staticProxyGroup = new QButtonGroup; - + /* static proxy panel */ bottomLabel = new QLabel(QString::fromLocal8Bit(cfg->BottomPanelText.c_str())); bottomLabel->setObjectName("bottomLabel"); @@ -89,7 +95,7 @@ ProxyDialog::ProxyDialog(QWidget *parent): QDialog(parent) bottomPanelLayout->addWidget(btn, i, j); } } - + /* setup layouting */ QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(topLabel); @@ -106,7 +112,7 @@ void ProxyDialog::StaticToggle(bool val) void ProxyDialog::StaticClick() { - Logger::Debug("click\n"); + Logger::Debug("click\n"); } void ProxyDialog::CountryActivated(int index) @@ -118,10 +124,10 @@ void ProxyDialog::CountryActivated(int index) { return; } - + string country(countryBox->currentText().toLocal8Bit().constData()); Logger::Info("Country %s was selected\n", country.c_str()); - + UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); vector states = cfg->GetStates(country); if (states.empty()) @@ -160,11 +166,11 @@ void ProxyDialog::StateActivated(int index) { return; } - + string country(countryBox->currentText().toLocal8Bit().constData()); string state(stateBox->currentText().toLocal8Bit().constData()); Logger::Info("State %s was selected\n", state.c_str()); - + UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); vector cities = cfg->GetCities(country, state); cityBox->clear(); @@ -185,9 +191,9 @@ void ProxyDialog::CityActivated(int index) { return; } - + vector proxies; - UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); + UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); string country(countryBox->currentText().toLocal8Bit().constData()); string city(cityBox->currentText().toLocal8Bit().constData()); if (stateBox->isVisible()) @@ -199,7 +205,7 @@ void ProxyDialog::CityActivated(int index) { proxies = cfg->GetProxies(country, city); } - + /* delete existing buttons */ if (topPanelLayout->count() != 0) { @@ -210,7 +216,7 @@ void ProxyDialog::CityActivated(int index) delete child->widget(); } } - + Logger::Trace("Adding new buttons\n"); for (unsigned i = 0; i < proxies.size(); i++) { diff --git a/client/Dialog.h b/client/Dialog.h index b2d21d3..e3be343 100644 --- a/client/Dialog.h +++ b/client/Dialog.h @@ -29,7 +29,7 @@ private slots: void CountryActivated(int index); void StateActivated(int index); void CityActivated(int index); - + void StaticToggle(bool toggle); void StaticClick(); private: @@ -43,4 +43,4 @@ private: QLabel *bottomLabel; }; -#endif \ No newline at end of file +#endif diff --git a/client/Proxifier.cpp b/client/Proxifier.cpp new file mode 100644 index 0000000..5ef213d --- /dev/null +++ b/client/Proxifier.cpp @@ -0,0 +1,310 @@ + +#include +#include +#include "Logger.h" +#include "Proxifier.h" + + +Proxifier* Proxifier::instance = NULL; + + +Proxifier::Proxy::Proxy(): port(0), id(0), option(0), emptyAuth(true) +{ +} + + +Proxifier::Chain::Chain(): id(0) +{ +} + + +Proxifier::Rule::Rule(): isEnabled(false), id(0) +{ +} + + +/** + * Proxifier class + */ +Proxifier* Proxifier::GetInstance() +{ + if (instance == NULL) + { + instance = new Proxifier; + } + return instance; +} + +Proxifier::Proxifier(): valid(false) +{ + Update(); +} + +bool Proxifier::IsValid() +{ + return valid; +} + +void Proxifier::Update() +{ + valid = false; + configDom = new QDomDocument("config"); + QFile config("Default.ppx"); + if (!config.open(QIODevice::ReadOnly)) + { + Logger::Error("Can't open Proxifier configuration file\n"); + return; + } + if (!configDom->setContent(&config)) + { + Logger::Fatal("Invalid Proxifier configuration file!"); + return; + } + + QDomElement root = configDom->documentElement(); + if (root.tagName() != "ProxifierProfile") + { + Logger::Fatal("Invalid Proxifier configuration file!"); + return; + } + QDomElement options = root.firstChildElement("Options"); + /** + * @todo process Options if needed + */ + + // parse proxy list + if (!UpdateProxyList(root)) + { + Logger::Fatal("Invalid Proxifier configuration file!"); + return; + } + // parse chain list + if (!UpdateChainList(root)) + { + Logger::Fatal("Invalid Proxifier configuration file!"); + return; + } + // parse rule list + if (!UpdateRuleList(root)) + { + Logger::Fatal("Invalid Proxifier configuration file!"); + return; + } + + valid = true; +} + +bool Proxifier::UpdateProxyList(QDomElement& root) +{ + Logger::Trace("Processing Proxifier proxy list\n"); + QDomElement proxyListElem = root.firstChildElement("ProxyList"); + if (proxyListElem.isNull()) + { + return false; + } + + proxyList.clear(); + QDomElement proxy = proxyListElem.firstChildElement("Proxy"); + while (!proxy.isNull()) + { + bool ok = true; // used when converting values to int + Proxy proxyRecord; + + // check whether attributes are present + if (! (proxy.hasAttribute("id") && proxy.hasAttribute("type"))) + { + Logger::Error("Invalid Proxy entry\n"); + proxy = proxy.nextSiblingElement("Proxy"); + continue; + } + // proxy id + QString id = proxy.attribute("id"); + proxyRecord.id = id.toInt(&ok); + if (!ok) + { + Logger::Error("Invalid Proxy id\n"); + proxy = proxy.nextSiblingElement("Proxy"); + continue; + } + //proxy type + proxyRecord.type = proxy.attribute("type").toStdString(); + // proxy address + QDomElement addrElem = proxy.firstChildElement("Address"); + proxyRecord.host = addrElem.text().toStdString(); + // proxy port + QDomElement portElem = proxy.firstChildElement("Port"); + QString port = portElem.text(); + proxyRecord.port = port.toShort(&ok); + if (!ok) + { + Logger::Error("Invalid Proxy port\n"); + proxy = proxy.nextSiblingElement("Proxy"); + continue; + } + // proxy options + QDomElement optElem = proxy.firstChildElement("Options"); + QString opt = optElem.text(); + proxyRecord.option = opt.toInt(&ok); + if (!ok) + { + Logger::Error("Invalid Proxy option\n"); + continue; + } + // auth section + QDomElement authElem = proxy.firstChildElement("Authentication"); + if (!authElem.isNull()) + { + if (! authElem.hasChildNodes()) + { + // in case if "NTLM + userLogin" = selfclosing auth tag + proxyRecord.emptyAuth = true; + } + else + { + // username + QDomElement userElem = authElem.firstChildElement("Username"); + proxyRecord.login = userElem.text().toStdString(); + // pass + QDomElement passElem = authElem.firstChildElement("Password"); + proxyRecord.password = passElem.text().toStdString(); + } + } + else + { + Logger::Trace("Auth section is empty\n"); + } + Logger::Trace("Found proxy in proxifier config: id=%d\n", proxyRecord.id); + proxyList.push_back(proxyRecord); + + // process next proxy element + proxy = proxy.nextSiblingElement("Proxy"); + } + return true; +} + +bool Proxifier::UpdateChainList(QDomElement& root) +{ + Logger::Trace("Processing Proxifier chain list\n"); + QDomElement chainListElem = root.firstChildElement("ChainList"); + if (chainListElem.isNull()) + { + return false; + } + + chainList.clear(); + QDomElement chain = chainListElem.firstChildElement("Chain"); + while (!chain.isNull()) + { + bool ok; + Chain chainRecord; + + // chain id + if (!chain.hasAttribute("id")) + { + Logger::Error("Invalid Chain entry\n"); + chain = chain.nextSiblingElement("Chain"); + continue; + } + QString id = chain.attribute("id"); + chainRecord.id = id.toInt(&ok); + if (!ok) + { + Logger::Error("Invalid Chain id\n"); + chain = chain.nextSiblingElement("Chain"); + continue; + } + // chain name + QDomElement nameElem = chain.firstChildElement("Name"); + chainRecord.name = nameElem.text().toStdString(); + //chain proxies + QDomElement proxyElem = chain.firstChildElement("Proxy"); + while (!proxyElem.isNull()) + { + Logger::Trace("Processing Chain proxy\n"); + bool isEnabled = false; + QString enAttr = proxyElem.attribute("enabled"); + if (enAttr == "true") + { + isEnabled = true; + } + QString idTxt = proxyElem.text(); + int id = idTxt.toInt(); + chainRecord.proxies[id] = isEnabled; + // proceed to the next chain proxy + proxyElem = proxyElem.nextSiblingElement("Proxy"); + } + Logger::Trace("Found chain in proxifier config: id=%d\n", chainRecord.id); + chainList.push_back(chainRecord); + + // proceed to the next chain + chain = chain.nextSiblingElement("Chain"); + } + return true; +} + +bool Proxifier::UpdateRuleList(QDomElement& root) +{ + Logger::Trace("Processing Proxifier rule list\n"); + QDomElement ruleListElem = root.firstChildElement("RuleList"); + if (ruleListElem.isNull()) + { + return false; + } + + ruleList.clear(); + QDomElement rule = ruleListElem.firstChildElement("Rule"); + while (!rule.isNull()) + { + Rule ruleRecord; + + // rule enabled attr + if (!rule.hasAttribute("enabled")) + { + Logger::Error("Invalid Rule entry\n"); + rule = rule.nextSiblingElement("Rule"); + continue; + } + QString enAttr = rule.attribute("enabled"); + if (enAttr == "true") + { + ruleRecord.isEnabled = true; + } + // rule name + QDomElement nameElem = rule.firstChildElement("Name"); + ruleRecord.name = nameElem.text().toStdString(); + // rule applications + QDomElement appsElem = rule.firstChildElement("Applications"); + if (!appsElem.isNull()) + { + ruleRecord.apps = appsElem.text().toStdString(); + } + // rule targets + QDomElement targetsElem = rule.firstChildElement("Targets"); + if (!targetsElem.isNull()) + { + ruleRecord.targets = targetsElem.text().toStdString(); + } + // rule ports + QDomElement portsElem = rule.firstChildElement("Ports"); + if (!portsElem.isNull()) + { + ruleRecord.ports = targetsElem.text().toStdString(); + } + // rule action + QDomElement actionElem = rule.firstChildElement("Action"); + QString actionTxt = actionElem.attribute("type"); + if ((actionTxt == "Chain") || (actionTxt == "Proxy")) + { + QString idTxt = actionElem.text(); + ruleRecord.id = idTxt.toInt(); + } + ruleRecord.action = actionTxt.toStdString(); + Logger::Trace("Found rule in proxifier config: name=%s\n", ruleRecord.name.c_str()); + ruleList.push_back(ruleRecord); + + // proceed to the next rule + rule = rule.nextSiblingElement("Rule"); + } + + return true; +} diff --git a/client/Proxifier.h b/client/Proxifier.h new file mode 100644 index 0000000..37ea3fd --- /dev/null +++ b/client/Proxifier.h @@ -0,0 +1,114 @@ + + +#ifndef PROXIFIER_CONFIG +#define PROXIFIER_CONFIG + +#include +#include +#include + +using namespace std; + + +class QDomDocument; + +class Proxifier +{ +public: + /** + * @brief class representing Proxifier's proxy setting + */ + class Proxy + { + public: + string login; + string password; + string host; + string type; + short port; + // proxifier-specific fields + int id; + short option; + bool emptyAuth; + + Proxy(); + }; + + /** + * @brief class representing Proxifier's proxy chain + */ + class Chain + { + public: + /** + * @brief chain id + */ + int id; + /** + * @brief chain name + */ + string name; + /** + * @brief associative array of proxies in the chain - [id: isEnabled] + */ + map proxies; + + Chain(); + }; + + class Rule + { + public: + /** + * @brief indicates if the rule is enabled + */ + bool isEnabled; + /** + * @brief rule name + */ + string name; + /** + * @brief list of applications the rule affects + */ + string apps; + /** + * @brief rule targets (list of hosts separeted w ';') + */ + string targets; + /** + * @brief rule ports (e.g.: 80; 8000-9000; 8080) + */ + string ports; + /** + * @brief rule action (one of: 'Direct', 'Block', 'Chain', 'Proxy') + */ + string action; + /** + * @brief action parameter (applicable only to 'Chain' and 'Proxy' actions) + */ + int id; + + Rule(); + }; + + + static Proxifier* GetInstance(); + bool IsValid(); + void Update(); + +private: + static Proxifier *instance; + + bool valid; + QDomDocument *configDom; + vector proxyList; + vector chainList; + vector ruleList; + + Proxifier(); + bool UpdateProxyList(QDomElement& root); + bool UpdateChainList(QDomElement& root); + bool UpdateRuleList(QDomElement& root); +}; + +#endif diff --git a/client/Proxy.h b/client/Proxy.h index 368f2b8..a718353 100644 --- a/client/Proxy.h +++ b/client/Proxy.h @@ -10,6 +10,7 @@ public: std::string login; std::string password; std::string host; + std::string type; short port; Proxy(): port(0) {} diff --git a/client/UpdatedConfig.cpp b/client/UpdatedConfig.cpp index d5b4177..6873d30 100644 --- a/client/UpdatedConfig.cpp +++ b/client/UpdatedConfig.cpp @@ -5,7 +5,7 @@ UpdatedConfig* UpdatedConfig::self = NULL; -UpdatedConfig *UpdatedConfig::CurrentConfig() +UpdatedConfig* UpdatedConfig::CurrentConfig() { if (self == NULL) self = new UpdatedConfig(); diff --git a/client/client.pro b/client/client.pro index ca6abf8..cfdc184 100644 --- a/client/client.pro +++ b/client/client.pro @@ -5,7 +5,7 @@ QMAKE_CXXFLAGS_DEBUG += -DDEBUG -g3 -ggdb -O0 CONFIG += qt debug console warn_on -QT = core gui network +QT = core gui network xml TEMPLATE = app TARGET = client @@ -23,7 +23,8 @@ HEADERS += client.h \ SslClient.h \ FileOpThread.h \ DownloadClient.h \ - Utility.h + Utility.h \ + Proxifier.h SOURCES += Dialog.cpp \ main.cpp \ @@ -35,7 +36,8 @@ SOURCES += Dialog.cpp \ SslClient.cpp \ FileOpThread.cpp \ DownloadClient.cpp \ - Utility.cpp + Utility.cpp \ + Proxifier.cpp OTHER_FILES += -- cgit v1.2.3