#include #ifdef WIN32 #include #include #include #endif #include #include #include "UpdatedConfig.h" #include "Logger.h" #include "Proxifier.h" #include "Utility.h" // static field initialization string Proxifier::defaultChain = "Client"; string Proxifier::defaultRule = "Default"; string Proxifier::firewallRule = "Firewall"; Proxifier* Proxifier::instance = NULL; Proxifier::ProxifierProxy::ProxifierProxy(): id(0), option(0), emptyAuth(true) { } Proxifier::Chain::Chain(): id(0) { } Proxifier::Rule::Rule(): isEnabled(false), actId(0) { } /** * Proxifier class */ Proxifier* Proxifier::GetInstance() { if (instance == NULL) { instance = new Proxifier; } return instance; } Proxifier::Proxifier(): valid(false) { Logger::Info("Trying to find proxifier configuration file\n"); // check variable from config file UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); if (! cfg->ProxifierConfigFile.empty()) { Logger::Info("Checking path: %s\n", cfg->ProxifierConfigFile.c_str()); QFileInfo filePathInfo(QString::fromLocal8Bit(cfg->ProxifierConfigFile.c_str())); if (filePathInfo.exists()) { Logger::Debug("Configuration found: %s\n", cfg->ProxifierConfigFile.c_str()); filePath = filePathInfo.absoluteFilePath(); ReadConfig(); return; } } #ifdef WIN32 QString folderName = "Proxifier"; QString fileName = "Profiles\\Default.ppx"; QString pathSlash = "\\"; // check in %USERPROFILE%\AppData\Roaming TCHAR dataPath[MAX_PATH]; if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, dataPath) != S_FALSE) { char* str = wstrdup(dataPath); QString file = str; file += pathSlash + folderName + pathSlash + fileName; Logger::Info("Checking path: %s\n", file.toStdString().c_str()); QFileInfo filePathInfo(file); if (filePathInfo.exists()) { Logger::Debug("Configuration found: %s\n", file.toStdString().c_str()); filePath = filePathInfo.absoluteFilePath(); ReadConfig(); return; } } if (SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, 0, dataPath) != S_FALSE) { // check in %ProgramFiles(x86)% char* str = wstrdup(dataPath); QString file = str; file += pathSlash + folderName + pathSlash + fileName; QFileInfo filePathInfo(file); Logger::Info("Checking path: %s\n", file.toStdString().c_str()); if (filePathInfo.exists()) { filePath = filePathInfo.absoluteFilePath(); ReadConfig(); return; } } filePath = fileName; /* // check in %ProgramFiles% (x86) char *sysDrive = getenv ("SystemDrive"); if (sysDrive != NULL) { fprintf(stderr, "system drive: %s\n", sysDrive); } */ #endif filePath = "Default.ppx"; ReadConfig(); } bool Proxifier::ReloadConfig() { #ifdef WIN32 char execName[] = "Proxifier.exe"; QString program; QStringList args; UpdatedConfig *cfg = UpdatedConfig::CurrentConfig(); if (! cfg->ProxifierExeFile.empty()) { program = QString::fromLocal8Bit(cfg->ProxifierExeFile.c_str()); QFileInfo filePathInfo(program); if (! filePathInfo.exists()) { return false; } } else { //try to find Proxifier.exe on my own QString folderName = "Proxifier"; QString pathSlash = "\\"; TCHAR programFiles[MAX_PATH]; if (SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, 0, programFiles) == S_FALSE) { return false; } // check in %ProgramFiles(x86)% char *str = wstrdup(programFiles); program = str; program += pathSlash + folderName + pathSlash + execName; program.prepend("\""); program.append("\""); QFileInfo filePathInfo(program); if (filePathInfo.exists()) { return false; } } if (filePath.isEmpty()) { return false; } Logger::Trace("Starting process: %s\n", program.toStdString().c_str()); args << filePath << "silent-load"; return QProcess::startDetached(program, args); #else return false; #endif } bool Proxifier::IsValid() { return valid; } bool Proxifier::IsOn(string& addr, short port) { // at first proxy should be in proxy list int proxyId = 0; if (!isProxyExists(addr, port, &proxyId)) { return false; } // next - check for "Client" chain int chainId; if (!isChainExists(defaultChain, &chainId)) { return false; } // and next - find chain by id for (unsigned i = 0; chainList.size(); i++) { if (chainList[i].id == chainId) { map::iterator it = chainList[i].proxies.find(proxyId); if (it == chainList[i].proxies.end()) { return false; } return it->second; } } return false; } vector Proxifier::GetActiveProxies() { vector result; // check for Client chain int chainId = 0; if (!isChainExists(defaultChain, &chainId)) { return result; } /** * @todo check if Client chain is enabled */ // find proxies in the chain for (unsigned i = 0; i < chainList.size(); i++) { if (chainList[i].name.compare(defaultChain) != 0) { continue; } map::iterator it = chainList[i].proxies.begin(); for ( ; it != chainList[i].proxies.end(); it++) { if (!it->second) { continue; } for (unsigned i = 0; i < proxyList.size(); i++) { if (proxyList[i].id != it->first) { continue; } Proxy proxy; proxy.login = proxyList[i].login; proxy.password = proxyList[i].password; proxy.host = proxyList[i].host; proxy.port = proxyList[i].port; proxy.type = proxyList[i].type; result.push_back(proxy); } } } return result; } bool Proxifier::TurnProxyOn(Proxy& proxy) { if (!valid) { return false; } // if proxy do not exist - add it int proxyId = 0; if (!isProxyExists(proxy.host, proxy.port, &proxyId)) { ProxifierProxy _proxy; _proxy.login = proxy.login; _proxy.password = proxy.password; _proxy.host = proxy.host; _proxy.port = proxy.port; _proxy.type = proxy.type; // default values for Proxifier Proxy record _proxy.option = 0; _proxy.useAuth = !proxy.login.empty(); _proxy.emptyAuth = false; if (!AddProxy(_proxy, &proxyId)) { return false; } } // if "Client" chain do not exist - add it int chainId = 0; if (!isChainExists(defaultChain, &chainId)) { if (!AddChain(defaultChain, &chainId)) { return false; } } // try to find proxy in chain for (unsigned i = 0; i < chainList.size(); i++) { if (chainList[i].name.compare(defaultChain) != 0) { continue; } map::iterator it = chainList[i].proxies.find(proxyId); if (it != chainList[i].proxies.end()) { if (!it->second) { // proxy is not enabled - remove it and add again RemoveProxyFromChain(proxyId, chainId); bool isHttp = (stricmp(proxy.type.c_str(), "http") == 0); AddProxyToChain(proxyId, chainId, isHttp); } } else { // proxy not found in the target chain - add it bool isHttp = (stricmp(proxy.type.c_str(), "http") == 0); AddProxyToChain(proxyId, chainId, isHttp); } } if (isRuleExists(defaultRule)) { // the "Default" rule can't be disabled from Proxifier's UI // so we can skip this check here Logger::Debug("Changing default rule action\n"); string action = "Chain"; if (!SetRuleAction(defaultRule, action, chainId)) { return false; } } else { Rule rule; rule.isEnabled = true; rule.name = defaultRule; rule.action = "Chain"; rule.actId = chainId; if (!AddRule(rule)) { return false; } } return true; } bool Proxifier::TurnProxyOff(Proxy& proxy) { if (!valid) { return false; } // check if proxy do not exist int proxyId = 0; if (!isProxyExists(proxy.host, proxy.port, &proxyId)) { return true; } int chainId = 0; if (!isChainExists(defaultChain, &chainId)) { return true; } // try to find proxy in chain for (unsigned i = 0; i < chainList.size(); i++) { if (chainList[i].name.compare(defaultChain) != 0) { continue; } map::iterator it = chainList[i].proxies.find(proxyId); if (it != chainList[i].proxies.end()) { // if it was the last proxy in chain - change default rule if (chainList[i].proxies.size() == 1) { string action = "Direct"; SetRuleAction(defaultRule, action); } RemoveProxyFromChain(proxyId, chainId); RemoveProxy(proxyId); // update config to reflect last changes ReadConfig(); break; } } return true; } bool Proxifier::ApplyFirewallRules(vector rules) { Logger::Trace("Applying new firewall list\n"); if (! RemoveRule(firewallRule)) { return false; } Rule _rule; _rule.isEnabled = true; _rule.name = firewallRule; _rule.apps = ""; _rule.ports = ""; _rule.action = "Block"; for (unsigned i = 0; i < rules.size(); i++) { _rule.targets.append(rules[i].host); _rule.targets.append(";"); } if (! AddRule(_rule)) { return false; } return true; } void Proxifier::ReadConfig() { valid = false; QDomDocument configDom("config"); QFile config(filePath); if (!config.open(QIODevice::ReadOnly)) { Logger::Error("Can't open Proxifier config file\n"); return; } if (!configDom.setContent(&config)) { Logger::Fatal("Invalid Proxifier config file!\n"); return; } QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Fatal("Invalid Proxifier config file!\n"); return; } QDomElement options = root.firstChildElement("Options"); /** * @todo process Options if needed */ // parse proxy list if (!ReadProxyList(root)) { Logger::Fatal("Invalid Proxifier config file!\n"); return; } // parse chain list if (!ReadChainList(root)) { Logger::Fatal("Invalid Proxifier configfile!\n"); return; } // parse rule list if (!ReadRuleList(root)) { Logger::Fatal("Invalid Proxifier config file!\n"); return; } config.close(); valid = true; } bool Proxifier::ReadProxyList(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 ProxifierProxy 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 Logger::Trace("Auth section is empty\n"); 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 not present\n"); proxyRecord.useAuth = false; } 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::ReadChainList(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::ReadRuleList(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 actIdTxt = actionElem.text(); ruleRecord.actId = actIdTxt.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; } int Proxifier::GetNextId() { if (!valid) { return -1; } // acquire all IDs, sort them and return max or spare vector ids; for (unsigned i = 0; i < proxyList.size(); i++) { ids.push_back(proxyList[i].id); } for (unsigned i = 0; i < chainList.size(); i++) { ids.push_back(chainList[i].id); } if (ids.size() == 0) { // return default id if there is no one present return 100; } sort(ids.begin(), ids.end()); int last = ids[0]; for (unsigned i = 0; i < ids.size(); i++) { if (ids[i] - last > 1) { return last + 1; } last = ids[i]; } return last + 1; } bool Proxifier::AddProxy(ProxifierProxy& proxy, int* id) { Logger::Trace("Adding new proxy to Proxifier config\n"); // read XML DOM structure QDomDocument configDom("config"); QFile* config = new QFile(filePath); if (!config->open(QIODevice::ReadOnly)) { Logger::Error("Can't open Proxifier config file for reading\n"); return false; } if (!configDom.setContent(config)) { Logger::Fatal("Invalid Proxifier config file!\n"); return false; } config->close(); delete config; QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier config file!\n"); return false; } QDomElement proxyListElem = root.firstChildElement("ProxyList"); if (proxyListElem.isNull()) { return false; } // create proxy record // root element QDomElement proxyElem = configDom.createElement("Proxy"); *id = GetNextId(); if (*id == -1) { Logger::Error("Can't get valid ID number!\n"); return false; } proxyElem.setAttribute("id", *id); proxyElem.setAttribute("type", QString::fromLocal8Bit(proxy.type.c_str())); // address element QDomElement addrElem = configDom.createElement("Address"); QDomText addrTxt = configDom.createTextNode(QString::fromLocal8Bit(proxy.host.c_str())); addrElem.appendChild(addrTxt); proxyElem.appendChild(addrElem); // port element QDomElement portElem = configDom.createElement("Port"); QString portStr; QDomText portTxt = configDom.createTextNode(portStr.setNum(proxy.port)); portElem.appendChild(portTxt); proxyElem.appendChild(portElem); // option element QDomElement optsElem = configDom.createElement("Options"); QString optsStr; QDomText optsTxt = configDom.createTextNode(optsStr.setNum(proxy.option)); optsElem.appendChild(optsTxt); proxyElem.appendChild(optsElem); // auth element if (proxy.useAuth) { QDomElement authElem = configDom.createElement("Authentication"); authElem.setAttribute("enabled", "true"); if (!proxy.emptyAuth) { // username QDomElement userElem = configDom.createElement("Username"); QDomText userTxt = configDom.createTextNode(QString::fromLocal8Bit(proxy.login.c_str())); userElem.appendChild(userTxt); authElem.appendChild(userElem); // password QDomElement passElem = configDom.createElement("Password"); QDomText passTxt = configDom.createTextNode(QString::fromLocal8Bit(proxy.password.c_str())); passElem.appendChild(passTxt); authElem.appendChild(passElem); } proxyElem.appendChild(authElem); } proxyListElem.appendChild(proxyElem); // update state to reflect all the changes ReadProxyList(root); // save new DOM to file config = new QFile(filePath); if (!config->open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier config file for writing\n"); return false; } QTextStream(config) << configDom.toString(indent); config->close(); delete config; return true; } bool Proxifier::RemoveProxy(int proxyId) { Logger::Trace("Adding new proxy to Proxifier config\n"); // read XML DOM structure QDomDocument configDom("config"); QFile* config = new QFile(filePath); if (!config->open(QIODevice::ReadOnly)) { Logger::Error("Can't open Proxifier config file for reading\n"); return false; } if (!configDom.setContent(config)) { Logger::Fatal("Invalid Proxifier config file!\n"); return false; } config->close(); delete config; QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier config file!\n"); return false; } QDomElement proxyListElem = root.firstChildElement("ProxyList"); if (proxyListElem.isNull()) { return false; } // find proxy record QDomElement proxyElem = proxyListElem.firstChildElement("Proxy"); while (!proxyElem.isNull()) { bool ok; if (!proxyElem.hasAttribute("id")) { Logger::Error("Invalid Proxy entry\n"); proxyElem = proxyElem.nextSiblingElement("Proxy"); continue; } QString idStr = proxyElem.attribute("id"); int id = idStr.toInt(&ok); if (!ok) { Logger::Error("Invalid Proxy entry\n"); proxyElem = proxyElem.nextSiblingElement("Proxy"); continue; } if (id == proxyId) { proxyListElem.removeChild(proxyElem); break; } proxyElem = proxyElem.nextSiblingElement("Proxy"); } // update state to reflect all the changes ReadProxyList(root); // save new DOM to file config = new QFile(filePath); if (!config->open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier config file for writing\n"); return false; } QTextStream(config) << configDom.toString(indent); config->close(); delete config; return true; } bool Proxifier::AddChain(string& name, int *id) { Logger::Trace("Adding new chain to Proxifier config\n"); // read XML DOM structure QDomDocument configDom("config"); QFile* config = new QFile(filePath); if (!config->open(QIODevice::ReadOnly)) { Logger::Error("Can't open Proxifier config file\n"); return false; } if (!configDom.setContent(config)) { Logger::Fatal("Invalid Proxifier config file!\n"); return false; } config->close(); delete config; QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier config file!\n"); return false; } QDomElement chainListElem = root.firstChildElement("ChainList"); if (chainListElem.isNull()) { return false; } QDomElement chainElem = configDom.createElement("Chain"); *id = GetNextId(); if (*id == -1) { Logger::Error("Can't get valid ID number!\n"); return false; } chainElem.setAttribute("id", *id); QDomElement nameElem = configDom.createElement("Name"); QDomText nameTxt = configDom.createTextNode(QString::fromLocal8Bit(name.c_str())); nameElem.appendChild(nameTxt); chainElem.appendChild(nameElem); chainListElem.appendChild(chainElem); // update state to reflect all the changes ReadChainList(root); // save new DOM to file config = new QFile(filePath); if (!config->open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier config file for writing\n"); return false; } QTextStream(config) << configDom.toString(indent); config->close(); delete config; return true; } bool Proxifier::AddProxyToChain(int proxyId, int chainId, bool isHttp) { Logger::Trace("Adding proxy to chain in Proxifier config\n"); // read XML DOM structure QDomDocument configDom("config"); QFile* config = new QFile(filePath); if (!config->open(QIODevice::ReadOnly)) { Logger::Error("Can't open Proxifier config file\n"); return false; } if (!configDom.setContent(config)) { Logger::Fatal("Invalid Proxifier config file!\n"); return false; } config->close(); delete config; QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier config file!\n"); return false; } QDomElement chainListElem = root.firstChildElement("ChainList"); if (chainListElem.isNull()) { return false; } QDomElement chainElem = chainListElem.firstChildElement("Chain"); while (!chainElem.isNull()) { bool ok; if (!chainElem.hasAttribute("id")) { Logger::Error("Invalid Chain entry\n"); chainElem = chainElem.nextSiblingElement("Chain"); continue; } QString idStr = chainElem.attribute("id"); int id = idStr.toInt(&ok); if (!ok) { Logger::Error("Invalid Chain id\n"); chainElem = chainElem.nextSiblingElement("Chain"); continue; } if (id == chainId) { // chain found => add proxy QDomElement proxyElem = configDom.createElement("Proxy"); proxyElem.setAttribute("enabled", "true"); QString idTxt; idTxt.setNum(proxyId); QDomText nameTxt = configDom.createTextNode(idTxt); proxyElem.appendChild(nameTxt); // append Http proxies to then end, but prepend other ones if (isHttp) { chainElem.appendChild(proxyElem); } else { // first child is 'Name' chainElem.insertAfter(proxyElem, chainElem.firstChildElement()); } break; } } // update state to reflect all the changes ReadChainList(root); // save new DOM to file config = new QFile(filePath); if (!config->open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier config file for writing\n"); return false; } QTextStream(config) << configDom.toString(indent); config->close(); delete config; return true; } bool Proxifier::RemoveProxyFromChain(int proxyId, int chainId) { Logger::Trace("Removing proxy from chain in Proxifier config\n"); // read XML DOM structure QDomDocument configDom("config"); QFile* config = new QFile(filePath); if (!config->open(QIODevice::ReadOnly)) { Logger::Error("Can't open Proxifier configuration file\n"); return false; } if (!configDom.setContent(config)) { Logger::Fatal("Invalid Proxifier configuration file!\n"); return false; } config->close(); delete config; QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier configuration file!\n"); return false; } QDomElement chainListElem = root.firstChildElement("ChainList"); if (chainListElem.isNull()) { return false; } QDomElement chainElem = chainListElem.firstChildElement("Chain"); while (!chainElem.isNull()) { bool ok; if (!chainElem.hasAttribute("id")) { Logger::Error("Invalid Chain entry\n"); chainElem = chainElem.nextSiblingElement("Chain"); continue; } QString idStr = chainElem.attribute("id"); int id = idStr.toInt(&ok); if (!ok) { Logger::Error("Invalid Chain id\n"); chainElem = chainElem.nextSiblingElement("Chain"); continue; } if (id == chainId) { // chain found => find proxy QDomElement proxyElem = chainElem.firstChildElement("Proxy"); while (!proxyElem.isNull()) { QString idTxt = proxyElem.text(); int id = idTxt.toInt(); if (id == proxyId) { chainElem.removeChild(proxyElem); break; } // proceed to the next chain proxy proxyElem = proxyElem.nextSiblingElement("Proxy"); } break; } // proceed to the next chain chainElem = chainElem.nextSiblingElement("Chain"); } // update state to reflect all the changes ReadChainList(root); // save new DOM to file config = new QFile(filePath); if (!config->open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier config file for writing\n"); return false; } QTextStream(config) << configDom.toString(indent); config->close(); delete config; return true; } bool Proxifier::AddRule(Rule& rule) { Logger::Trace("Adding rules to Proxifier config\n"); // read XML DOM structure QDomDocument configDom("config"); QFile* config = new QFile(filePath); if (!config->open(QIODevice::ReadOnly)) { Logger::Error("Can't open Proxifier config file\n"); return false; } if (!configDom.setContent(config)) { Logger::Fatal("Invalid Proxifier config file!\n"); return false; } config->close(); delete config; QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier config file!\n"); return false; } QDomElement ruleListElem = root.firstChildElement("RuleList"); if (ruleListElem.isNull()) { return false; } QDomElement ruleElem = configDom.createElement("Rule"); if (rule.isEnabled) { ruleElem.setAttribute("enabled", "true"); } else { ruleElem.setAttribute("enabled", "false"); } // name element QDomElement nameElem = configDom.createElement("Name"); QDomText nameTxt = configDom.createTextNode(QString::fromLocal8Bit(rule.name.c_str())); nameElem.appendChild(nameTxt); ruleElem.appendChild(nameElem); // applications element if (! rule.apps.empty()) { QDomElement appsElem = configDom.createElement("Applications"); QDomText appsTxt = configDom.createTextNode(QString::fromLocal8Bit(rule.apps.c_str())); appsElem.appendChild(appsTxt); ruleElem.appendChild(appsElem); } // targets element if (! rule.targets.empty()) { QDomElement targetsElem = configDom.createElement("Targets"); QDomText targetsTxt = configDom.createTextNode(QString::fromLocal8Bit(rule.targets.c_str())); targetsElem.appendChild(targetsTxt); ruleElem.appendChild(targetsElem); } // ports element if (! rule.ports.empty()) { QDomElement portsElem = configDom.createElement("Ports"); QDomText portsTxt = configDom.createTextNode(QString::fromLocal8Bit(rule.ports.c_str())); portsElem.appendChild(portsTxt); ruleElem.appendChild(portsElem); } // action element if (rule.action.empty()) { Logger::Error("Invalid action value: %s\n", rule.action.c_str()); return false; } QDomElement actionElem = configDom.createElement("Action"); QString actionType = QString::fromLocal8Bit(rule.action.c_str()); actionElem.setAttribute("type", actionType); if ((actionType == "Chain") || (actionType == "Proxy")) { QString actionId; actionId.setNum(rule.actId); QDomText actId = configDom.createTextNode(actionId); actionElem.appendChild(actId); } ruleElem.appendChild(actionElem); // Default rule should be the last one, so we can't just append it to the end, but to the start ruleListElem.insertBefore(ruleElem, ruleListElem.firstChildElement()); // update state to reflect all the changes ReadRuleList(root); // save new DOM to file config = new QFile(filePath); if (!config->open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier config file for writing\n"); return false; } QTextStream(config) << configDom.toString(indent); config->close(); delete config; return true; } bool Proxifier::SetRuleAction(string& name, string& action, int actId) { // !names only compared! Logger::Trace("Setting rule action in Proxifier config\n"); // read XML DOM structure QDomDocument configDom("config"); QFile* config = new QFile(filePath); if (!config->open(QIODevice::ReadWrite)) { Logger::Error("Can't open Proxifier configuration file\n"); return false; } if (!configDom.setContent(config)) { Logger::Fatal("Invalid Proxifier configuration file!\n"); return false; } config->close(); delete config; QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier configuration file!\n"); return false; } QDomElement ruleListElem = root.firstChildElement("RuleList"); if (ruleListElem.isNull()) { return false; } QDomElement ruleElem = ruleListElem.firstChildElement("Rule"); while (!ruleElem.isNull()) { QDomElement nameElem = ruleElem.firstChildElement("Name"); QString nameStr = nameElem.text(); if (nameStr == QString::fromLocal8Bit(name.c_str())) { // remove old QDomElement oldActionElem = ruleElem.firstChildElement("Action"); ruleElem.removeChild(oldActionElem); // add new QDomElement newActionElem = configDom.createElement("Action"); QString actionType = QString::fromLocal8Bit(action.c_str()); newActionElem.setAttribute("type", actionType); if ((actionType == "Chain") || (actionType == "Proxy")) { QString actionId; actionId.setNum(actId); QDomText actId = configDom.createTextNode(actionId); newActionElem.appendChild(actId); } ruleElem.appendChild(newActionElem); break; } // proceed to the next rule ruleElem = ruleElem.nextSiblingElement("Rule"); } // update state to reflect all the changes ReadRuleList(root); // save new DOM to file config = new QFile(filePath); if (!config->open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier config file for writing\n"); return false; } QTextStream(config) << configDom.toString(indent); config->close(); delete config; return true; } bool Proxifier::RemoveRule(string& name) { // !names only compared! Logger::Trace("Removing rule from Proxifier config\n"); // read XML DOM structure QDomDocument configDom("config"); QFile* config = new QFile(filePath); if (!config->open(QIODevice::ReadWrite)) { Logger::Error("Can't open Proxifier configuration file\n"); return false; } if (!configDom.setContent(config)) { Logger::Fatal("Invalid Proxifier configuration file!\n"); return false; } config->close(); delete config; QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier configuration file!\n"); return false; } QDomElement ruleListElem = root.firstChildElement("RuleList"); if (ruleListElem.isNull()) { return false; } QDomElement ruleElem = ruleListElem.firstChildElement("Rule"); while (!ruleElem.isNull()) { QDomElement nameElem = ruleElem.firstChildElement("Name"); QString nameStr = nameElem.text(); if (nameStr == QString::fromLocal8Bit(name.c_str())) { ruleListElem.removeChild(ruleElem); break; } // proceed to the next rule ruleElem = ruleElem.nextSiblingElement("Rule"); } // update state to reflect all the changes ReadRuleList(root); // save new DOM to file config = new QFile(filePath); if (!config->open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier config file for writing\n"); return false; } QTextStream(config) << configDom.toString(indent); config->close(); delete config; return true; } bool Proxifier::isProxyExists(string& addr, short port, int *id) { if (!valid) { return false; } for (unsigned i = 0; i < proxyList.size(); i++) { ProxifierProxy proxy = proxyList[i]; if ((addr.compare(proxy.host) == 0) && (port == proxy.port)) { if (id != NULL) { *id = proxy.id; } return true; } } return false; } bool Proxifier::isChainExists(string& name, int* id) { if (!valid) { return false; } for (unsigned i = 0; i < chainList.size(); i++) { Chain chain = chainList[i]; if (name.compare(chain.name) == 0) { if (id != NULL) { *id = chain.id; } return true; } } return false; } bool Proxifier::isRuleExists(string& name) { if (!valid) { return false; } for (unsigned i = 0; i < ruleList.size(); i++) { Rule rule = ruleList[i]; if (name.compare(rule.name) == 0) { return true; } } return false; }