#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), actId(0) { } /** * Proxifier class */ Proxifier* Proxifier::GetInstance() { if (instance == NULL) { instance = new Proxifier; } return instance; } Proxifier::Proxifier(): valid(false) { filename = "Default.ppx"; ReadConfig(); } bool Proxifier::IsValid() { return valid; } void Proxifier::ReadConfig() { valid = false; QDomDocument configDom("config"); QFile config(filename); 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 (!ReadProxyList(root)) { Logger::Fatal("Invalid Proxifier configuration file!"); return; } // parse chain list if (!ReadChainList(root)) { Logger::Fatal("Invalid Proxifier configuration file!"); return; } // parse rule list if (!ReadRuleList(root)) { Logger::Fatal("Invalid Proxifier configuration file!"); 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 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 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; } int max = 100; // first default proxifier ID for (unsigned i = 0; i < proxyList.size(); i++) { if (proxyList[i].id > max) { max = proxyList[i].id; } } for (unsigned i = 0; i < chainList.size(); i++) { if (chainList[i].id > max) { max = chainList[i].id; } } return max; } bool Proxifier::AddProxy(Proxy& proxy, int* id) { Logger::Trace("Adding new proxy to Proxifier configuration\n"); if (!valid) { Logger::Error("Current Proxifier configuration is not valid. Update first!\n"); return false; } QDomDocument configDom("config"); QFile config(filename); if (!config.open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier configuration file\n"); return false; } if (!configDom.setContent(&config)) { Logger::Fatal("Invalid Proxifier configuration file!"); return false; } QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier configuration file!"); 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); QTextStream(&config) << configDom.toString(indent); config.close(); return true; } bool Proxifier::AddChain(string& name, int *id) { QDomDocument configDom("config"); QFile config(filename); if (!config.open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier configuration file\n"); return false; } if (!configDom.setContent(&config)) { Logger::Fatal("Invalid Proxifier configuration file!"); return false; } QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier configuration file!"); 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); QTextStream(&config) << configDom.toString(indent); config.close(); return true; } bool Proxifier::AddChainProxy(int proxyId, int chainId) { QDomDocument configDom("config"); QFile config(filename); if (!config.open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier configuration file\n"); return false; } if (!configDom.setContent(&config)) { Logger::Fatal("Invalid Proxifier configuration file!"); return false; } QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier configuration file!"); 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); chainElem.appendChild(proxyElem); break; } } QTextStream(&config) << configDom.toString(indent); config.close(); return true; } bool Proxifier::RemoveChainProxy(int proxyId, int chainId) { QDomDocument configDom("config"); QFile config(filename); if (!config.open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier configuration file\n"); return false; } if (!configDom.setContent(&config)) { Logger::Fatal("Invalid Proxifier configuration file!"); return false; } QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier configuration file!"); 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; } } break; } } QTextStream(&config) << configDom.toString(indent); config.close(); return true; } bool Proxifier::AddRule(Rule& rule) { QDomDocument configDom("config"); QFile config(filename); if (!config.open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier configuration file\n"); return false; } if (!configDom.setContent(&config)) { Logger::Fatal("Invalid Proxifier configuration file!"); return false; } QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier configuration file!"); 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("Applications"); QDomText targetsTxt = configDom.createTextNode(QString::fromLocal8Bit(rule.targets.c_str())); targetsElem.appendChild(targetsTxt); ruleElem.appendChild(targetsElem); } // ports element if (! rule.targets.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 portsTxt = configDom.createTextNode(actionId); } ruleElem.appendChild(actionElem); QTextStream(&config) << configDom.toString(indent); config.close(); return true; } bool Proxifier::RemoveRule(string name) { // !names only compared! QDomDocument configDom("config"); QFile config(filename); if (!config.open(QIODevice::WriteOnly)) { Logger::Error("Can't open Proxifier configuration file\n"); return false; } if (!configDom.setContent(&config)) { Logger::Fatal("Invalid Proxifier configuration file!"); return false; } QDomElement root = configDom.documentElement(); if (root.tagName() != "ProxifierProfile") { Logger::Error("Invalid Proxifier configuration file!"); return false; } QDomElement ruleListElem = root.firstChildElement("ChainList"); 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; } } QTextStream(&config) << configDom.toString(indent); config.close(); return true; }