resolver.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. #include "cppcodec/base32_rfc4648.hpp"
  2. #include "resolver.h"
  3. #include "funcs.h"
  4. #include "HTTPheaders.h"
  5. #include <QTcpSocket>
  6. #include <QDateTime>
  7. #include <QHostInfo>
  8. #include <QDebug>
  9. #include <QFile>
  10. #ifdef _WIN32
  11. #include <ws2tcpip.h>
  12. #else
  13. #include <arpa/inet.h>
  14. #endif
  15. Resolver::Resolver(const QString& addr, quint16 port, QObject* parent) :
  16. QObject(parent),
  17. m_tcpServer(new QTcpServer),
  18. m_address(addr),
  19. m_port(port)
  20. {
  21. if (!m_tcpServer->listen(m_address, m_port)) {
  22. throw "Server not binded";
  23. }
  24. qDebug().noquote() << "<-" << m_tcpServer->serverAddress().toString() + " : " +
  25. QString::number(m_tcpServer->serverPort()) << "[" + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz") + "]";
  26. connect(m_tcpServer, SIGNAL(newConnection()), this, SLOT(slotNewUser()));
  27. }
  28. void Resolver::closeSocketViaDescriptor(int id)
  29. {
  30. if(m_sockets.contains(id)) {
  31. m_sockets.value(id)->close();
  32. }
  33. }
  34. QSharedPointer<QTcpSocket> Resolver::getSocketViaDescriptor(int id)
  35. {
  36. if (!m_sockets.contains(id)) {
  37. qDebug() << "Resolver::getSocketViaDescriptor: Requested socket not found";
  38. }
  39. return m_sockets.value(id);
  40. }
  41. void Resolver::slotNewUser()
  42. {
  43. if (!m_tcpServer->isListening()) return;
  44. QTcpSocket* clientSocket = m_tcpServer->nextPendingConnection();
  45. int idUserSock = clientSocket->socketDescriptor();
  46. m_sockets.insert(idUserSock, QSharedPointer<QTcpSocket>(clientSocket));
  47. connect (m_sockets.value(idUserSock).data(), SIGNAL(readyRead()), this, SLOT(slotReadyClient()));
  48. connect (m_sockets.value(idUserSock).data(), SIGNAL(disconnected()), this, SLOT(slotClientDisconnected()));
  49. }
  50. void Resolver::slotReadyClient()
  51. {
  52. QTcpSocket* clientSocket = static_cast<QTcpSocket*>(sender());
  53. QString req(clientSocket->readAll());
  54. qDebug().noquote() << "\n->" << clientSocket->peerAddress().toString()
  55. << "[" + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz") + "]";
  56. bool web = req.startsWith("GET /");
  57. QSharedPointer<QTextStream> ts(new QTextStream(clientSocket));
  58. if (web) {
  59. qDebug().noquote() << " └ Via web browser";
  60. if (req.contains("toConverting=")) {
  61. processPage(req, ts, web);
  62. } else {
  63. startPage(ts, web);
  64. }
  65. } else {
  66. req.remove('\r');
  67. req.remove('\n');
  68. qDebug().noquote() << " └ Without web browser";
  69. if (req.contains(":") or req.contains(".")) {
  70. processPage(req, ts, web);
  71. } else {
  72. startPage(ts, web);
  73. }
  74. }
  75. }
  76. void Resolver::slotClientDisconnected()
  77. {
  78. QTcpSocket* clientSocket = static_cast<QTcpSocket*>(sender());
  79. auto idUserSock = clientSocket->socketDescriptor();
  80. m_sockets.remove(idUserSock);
  81. }
  82. void Resolver::convertStrToRaw(const QString &str, Address &array)
  83. {
  84. inet_pton(AF_INET6, str.toUtf8(), (void*)array.data());
  85. }
  86. QString Resolver::getBase32(const Address &rawAddr)
  87. {
  88. return cppcodec::base32_rfc4648::encode(rawAddr.data(), ADDRIPV6_SIZE).c_str();
  89. }
  90. QString Resolver::decodeMeshToIP(const QString &meshname)
  91. {
  92. std::string mesh = pickupStringForMeshname(meshname.toStdString()) + "======"; // 6 паддингов - норма для IPv6 адреса
  93. std::vector<uint8_t> raw;
  94. try {
  95. raw = cppcodec::base32_rfc4648::decode(mesh);
  96. } catch (cppcodec::padding_error) {
  97. return QString();
  98. } catch (cppcodec::symbol_error) {
  99. return QString();
  100. }
  101. Address rawAddr;
  102. for(int i = 0; i < 16; ++i)
  103. rawAddr[i] = raw[i];
  104. return getAddress(rawAddr);
  105. }
  106. std::string Resolver::pickupStringForMeshname(std::string str)
  107. {
  108. bool dot = false;
  109. std::string::iterator delend;
  110. for (auto it = str.begin(); it != str.end(); it++)
  111. {
  112. *it = toupper(*it); // делаем все буквы заглавными для обработки
  113. if(*it == '.') {
  114. delend = it;
  115. dot = true;
  116. }
  117. }
  118. if (dot)
  119. for (auto it = str.end(); it != delend; it--)
  120. str.pop_back(); // удаляем доменную зону
  121. return str;
  122. }
  123. QString Resolver::getAddress(const Address& rawAddr)
  124. {
  125. char ipStrBuf[46];
  126. inet_ntop(AF_INET6, rawAddr.data(), ipStrBuf, 46);
  127. return QString(ipStrBuf);
  128. }
  129. void Resolver::startPage(QSharedPointer<QTextStream> ts, bool web)
  130. {
  131. QTcpSocket* clientSocket = static_cast<QTcpSocket*>(sender());
  132. if (web) {
  133. qDebug().noquote() << " └ Start page";
  134. QString page = http::HTML_PAGE;
  135. QString css = http::CSS_DEFAULT;
  136. css.replace("{{COLOR}}", "gray");
  137. page.replace("{{STYLES}}", css);
  138. page.replace("{{TEXT}}", "<p>Input any domain to resolve or IPv6 to convert to <a href=\"https://github.com/zhoreeq/meshname\" style=\"text-decoration: none\">meship</a>.</p>"
  139. "<p>Also you can use Mario DNS tool via command line (telnet or netcat for example) to get result in JSON. Just pass the value for processing.");
  140. *ts << page;
  141. }
  142. else {
  143. qDebug().noquote() << " └ Incorrect request";
  144. *ts << "{\n"
  145. " \"status\": false,\n"
  146. " \"answer\": \"Push any domain to resolve or IPv6 to convert to meship\"\n"
  147. "}\n";
  148. }
  149. clientSocket->close();
  150. }
  151. void Resolver::startPageWithMessage(const QString & value, QSharedPointer<QTextStream> ts, const QString & msg, bool web)
  152. {
  153. qDebug().noquote() << " └ " + msg;
  154. if (web) {
  155. QString page = http::HTML_PAGE;
  156. QString css = http::CSS_DEFAULT;
  157. css.replace("{{COLOR}}", "red");
  158. page.replace("{{STYLES}}", css);
  159. page.replace("{{TEXT}}", msg);
  160. if (!value.isEmpty()) {
  161. page.replace("placeholder=\"IPv6 address or domain\"", "value=\"" + value + "\"");
  162. }
  163. *ts << page;
  164. }
  165. else {
  166. *ts << "{\n"
  167. " \"status\": false,\n"
  168. " \"answer\": \"" + msg + "\"\n"
  169. "}\n";
  170. }
  171. }
  172. void Resolver::processPage(const QString& req, QSharedPointer<QTextStream> ts, bool web)
  173. {
  174. QTcpSocket* clientSocket = static_cast<QTcpSocket*>(sender());
  175. QString value;
  176. if (web) {
  177. value = funcs::getValue(req, "toConverting");
  178. } else {
  179. value = req;
  180. }
  181. value.remove('+');
  182. value = QByteArray::fromPercentEncoding(value.toUtf8());
  183. qDebug().noquote() << " └ " + value;
  184. const uint8_t MAX_LEN = 60;
  185. if (value.size() > MAX_LEN) {
  186. startPageWithMessage("", ts, "Maximum input value length = " + QString::number(MAX_LEN), web);
  187. }
  188. else if (value.contains(":")) {
  189. toMeship(value, ts, web);
  190. }
  191. else if (value.endsWith(".meship")) {
  192. toIp(value, ts, web);
  193. }
  194. else if (value.contains(".")) {
  195. toRealResolv(value, ts, web);
  196. }
  197. else {
  198. startPageWithMessage(value, ts, "Input value must contains domain or IPv6", web);
  199. }
  200. clientSocket->close();
  201. }
  202. void Resolver::toMeship(const QString & value, QSharedPointer<QTextStream> ts, bool web)
  203. {
  204. Address rawAddr;
  205. convertStrToRaw(value, rawAddr);
  206. QString base32 = getBase32(rawAddr);
  207. base32 = base32.toLower();
  208. base32.remove('=');
  209. base32 += ".meship";
  210. if (web) {
  211. QString page = http::HTML_PAGE;
  212. QString css = http::CSS_DEFAULT;
  213. css.replace("{{COLOR}}", "green");
  214. page.replace("{{STYLES}}", css);
  215. page.replace("{{TEXT}}", base32);
  216. page.replace("placeholder=\"IPv6 address or domain\"", "value=\"" + value + "\"");
  217. *ts << page;
  218. }
  219. else {
  220. *ts << "{\n"
  221. " \"status\": true,\n"
  222. " \"answer\": \"" + base32 + "\"\n"
  223. "}\n";
  224. }
  225. }
  226. void Resolver::toIp(const QString & value, QSharedPointer<QTextStream> ts, bool web)
  227. {
  228. QString result = decodeMeshToIP(value);
  229. if (result.isEmpty()) {
  230. startPageWithMessage(value, ts, "Failed: meship domain must have 26 base32 (RFC4648) characters only", web);
  231. return;
  232. }
  233. if (web) {
  234. QString page = http::HTML_PAGE;
  235. QString css = http::CSS_DEFAULT;
  236. css.replace("{{COLOR}}", "green");
  237. page.replace("{{STYLES}}", css);
  238. page.replace("{{TEXT}}", result);
  239. page.replace("placeholder=\"IPv6 address or domain\"", "value=\"" + value + "\"");
  240. *ts << page;
  241. }
  242. else {
  243. *ts << "{\n"
  244. " \"status\": true,\n"
  245. " \"answer\": \"" + result + "\"\n"
  246. "}\n";
  247. }
  248. }
  249. void Resolver::toRealResolv(const QString & value, QSharedPointer<QTextStream> ts, bool web)
  250. {
  251. QHostInfo host = QHostInfo::fromName(value);
  252. if (host.error() == QHostInfo::NoError) {
  253. auto addrs = host.addresses();
  254. if (web) {
  255. QString addresses;
  256. for (auto a: addrs) {
  257. addresses += a.toString() + "<br>";
  258. }
  259. QString page = http::HTML_PAGE;
  260. QString css = http::CSS_DEFAULT;
  261. css.replace("{{COLOR}}", "green");
  262. page.replace("{{STYLES}}", css);
  263. page.replace("{{TEXT}}", addresses);
  264. page.replace("placeholder=\"IPv6 address or domain\"", "value=\"" + value + "\"");
  265. *ts << page;
  266. }
  267. else {
  268. *ts << "{\n"
  269. " \"status\": true,\n"
  270. " \"answer\": [\n";
  271. for (auto it = addrs.begin(); it != addrs.end(); it++) {
  272. *ts << " \"" + it->toString() + "\"";
  273. if (it+1 != addrs.end()) {
  274. *ts << ",";
  275. }
  276. *ts << "\n";
  277. }
  278. *ts << " ]\n"
  279. "}\n";
  280. }
  281. } else {
  282. QString msg;
  283. if (value.endsWith(".meshname")) {
  284. msg = "Domain not resolved. Try \".meship\" instead \".meshname\" for direct translation to address";
  285. } else {
  286. msg = "Failed: " + host.errorString();
  287. }
  288. startPageWithMessage(value, ts, msg, web);
  289. }
  290. }