diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5ba6751..28acdda 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,6 +18,7 @@ jobs: - uses: actions/checkout@main - name: Install Qt uses: jurplel/install-qt-action@v3 + - uses: ilammy/msvc-dev-cmd@v1 - name: Build ${{ matrix.platform }} shell: bash run: cd CaptiveDNS && qmake && make \ No newline at end of file diff --git a/CaptiveDNS/CaptiveDNS.pro b/CaptiveDNS/CaptiveDNS.pro index 86990df..d44e462 100755 --- a/CaptiveDNS/CaptiveDNS.pro +++ b/CaptiveDNS/CaptiveDNS.pro @@ -64,6 +64,7 @@ FORMS += \ cacheviewer.ui CONFIG += mobility + MOBILITY = DISTFILES += \ diff --git a/CaptiveDNS/dnsserverwindow.cpp b/CaptiveDNS/dnsserverwindow.cpp index 4b4cad7..1945702 100755 --- a/CaptiveDNS/dnsserverwindow.cpp +++ b/CaptiveDNS/dnsserverwindow.cpp @@ -30,12 +30,16 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +Ui::DNSServerWindow* DNSServerWindow::mainUi = NULL; + DNSServerWindow::DNSServerWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::DNSServerWindow) { ui->setupUi(this); qRegisterMetaType("ListEntry"); qRegisterMetaType>("std::vector"); qRegisterMetaType("QHostAddress"); + + DNSServerWindow::mainUi = ui; settingspath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); QDir d{settingspath}; @@ -159,6 +163,39 @@ void DNSServerWindow::listeningIPsUpdate() if(ipslist.size() > 0) { + // sort the ipslist so that the first one is the one we want to respond with + // (eg. prioritize 192.168.x.x over 10.x.x.x, over 172.16.x.x, etc.) + + // sort the list + std::sort(ipslist.begin(), ipslist.end()); + + // check for 10.x.x.x + for (int i = 0; i < ipslist.size(); i++) + { + if((ipslist[i] & 0xFF000000) == 0x0A000000) + { + // move it to the front + ipslist.prepend(ipslist[i]); + ipslist.remove(i+1); + break; + } + } + + // check for 192.168.x.x + for (int i = 0; i < ipslist.size(); i++) + { + if((ipslist[i] & 0xFFFF0000) == 0xC0A80000) + { + // move it to the front + ipslist.prepend(ipslist[i]); + ipslist.remove(i+1); + break; + } + } + + // really, which IP to use should be a choice in the UI + // but for now we'll just use the first one and sort the list + server->listeningIPs = ipslist; } if(ipv6slist.size() > 0) @@ -498,7 +535,6 @@ bool DNSServerWindow::settingsLoad() // blacklist only (allow all non-captive portal domains) server->whitelistmode = false; - on_blacklistButton_clicked(); // no settings, so no initial mode server->initialMode = false; @@ -534,35 +570,7 @@ void DNSServerWindow::on_saveButton_clicked() void DNSServerWindow::on_removeButton_clicked() { - // auto selected = ui->dnslist->selectedItems(); - // for(QTreeWidgetItem *i : selected) - // { - // if(server->whitelistmode) - // { - // for(int x = 0; x < server->whitelist.size(); x++) - // { - // if(i->text(1) == server->whitelist[x].hostname) - // { - // qDebug() << "Removing from whitelist:" << i->text(1); - // server->whitelist.remove(x); - // break; - // } - // } - // } - // else - // { - // for(int x = 0; x < server->blacklist.size(); x++) - // { - // if(i->text(1) == server->blacklist[x].hostname) - // { - // qDebug() << "Removing from blacklist:" << i->text(1); - // server->blacklist.remove(x); - // break; - // } - // } - // } - // } - // qDeleteAll(selected); + // blanked out } void DNSServerWindow::on_hostnameEdit_returnPressed() @@ -578,41 +586,7 @@ void DNSServerWindow::on_ipEdit_returnPressed() void DNSServerWindow::on_secondAddButton_clicked() { bool alreadyAdded = false; - // auto selected = ui->dnsqueries->selectedItems(); - // if(server->whitelistmode) - // { - // for(QTreeWidgetItem *i : selected) - // { - // for(ListEntry &e : server->whitelist) - // { - // if(e.hostname == i->text(1)) - // { - // alreadyAdded = true; - // break; - // } - // } - - // if(!alreadyAdded) - // server->whitelist.append(ListEntry(i->text(1))); - // } - // } - // else - // { - // for(QTreeWidgetItem *i : selected) - // { - // for(ListEntry &e : server->blacklist) - // { - // if(e.hostname == i->text(1)) - // { - // alreadyAdded = true; - // break; - // } - // } - - // if(!alreadyAdded) - // server->blacklist.append(ListEntry(i->text(1))); - // } - // } + // blanked out refreshList(); } void DNSServerWindow::on_settingsButton_clicked() diff --git a/CaptiveDNS/dnsserverwindow.h b/CaptiveDNS/dnsserverwindow.h index 295dc6e..83194d4 100755 --- a/CaptiveDNS/dnsserverwindow.h +++ b/CaptiveDNS/dnsserverwindow.h @@ -51,6 +51,8 @@ class DNSServerWindow : public QMainWindow explicit DNSServerWindow(QWidget *parent = 0); ~DNSServerWindow(); + static Ui::DNSServerWindow* mainUi; + signals: void displayCache(const std::vector &cache); void clearSources(); @@ -85,6 +87,7 @@ private slots: void on_secondAddButton_clicked(); void on_settingsButton_clicked(); void on_cacheViewButton_clicked(); + private: Ui::DNSServerWindow *ui; diff --git a/CaptiveDNS/dnsserverwindow.ui b/CaptiveDNS/dnsserverwindow.ui index ea04907..8e4904c 100755 --- a/CaptiveDNS/dnsserverwindow.ui +++ b/CaptiveDNS/dnsserverwindow.ui @@ -39,7 +39,7 @@ - + CaptiveDNS is running! diff --git a/CaptiveDNS/messagesthread.cpp b/CaptiveDNS/messagesthread.cpp index 1a62893..7c9fb3b 100755 --- a/CaptiveDNS/messagesthread.cpp +++ b/CaptiveDNS/messagesthread.cpp @@ -66,6 +66,7 @@ void MessagesThread::run() if(data->dnsServer->startServer(QHostAddress::Any, data->dnsServerPort)) qDebug() << "DNS server started on address:" << data->dnsServer->serversock.localAddress() << "and port:" << data->dnsServer->serversock.localPort(); + if(data->httpServer->startServer(QHostAddress::Any, data->httpServerPort)) qDebug() << "HTTP server started on address:" << data->httpServer->serverAddress() << "and port:" << data->httpServer->serverPort(); diff --git a/CaptiveDNS/messagesthread.h b/CaptiveDNS/messagesthread.h index cbd4467..76a77c0 100755 --- a/CaptiveDNS/messagesthread.h +++ b/CaptiveDNS/messagesthread.h @@ -56,6 +56,7 @@ class MessagesThread : public QThread signals: void serversInitialized(); void androidInit(); + void displayErrorPopup(QString error); }; #endif // MESSAGESTHREAD_H diff --git a/CaptiveDNS/smalldnsserver.cpp b/CaptiveDNS/smalldnsserver.cpp index 54185f3..1ec911d 100755 --- a/CaptiveDNS/smalldnsserver.cpp +++ b/CaptiveDNS/smalldnsserver.cpp @@ -1,5 +1,11 @@ #include "smalldnsserver.h" +#include +#include +#include "dnsserverwindow.h" +#include "ui_dnsserverwindow.h" + + /* YourFriendlyDNS - A really awesome multi-platform (lin,win,mac,android) local caching and proxying dns server! Copyright (C) 2018 softwareengineer1 @ github.com/softwareengineer1 Support my work by sending me some Bitcoin or Bitcoin Cash in the value of what you valued one or more of my software projects, @@ -73,9 +79,33 @@ SmallDNSServer::SmallDNSServer(QObject *parent) // connect(dnscrypt, &DNSCrypt::decryptedLookupDoneSendResponseNow, this, &SmallDNSServer::decryptedLookupDoneSendResponseNow); } +void SmallDNSServer::displayErrorPopup(QString error) +{ + // run code on the main thread + // TODO: not working for some reason, crashes with an error about main threads still + // QMetaObject::invokeMethod(this, [error]() { + // QMessageBox::critical(0, "Error", error); + // }); + + QString msg = "Error: " + error + "\n(Is another DNS server already running?)"; + DNSServerWindow::mainUi->dnsStatus->setText(msg); + DNSServerWindow::mainUi->dnsStatus->setStyleSheet("color: red"); + +} + bool SmallDNSServer::startServer(QHostAddress address, quint16 port, bool reuse) { - return serversock.bind(address, port, reuse ? QUdpSocket::ReuseAddressHint : QUdpSocket::DefaultForPlatform); + bool res = serversock.bind(address, port, reuse ? QUdpSocket::ReuseAddressHint : QUdpSocket::DefaultForPlatform); + + printf("SmallDNSServer::startServer() %s:%d\n", address.toString().toUtf8().data(), port); + printf("SmallDNSServer::startServer() %s\n", res ? "success" : "failed"); + if (!res) { + printf("SmallDNSServer::startServer() %s\n", serversock.errorString().toUtf8().data()); + // display qt error popup + emit displayErrorPopup(serversock.errorString()); + } + + return res; } void SmallDNSServer::clearDNSCache() @@ -240,30 +270,16 @@ void SmallDNSServer::processDNSRequests() bool shouldCacheDomain, useDedicatedDNSCryptProviderToResolveV2And3Hosts = false; quint32 customIP = ipToRespondWith; std::string domain = (char*)dns.domainString.toUtf8().data(); - if(whitelistmode) - { - ListEntry *whiteListed = getListEntry(domain, TYPE_WHITELIST); - if(whiteListed) - { - qDebug() << "Matched WhiteList!" << whiteListed->hostname << "to:" << dns.domainString; - //It's whitelist mode and in the whitelist, so it should return a real IP! Unless you've manually specified an IP - if(whiteListed->ip != 0) - customIP = whiteListed->ip; - } - shouldCacheDomain = (whiteListed != nullptr); - } - else + ListEntry *blackListed = getListEntry(domain, TYPE_BLACKLIST); + if(blackListed) { - ListEntry *blackListed = getListEntry(domain, TYPE_BLACKLIST); - if(blackListed) - { - qDebug() << "Matched BlackList!" << blackListed->hostname << "to:" << dns.domainString; - //It's blacklist mode and in the blacklist, so it should return your custom IP! And your manually specified one if you did specify a particular one - if(blackListed->ip != 0) - customIP = blackListed->ip; - } - shouldCacheDomain = (blackListed == nullptr); + qDebug() << "Matched BlackList!" << blackListed->hostname << "to:" << dns.domainString; + //It's blacklist mode and in the blacklist, so it should return your custom IP! And your manually specified one if you did specify a particular one + if(blackListed->ip != 0) + customIP = blackListed->ip; } + shouldCacheDomain = (blackListed == nullptr); + if(shouldCacheDomain) { //Trying to exclude local hostnames from leaking @@ -313,27 +329,12 @@ void SmallDNSServer::processDNSRequests() dns.senderPort = senderPort; dns.ttl = dnsTTL; - if(dnscryptEnabled) - { - qDebug() << "Making encrypted DNS request type:" << dns.question.qtype << "for domain:" << dns.domainString << "request id:" << dns.header.id << "datagram:" << datagram; - if(useDedicatedDNSCryptProviderToResolveV2And3Hosts) - { - // dnscrypt->setProvider(dedicatedDNSCrypter); - qDebug() << "Using dedicated DNSCrypt provider to resolve DoH/DoTLS provider's host:" << dns.domainString; - } - // else - // dnscrypt->setProvider(selectRandomDNSCryptServer()); - - // dnscrypt->makeEncryptedRequest(dns); - } - else - { - qDebug() << "Making DNS request type:" << dns.question.qtype << "for domain:" << dns.domainString << "request id:" << dns.header.id << "datagram:" << datagram; - QString server = selectRandomDNSServer(); - quint16 serverPort = DNSInfo::extractPort(server); - if(serverPort == 0 || serverPort == 443) serverPort = 53; - clientsock.writeDatagram(datagram, QHostAddress(server), serverPort); - } + + qDebug() << "Making DNS request type:" << dns.question.qtype << "for domain:" << dns.domainString << "request id:" << dns.header.id << "datagram:" << datagram; + QString server = selectRandomDNSServer(); + quint16 serverPort = DNSInfo::extractPort(server); + if(serverPort == 0 || serverPort == 443) serverPort = 53; + clientsock.writeDatagram(datagram, QHostAddress(server), serverPort); InitialResponse *ir = new InitialResponse(dns); if(ir) diff --git a/CaptiveDNS/smalldnsserver.h b/CaptiveDNS/smalldnsserver.h index 0740cdb..86f1c1f 100755 --- a/CaptiveDNS/smalldnsserver.h +++ b/CaptiveDNS/smalldnsserver.h @@ -74,6 +74,10 @@ bool GeneralTextCompare( char cAltTerminator = '\0' // For function names, for example, you can stop at the first '(' ); +namespace Ui { +class DNSServerWindow; +} + class SmallDNSServer : public QObject { Q_OBJECT @@ -98,6 +102,7 @@ class SmallDNSServer : public QObject // DNSCrypt *dnscrypt; private: + Ui::DNSServerWindow *ui; ListEntry* getListEntry(const std::string &tame, int listType); DNSInfo* getCachedEntry(const QString &byDomain, quint16 andType); void parseAndRespond(QByteArray &datagram, DNSInfo &dns); @@ -119,6 +124,7 @@ public slots: void clearDNSCache(); void deleteEntriesFromCache(std::vector entries); void decryptedLookupDoneSendResponseNow(QByteArray decryptedResponse, DNSInfo &dns); + void displayErrorPopup(QString error); private slots: void processDNSRequests(); diff --git a/CaptiveDNS/smallhttpserver.cpp b/CaptiveDNS/smallhttpserver.cpp index 4f547fb..2d71de4 100755 --- a/CaptiveDNS/smallhttpserver.cpp +++ b/CaptiveDNS/smallhttpserver.cpp @@ -135,7 +135,7 @@ void SmallHTTPServer::createLanding()
  • DuckDuckGo
  • \n\
  • StartPage
  • \n\ \n\ -

    To customize this page, press \"Edit Landing Page\" in the CaptiveDNS app, and then open `landing.html` in a text editor.

    \n\ +

    To customize this page, press \"Edit Landing Page\" in the CaptiveDNS app, and then open landing.html in a text editor.

    \n\

    For source code and license information, see here.

    \n\

    Reload Page

    \n\ "; diff --git a/README.md b/README.md index 80cb3ea..4fdcf97 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ An app to help display a [captive portal](https://en.wikipedia.org/wiki/Captive_ Based on [YourFriendlyDNS](https://github.com/softwareengineer1/YourFriendlyDNS/), which contains many more advanced options for other self-hosted DNS use cases. ## Screenshots -CaptiveDNS Screenshot +CaptiveDNS Window Screenshot CaptiveDNS Landing page + ## Captured Domains diff --git a/preview2.png b/preview2.png new file mode 100644 index 0000000..e68be9c Binary files /dev/null and b/preview2.png differ