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