feat(dns): add DNS server with configurable port and IP via CLI
This commit is contained in:
@@ -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>();
|
||||||
|
}
|
||||||
@@ -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_;
|
||||||
|
};
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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_;
|
||||||
|
};
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user