Improved dns handling and logging. Added support for IPv6
This commit is contained in:
parent
2c31aa7370
commit
377ee99707
@ -5,5 +5,7 @@ find_package(Libevent REQUIRED)
|
|||||||
include_directories(${LIBEVENT_INCLUDE_DIRS})
|
include_directories(${LIBEVENT_INCLUDE_DIRS})
|
||||||
message(${LIBEVENT_INCLUDE_DIRS})
|
message(${LIBEVENT_INCLUDE_DIRS})
|
||||||
|
|
||||||
add_executable(TeaWebDNS ./main.cpp src/server.cpp src/handler.cpp)
|
find_package(spdlog REQUIRED)
|
||||||
target_link_libraries(TeaWebDNS ${LIBEVENT_STATIC_LIBRARIES} pthread teadns__parser)
|
|
||||||
|
add_executable(TeaWebDNS ./main.cpp src/server.cpp src/handler.cpp src/logger.cpp)
|
||||||
|
target_link_libraries(TeaWebDNS ${LIBEVENT_STATIC_LIBRARIES} stdc++fs pthread teadns::parser spdlog::spdlog)
|
@ -1,6 +1,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <event2/thread.h>
|
#include <event2/thread.h>
|
||||||
|
#include "src/logger.h"
|
||||||
#include "src/server.h"
|
#include "src/server.h"
|
||||||
#include "src/handler.h"
|
#include "src/handler.h"
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ std::vector<sockaddr_storage> bindings(uint16_t port) {
|
|||||||
memset(&any_v4, 0, sizeof(sockaddr_in));
|
memset(&any_v4, 0, sizeof(sockaddr_in));
|
||||||
|
|
||||||
any_v4.sin_family = AF_INET;
|
any_v4.sin_family = AF_INET;
|
||||||
any_v4.sin_port = htons(port); //htons(53);
|
any_v4.sin_port = htons(port);
|
||||||
any_v4.sin_addr.s_addr = INADDR_ANY;
|
any_v4.sin_addr.s_addr = INADDR_ANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ std::vector<sockaddr_storage> bindings(uint16_t port) {
|
|||||||
memset(&any_v4, 0, sizeof(sockaddr_in));
|
memset(&any_v4, 0, sizeof(sockaddr_in));
|
||||||
|
|
||||||
any_v4.sin_family = AF_INET;
|
any_v4.sin_family = AF_INET;
|
||||||
any_v4.sin_port = htons(port); //htons(53);
|
any_v4.sin_port = htons(port);
|
||||||
any_v4.sin_addr.s_addr = (1UL << 24U) | 127U;
|
any_v4.sin_addr.s_addr = (1UL << 24U) | 127U;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,9 +34,15 @@ std::vector<sockaddr_storage> bindings(uint16_t port) {
|
|||||||
extern std::vector<std::string> le_token;
|
extern std::vector<std::string> le_token;
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
evthread_use_pthreads();
|
evthread_use_pthreads();
|
||||||
|
std::string error{};
|
||||||
|
|
||||||
|
if(!logger::setup(error)) {
|
||||||
|
std::cerr << "Failed to setup log: " << error << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if(argc < 2) {
|
if(argc < 2) {
|
||||||
std::cerr << "Missing port. Default DNS port is 53\n";
|
log_general()->error("Missing port. Default DNS port is 53");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,18 +50,19 @@ int main(int argc, char** argv) {
|
|||||||
try {
|
try {
|
||||||
port = std::stoul(argv[1]);
|
port = std::stoul(argv[1]);
|
||||||
} catch(std::exception& ex) {
|
} catch(std::exception& ex) {
|
||||||
std::cerr << "Failed to parse port\n";
|
log_general()->error("Failed to parse port ({})", argv[1]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
std::string error{};
|
|
||||||
|
|
||||||
auto handler = std::make_shared<WebDNSHandler>();
|
auto handler = std::make_shared<WebDNSHandler>();
|
||||||
DNSServer server{handler};
|
DNSServer server{handler};
|
||||||
|
|
||||||
|
log_general()->info("Starting server on port {}", port);
|
||||||
if(!server.start(bindings(port), error)) {
|
if(!server.start(bindings(port), error)) {
|
||||||
|
auto logger = log_general();
|
||||||
for(auto& binding : server.bindings())
|
for(auto& binding : server.bindings())
|
||||||
std::cout << " - " << binding->error << "\n";
|
logger->error(" - {}", error);
|
||||||
std::cerr << "Failed to start server: " << error << "\n";
|
logger->error("Failed to start server: {}", error);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,21 +73,23 @@ int main(int argc, char** argv) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(line == "end" || line == "stop") {
|
if(line == "end" || line == "stop") {
|
||||||
std::cout << "Stopping server\n";
|
log_general()->info("Stopping server");
|
||||||
break;
|
break;
|
||||||
} else if(line.length() > 13 && line.substr(0, 13) == "add-le-token ") {
|
} else if(line.length() > 13 && line.substr(0, 13) == "add-le-token ") {
|
||||||
le_token.push_back(line.substr(13));
|
le_token.push_back(line.substr(13));
|
||||||
std::cout << "Added letsencrypt token: " << le_token.back() << "\n";
|
log_general()->info("Added LetsEncrypt token {}", le_token.back());
|
||||||
} else if(line.length() > 14 && line.substr(0, 14) == "clear-le-token ") {
|
} else if(line.length() >= 14 && line.substr(0, 14) == "clear-le-token") {
|
||||||
std::cout << "Cleaning up LE tokens\n";
|
log_general()->info("Cleaning up {} le tokens", le_token.size());
|
||||||
le_token.clear();
|
le_token.clear();
|
||||||
} else if(line.length() > 14 && line.substr(0, 14) == "list-le-token ") {
|
} else if(line.length() >= 14 && line.substr(0, 14) == "list-le-token") {
|
||||||
std::cout << "Letsencrypt tokens (" << le_token.size() << "):\n";
|
log_general()->info("LetsEncrypt tokens ({}):", le_token.size());
|
||||||
for(auto& token : le_token)
|
for(auto& token : le_token)
|
||||||
std::cout << " - " << token << "\n";
|
log_general()->info(" - ", token);
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Unknown command \"" << line << "\"\n";
|
log_general()->error("Unknown command \"{}\"", line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger::shutdown();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -1,38 +1,48 @@
|
|||||||
#include "./handler.h"
|
#include "./handler.h"
|
||||||
#include "./server.h"
|
#include "./server.h"
|
||||||
#include "./net.h"
|
#include "./net.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <teadns/parser.h>
|
#include <teadns/parser.h>
|
||||||
#include <teadns/builder.h>
|
#include <teadns/builder.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
using namespace ts::dns;
|
using namespace ts::dns;
|
||||||
using namespace ts::dns::builder;
|
using namespace ts::dns::builder;
|
||||||
|
|
||||||
std::vector<std::string> le_token;
|
std::vector<std::string> le_token;
|
||||||
|
|
||||||
|
struct ClientAddress {
|
||||||
|
std::string str;
|
||||||
|
const sockaddr_storage &addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
void create_answer(DNSBuilder& response, const ClientAddress &client_address, const parser::DNSQuery& query);
|
||||||
void WebDNSHandler::handle_message(const std::shared_ptr<DNSServerBinding>& binding, const sockaddr_storage &address, void *buffer, size_t size) {
|
void WebDNSHandler::handle_message(const std::shared_ptr<DNSServerBinding>& binding, const sockaddr_storage &address, void *buffer, size_t size) {
|
||||||
std::cout << "Received DNS request from " << net::to_string(address) << ":\n";
|
const ClientAddress addr_data{net::to_string(address), address};
|
||||||
|
auto logger = log_dns();
|
||||||
|
const auto begin = std::chrono::system_clock::now();
|
||||||
|
|
||||||
DNSParser parser{0, nullptr, buffer, size};
|
DNSParser parser{0, nullptr, buffer, size};
|
||||||
|
|
||||||
std::string error;
|
std::string error;
|
||||||
if(!parser.parse(error)) {
|
if(!parser.parse(error)) {
|
||||||
std::cout << " Failed to parse request: " << error << "\n";
|
logger->warn("[{}] Received invalid DNS request: {}", addr_data.str, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
logger->info("[{}] Received DNS request with {} queries", addr_data.str, parser.queries().size());
|
||||||
std::cout << " Query type: " << (uint32_t) parser.header().query_type() << "\n";
|
logger->trace("[{}] Query type: {}", addr_data.str, (uint32_t) parser.header().query_type());
|
||||||
std::cout << " Queries (" << parser.queries().size() << "):\n";
|
logger->trace("[{}] Queries ({}):", addr_data.str, (uint32_t) parser.queries().size());
|
||||||
for(auto& query : parser.queries())
|
for(auto& query : parser.queries())
|
||||||
std::cout << " " << query->qname() << " (" << rrclass::name(query->qclass()) << "::" << rrtype::name(query->qtype()) << ")\n";
|
logger->trace("[{}] {} ({}::{})", addr_data.str, query->qname(), rrclass::name(query->qclass()), rrtype::name(query->qtype()));
|
||||||
std::cout << " Sending response.\n";
|
|
||||||
|
|
||||||
{
|
{
|
||||||
DNSBuilder response{};
|
DNSBuilder response{};
|
||||||
|
|
||||||
response.header().id(*(uint16_t*) buffer);
|
response.header().id(*(uint16_t*) buffer);
|
||||||
response.header().set_answer(true);
|
response.header().set_answer(true);
|
||||||
response.header().set_response_code(rcode::NOERROR);
|
|
||||||
response.header().set_query_type(parser.header().query_type());
|
response.header().set_query_type(parser.header().query_type());
|
||||||
|
|
||||||
for(auto& query : parser.queries()) {
|
for(auto& query : parser.queries()) {
|
||||||
@ -41,62 +51,143 @@ void WebDNSHandler::handle_message(const std::shared_ptr<DNSServerBinding>& bind
|
|||||||
q.set_qname(query->qname());
|
q.set_qname(query->qname());
|
||||||
q.set_qtype(query->qtype());
|
q.set_qtype(query->qtype());
|
||||||
|
|
||||||
if(query->qclass() == rrclass::IN && query->qtype() == rrtype::A) {
|
try {
|
||||||
auto dn = query->qname();
|
create_answer(response, addr_data, *query);
|
||||||
uint8_t resp[4];
|
} catch(std::exception& ex) {
|
||||||
{
|
logger->error("[{}] Failed to generate answer for query. Cought an exception: {}", addr_data.str, ex.what());
|
||||||
size_t index = 0;
|
|
||||||
size_t aindex = 0;
|
|
||||||
do {
|
|
||||||
auto found = dn.find('-', index);
|
|
||||||
auto length = index == -1 ? dn.length() - index : found - index;
|
|
||||||
|
|
||||||
try {
|
|
||||||
resp[aindex] = std::stoul(dn.substr(index, length));
|
|
||||||
} catch(std::exception& ex) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
aindex++;
|
|
||||||
index = found;
|
|
||||||
} while(index++ && aindex < 4);
|
|
||||||
if(aindex != 4)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
std::cout << " Adding answer ";
|
|
||||||
for(size_t index = 0; index < 4; index++)
|
|
||||||
std::cout << (uint32_t) resp[index] << (index == 3 ? "\n" : ".");
|
|
||||||
|
|
||||||
auto& a = response.push_answer(query->qname());
|
|
||||||
a.set_class(query->qclass());
|
|
||||||
a.set_type(query->qtype());
|
|
||||||
a.set_ttl(120);
|
|
||||||
a.builder<rrbuilder::A>().set_address(resp);
|
|
||||||
} else if(query->qclass() == rrclass::IN && query->qtype() == rrtype::TXT) {
|
|
||||||
auto dn = query->qname();
|
|
||||||
std::transform(dn.begin(), dn.end(), dn.begin(), tolower);
|
|
||||||
|
|
||||||
if(dn == "_acme-challenge.con-gate.work") {
|
|
||||||
std::cout << " Letsencrypt request\n";
|
|
||||||
std::cout << " Sending predefined key(s)\n";
|
|
||||||
|
|
||||||
for(auto& key : le_token) {
|
|
||||||
auto& a = response.push_answer(query->qname());
|
|
||||||
a.set_class(query->qclass());
|
|
||||||
a.set_type(query->qtype());
|
|
||||||
a.set_ttl(120);
|
|
||||||
a.builder<rrbuilder::TXT>().set_text(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(parser.answers().empty())
|
||||||
|
response.header().set_response_code(rcode::NXDOMAIN);
|
||||||
|
else
|
||||||
|
response.header().set_response_code(rcode::NOERROR);
|
||||||
|
|
||||||
char rbuffer[1024];
|
char rbuffer[1024];
|
||||||
auto len = response.build(rbuffer, 1024, error);
|
auto len = response.build(rbuffer, 1024, error);
|
||||||
if(!len) {
|
if(!len) {
|
||||||
std::cout << " Failed to build response: " << error << "\n";
|
//TODO: Send prebuild server fail packet
|
||||||
return;
|
logger->error("[{}] Failed to build response: {}", error);
|
||||||
|
} else {
|
||||||
|
binding->send(address, rbuffer, len);
|
||||||
}
|
}
|
||||||
binding->send(address, rbuffer, len);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto end = std::chrono::system_clock::now();
|
||||||
|
logger->info("[{}] Query completed in {}us", addr_data.str, std::chrono::floor<std::chrono::microseconds>(end - begin).count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAX_IPV6_ADDRESS_STR_LEN 39
|
||||||
|
|
||||||
|
//Address at least one char long!
|
||||||
|
bool parse_v6(uint8_t(result)[16], const std::string_view& address) {
|
||||||
|
uint16_t accumulator{0};
|
||||||
|
uint8_t colon_count{0}, pos{0};
|
||||||
|
|
||||||
|
memset(result, 0, 16);
|
||||||
|
|
||||||
|
// Step 1: look for position of ::, and count colons after it
|
||||||
|
for(uint8_t i = 1; i <= MAX_IPV6_ADDRESS_STR_LEN && address.length() > i; i++) {
|
||||||
|
if (address[i] == ':') {
|
||||||
|
if (address[i - 1] == ':') {
|
||||||
|
colon_count = 14; // Double colon!
|
||||||
|
} else if (colon_count) {
|
||||||
|
colon_count -= 2; // Count backwards the number of colons after the ::
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: convert from ascii to binary
|
||||||
|
for(uint8_t i=0; i <= MAX_IPV6_ADDRESS_STR_LEN && pos < 16; i++) {
|
||||||
|
if (address[i] == ':' || address.length() == i) {
|
||||||
|
result[pos] = accumulator >> 8U;
|
||||||
|
result[pos + 1] = accumulator;
|
||||||
|
accumulator = 0;
|
||||||
|
|
||||||
|
if (colon_count && i && address[i - 1] == ':') {
|
||||||
|
pos = colon_count;
|
||||||
|
} else {
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(uint8_t&) address[i] |= 0x20U;
|
||||||
|
accumulator <<= 4U;
|
||||||
|
|
||||||
|
if (address[i] >= '0' && address[i] <= '9') {
|
||||||
|
accumulator |= (uint8_t) (address[i] - '0');
|
||||||
|
} else if (address[i] >= 'a' && address[i] <= 'f') {
|
||||||
|
accumulator |= (uint8_t) ((address[i] - 'a') + 10);
|
||||||
|
} else {
|
||||||
|
return false; // Not hex or colon: fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void create_answer(DNSBuilder& response, const ClientAddress & client_address, const parser::DNSQuery& query) {
|
||||||
|
if(query.qclass() != rrclass::IN) return;
|
||||||
|
|
||||||
|
if(query.qtype() == rrtype::A) {
|
||||||
|
auto dn = query.qname();
|
||||||
|
uint8_t resp[4];
|
||||||
|
{
|
||||||
|
size_t index = 0;
|
||||||
|
size_t aindex = 0;
|
||||||
|
do {
|
||||||
|
auto found = dn.find('-', index);
|
||||||
|
auto length = index == -1 ? dn.length() - index : found - index;
|
||||||
|
|
||||||
|
try {
|
||||||
|
resp[aindex] = std::stoul(dn.substr(index, length));
|
||||||
|
} catch(std::exception& ex) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
aindex++;
|
||||||
|
index = found;
|
||||||
|
} while(index++ && aindex < 4);
|
||||||
|
if(aindex != 4)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_dns()->info("[{}] Sending requested IPv4 ({}): {}.{}.{}.{}", client_address.str, dn, resp[0], resp[1], resp[2], resp[3]);
|
||||||
|
auto& a = response.push_answer(query.qname());
|
||||||
|
a.set_class(query.qclass());
|
||||||
|
a.set_type(rrtype::A);
|
||||||
|
a.set_ttl(120);
|
||||||
|
a.builder<rrbuilder::A>().set_address(resp);
|
||||||
|
} else if(query.qtype() == rrtype::AAAA) {
|
||||||
|
auto dn = query.qname();
|
||||||
|
const auto parts = parse_dn(dn);
|
||||||
|
|
||||||
|
if(parts.size() != 3) return;
|
||||||
|
|
||||||
|
in6_addr result{};
|
||||||
|
if(!parse_v6(result.__in6_u.__u6_addr8, parts[0])) return;
|
||||||
|
|
||||||
|
log_dns()->info("[{}] Sending requested IPv6 ({}): {}", client_address.str, dn, net::to_string(result));
|
||||||
|
|
||||||
|
auto& a = response.push_answer(query.qname());
|
||||||
|
a.set_class(query.qclass());
|
||||||
|
a.set_type(rrtype::AAAA);
|
||||||
|
a.set_ttl(120);
|
||||||
|
a.builder<rrbuilder::AAAA>().set_address(result.__in6_u.__u6_addr32);
|
||||||
|
} else if(query.qtype() == rrtype::TXT) {
|
||||||
|
auto dn = query.qname();
|
||||||
|
std::transform(dn.begin(), dn.end(), dn.begin(), tolower);
|
||||||
|
|
||||||
|
if(dn == "_acme-challenge.con-gate.work") {
|
||||||
|
log_dns()->info("[{}] Received LetsEncrypt auth request. Sending {} predefined keys.", le_token.size());
|
||||||
|
|
||||||
|
for(auto& key : le_token) {
|
||||||
|
auto& a = response.push_answer(query.qname());
|
||||||
|
a.set_class(query.qclass());
|
||||||
|
a.set_type(query.qtype());
|
||||||
|
a.set_ttl(120);
|
||||||
|
a.builder<rrbuilder::TXT>().set_text(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
server/src/logger.cpp
Normal file
50
server/src/logger.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "./logger.h"
|
||||||
|
|
||||||
|
#include <experimental/filesystem>
|
||||||
|
#include <spdlog/sinks/file_sinks.h>
|
||||||
|
#include <spdlog/sinks/stdout_sinks.h>
|
||||||
|
|
||||||
|
namespace fs = std::experimental::filesystem;
|
||||||
|
|
||||||
|
const static std::string log_folder{"logs/"};
|
||||||
|
|
||||||
|
std::shared_ptr<spdlog::logger> logger::logger_general{nullptr};
|
||||||
|
std::shared_ptr<spdlog::logger> logger::logger_network{nullptr};
|
||||||
|
std::shared_ptr<spdlog::logger> logger::logger_dns{nullptr};
|
||||||
|
|
||||||
|
bool logger::setup(std::string& error) {
|
||||||
|
try {
|
||||||
|
if(!fs::exists(log_folder) && !fs::create_directories(log_folder)) {
|
||||||
|
error = "failed to create directory " + log_folder;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch(fs::filesystem_error& ex) {
|
||||||
|
error = "failed to create log folder at " + log_folder + ": " + std::string{ex.what()};
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<spdlog::sink_ptr> sinks{};
|
||||||
|
sinks.reserve(2);
|
||||||
|
{
|
||||||
|
auto file_sink = std::make_shared<spdlog::sinks::daily_file_sink_st>(log_folder + "log_", 0, 0);
|
||||||
|
file_sink->set_level(spdlog::level::trace);
|
||||||
|
sinks.push_back(file_sink);
|
||||||
|
|
||||||
|
auto console_sink = std::make_shared<spdlog::sinks::stdout_sink_st>();
|
||||||
|
console_sink->set_level(spdlog::level::trace);
|
||||||
|
sinks.push_back(console_sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
spdlog::register_logger(logger_general = std::make_shared<spdlog::async_logger>("general", std::begin(sinks), std::end(sinks), 8192, spdlog::async_overflow_policy::block_retry));
|
||||||
|
spdlog::register_logger(logger_network = std::make_shared<spdlog::async_logger>("network", std::begin(sinks), std::end(sinks), 8192, spdlog::async_overflow_policy::block_retry));
|
||||||
|
spdlog::register_logger(logger_dns = std::make_shared<spdlog::async_logger>("dns ", std::begin(sinks), std::end(sinks), 8192, spdlog::async_overflow_policy::block_retry));
|
||||||
|
|
||||||
|
spdlog::apply_all([](const std::shared_ptr<spdlog::logger>& l) {
|
||||||
|
l->set_level(spdlog::level::trace);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool logger::shutdown() {
|
||||||
|
spdlog::drop_all();
|
||||||
|
}
|
17
server/src/logger.h
Normal file
17
server/src/logger.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define SPDLOG_LEVEL_NAMES { "trace ", "debug ", "info ", "warning ", "error ", "critical", "off " }
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
namespace logger {
|
||||||
|
extern std::shared_ptr<spdlog::logger> logger_general;
|
||||||
|
extern std::shared_ptr<spdlog::logger> logger_network;
|
||||||
|
extern std::shared_ptr<spdlog::logger> logger_dns;
|
||||||
|
|
||||||
|
extern bool setup(std::string& /* error */);
|
||||||
|
extern bool shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::shared_ptr<spdlog::logger> log_general() { return logger::logger_general; }
|
||||||
|
inline std::shared_ptr<spdlog::logger> log_network() { return logger::logger_network; }
|
||||||
|
inline std::shared_ptr<spdlog::logger> log_dns() { return logger::logger_dns; }
|
@ -1,6 +1,7 @@
|
|||||||
#include "./server.h"
|
#include "./server.h"
|
||||||
#include "./handler.h"
|
#include "./handler.h"
|
||||||
#include "./net.h"
|
#include "./net.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -280,18 +281,17 @@ void DNSServer::event_cb_read(evutil_socket_t fd, short, void *ptr_binding) {
|
|||||||
if(errno == EAGAIN)
|
if(errno == EAGAIN)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
std::cerr << "Failed to receive data: " << errno << "/" << strerror(errno) << "\n";
|
log_network()->warn("Failed to receive data from fd {}: {}/{}", fd, errno, strerror(errno));
|
||||||
break; /* this should never happen! */
|
break; /* this should never happen! */
|
||||||
}
|
}
|
||||||
|
|
||||||
read_count++;
|
read_count++;
|
||||||
//buffer, (size_t) read_length
|
|
||||||
|
|
||||||
auto handler = binding->server->handler;
|
auto handler = binding->server->handler;
|
||||||
if(handler)
|
if(handler)
|
||||||
handler->handle_message(binding_ref, source_address, buffer, read_length);
|
handler->handle_message(binding_ref, source_address, buffer, read_length);
|
||||||
else
|
else
|
||||||
std::cerr << "Dropping " << read_length << " bytes from " << net::to_string(source_address, true) << " because we've no handler\n";
|
log_network()->warn("Dropping {} bytes from {} because we've no handler", read_length, net::to_string(source_address, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +315,7 @@ void DNSServer::event_cb_write(evutil_socket_t fd, short, void *ptr_binding) {
|
|||||||
|
|
||||||
code = sendto(fd, (char*) buffer + sizeof(DNSServerBinding::BindingBuffer), buffer->size, 0, (sockaddr*) &buffer->target, sizeof(buffer->target));
|
code = sendto(fd, (char*) buffer + sizeof(DNSServerBinding::BindingBuffer), buffer->size, 0, (sockaddr*) &buffer->target, sizeof(buffer->target));
|
||||||
if(code <= 0)
|
if(code <= 0)
|
||||||
std::cerr << "Failed to send DNS response to " << net::to_string(buffer->target, true) << ": " << errno << "/" << strerror(errno);
|
log_network()->error("Failed to send DNS response to {}: {}/{}", net::to_string(buffer->target, true), errno, strerror(errno));
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,4 +2,6 @@ project(TeaDNS-Parser)
|
|||||||
|
|
||||||
add_library(teadns__parser INTERFACE)
|
add_library(teadns__parser INTERFACE)
|
||||||
target_sources(teadns__parser INTERFACE src/parser.cpp src/types.cpp src/builder.cpp)
|
target_sources(teadns__parser INTERFACE src/parser.cpp src/types.cpp src/builder.cpp)
|
||||||
target_include_directories(teadns__parser INTERFACE include)
|
target_include_directories(teadns__parser INTERFACE include)
|
||||||
|
|
||||||
|
add_library(teadns::parser ALIAS teadns__parser)
|
@ -143,6 +143,31 @@ namespace ts::dns {
|
|||||||
uint32_t address{0};
|
uint32_t address{0};
|
||||||
);
|
);
|
||||||
|
|
||||||
|
define_builder(AAAA, base,
|
||||||
|
inline void set_address(const uint32_t (&address)[4]) {
|
||||||
|
this->set_address(address[0], address[1], address[2], address[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_address(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
|
||||||
|
this->address[0] = a;
|
||||||
|
this->address[1] = b;
|
||||||
|
this->address[2] = c;
|
||||||
|
this->address[3] = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_address(const uint8_t (&address)[16]) {
|
||||||
|
this->set_address(
|
||||||
|
(uint32_t) htonl((address[ 0] << 24UL) | (address[ 1] << 16UL) | (address[ 2] << 8UL) | address[ 3]),
|
||||||
|
(uint32_t) htonl((address[ 4] << 24UL) | (address[ 5] << 16UL) | (address[ 6] << 8UL) | address[ 7]),
|
||||||
|
(uint32_t) htonl((address[ 8] << 24UL) | (address[ 8] << 16UL) | (address[10] << 8UL) | address[11]),
|
||||||
|
(uint32_t) htonl((address[12] << 24UL) | (address[13] << 16UL) | (address[14] << 8UL) | address[15])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t address[4]{0, 0, 0, 0};
|
||||||
|
);
|
||||||
|
|
||||||
define_builder(TXT, base,
|
define_builder(TXT, base,
|
||||||
inline void set_text(const std::string& text) { this->_text = text; }
|
inline void set_text(const std::string& text) { this->_text = text; }
|
||||||
private:
|
private:
|
||||||
|
@ -88,6 +88,8 @@ namespace ts::dns {
|
|||||||
rr_list_t parsed_additionals;
|
rr_list_t parsed_additionals;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<std::string_view> parse_dn(const std::string_view& /* dn */);
|
||||||
|
|
||||||
namespace parser {
|
namespace parser {
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
class DNSHeader {
|
class DNSHeader {
|
||||||
|
@ -121,6 +121,18 @@ bool rrbuilder::A::build(char *&buffer, size_t &max_size, std::string &error) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rrbuilder::AAAA::build(char *&buffer, size_t &max_size, std::string &error) {
|
||||||
|
if(max_size < 16) {
|
||||||
|
error = "buffer too small";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer, &this->address[0], 16);
|
||||||
|
buffer += 16;
|
||||||
|
max_size -= 16;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool rrbuilder::TXT::build(char *&buffer, size_t &max_size, std::string &error) {
|
bool rrbuilder::TXT::build(char *&buffer, size_t &max_size, std::string &error) {
|
||||||
if(max_size + 1 < this->_text.size()) {
|
if(max_size + 1 < this->_text.size()) {
|
||||||
error = "buffer too small";
|
error = "buffer too small";
|
||||||
|
@ -401,3 +401,19 @@ std::string named_base::name() {
|
|||||||
return this->handle->dns_data()->parse_dns_dn(error, index, true);
|
return this->handle->dns_data()->parse_dns_dn(error, index, true);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::string_view> ts::dns::parse_dn(const std::string_view &dn) {
|
||||||
|
std::vector<std::string_view> result{};
|
||||||
|
result.reserve(8);
|
||||||
|
|
||||||
|
size_t index{0}, found{0};
|
||||||
|
do {
|
||||||
|
found = dn.find('.', index);
|
||||||
|
const auto length = (found == -1 ? dn.length() : found) - index;
|
||||||
|
result.emplace_back(dn.substr(index, length));
|
||||||
|
index = found;
|
||||||
|
} while(++index);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user