feat(dns): add DNS server with configurable port and IP via CLI

This commit is contained in:
Ваше Имя
2025-09-30 18:55:58 +04:00
parent 46574026fe
commit 7dac7fb0de
5 changed files with 155 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
#include "dns_cli.hpp"
// helper for default values
constexpr auto withDefault = [](auto value) {
using T = decltype(value);
return boost::program_options::value<T>()->default_value(value);
};
DnsCli::DnsCli()
: CliBase("DNS Server Options")
, port_(5300)
, ip_("127.0.0.1")
{
}
void DnsCli::setupOptions()
{
// clang-format off
desc_.add_options()
("help,h", "Show help message")
("port,p", withDefault(5300), "UDP port to listen on")
("ip,i", withDefault(std::string("127.0.0.1")), "IP address to return in A record");
// clang-format on
}
int DnsCli::getPort() const
{
return vm_["port"].as<int>();
}
std::string DnsCli::getIp() const
{
return vm_["ip"].as<std::string>();
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include "cli_base.hpp"
#include <string>
class DnsCli : public CliBase
{
public:
DnsCli();
int getPort() const;
std::string getIp() const;
protected:
void setupOptions() override;
private:
int port_;
std::string ip_;
};
+57
View File
@@ -0,0 +1,57 @@
#include "dns_server.hpp"
#include "logger.hpp"
DnsServer::DnsServer(IoContext &io, unsigned short port, std::string answerIp)
: UdpServerBase(io, port)
, answerIp_(std::move(answerIp))
{
}
void DnsServer::handleRequest(
const std::string_view data, const UdpEndpoint &sender
)
{
if (data.size() < 12) {
Logger::warn("Invalid DNS packet");
return;
}
// response buffer
std::string resp;
// copy ID
resp.append(data.substr(0, 2));
// flags: QR=1 (response), AA=1
resp.push_back('\x81');
resp.push_back('\x80');
// QDCOUNT=1, ANCOUNT=1, NSCOUNT=0, ARCOUNT=0
resp.append("\0\1\0\1\0\0\0\0", 8);
// copy question (from offset 12 till end of query)
resp.append(data.substr(12));
// answer section
resp.append("\xc0\x0c"); // name pointer to question
resp.append("\0\1"); // TYPE A
resp.append("\0\1"); // CLASS IN
resp.append("\0\0\0\x3c"); // TTL = 60
resp.append("\0\x04"); // RDLENGTH = 4
// answer IP (from CLI or default 127.0.0.1)
unsigned int b1, b2, b3, b4;
if (sscanf(answerIp_.c_str(), "%u.%u.%u.%u", &b1, &b2, &b3, &b4) != 4) {
b1 = 127;
b2 = 0;
b3 = 0;
b4 = 1;
}
resp.push_back(static_cast<char>(b1));
resp.push_back(static_cast<char>(b2));
resp.push_back(static_cast<char>(b3));
resp.push_back(static_cast<char>(b4));
Logger::info("DNS query answered with A " + answerIp_);
doSend(resp, sender);
}
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#include "udp_server_base.hpp"
#include <string>
class DnsServer : public UdpServerBase
{
public:
DnsServer(IoContext &io, unsigned short port, std::string answerIp);
protected:
void handleRequest(
const std::string_view data, const UdpEndpoint &sender
) override;
private:
std::string answerIp_;
};
+26
View File
@@ -0,0 +1,26 @@
#include "dns_cli.hpp"
#include "dns_server.hpp"
#include "logger.hpp"
int main(int argc, char *argv[])
{
DnsCli cli;
cli.parse(argc, argv);
if (cli.isHelp()) {
cli.printHelp();
return 0;
}
Logger::init(true, "dns_server.log");
Logger::info(
"DNS server starting on port " + std::to_string(cli.getPort())
+ ", answering with IP " + cli.getIp()
);
IoContext io;
DnsServer server(io, cli.getPort(), cli.getIp());
server.start();
io.run();
}