move hook out of dnsd into daemon, made hook use timer, decode_answer has beginning SOA parsing support, getDNSstring() refactor

This commit is contained in:
Ryan Tharp 2018-08-02 05:51:49 -07:00
parent 82f300523d
commit 52bbf890ef
7 changed files with 241 additions and 57 deletions

View File

@ -27,17 +27,85 @@ handle_signal(int sig)
done = true;
}
sockaddr *
hookChecker(std::string name, struct dnsd_context *context)
{
llarp::LogInfo("Hooked ", name);
// cast your context->user;
return nullptr;
std::string const default_chars =
"abcdefghijklmnaoqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
#include <random>
std::string random_string(size_t len = 15, std::string const &allowed_chars = default_chars) {
std::mt19937_64 gen { std::random_device()() };
std::uniform_int_distribution<size_t> dist { 0, allowed_chars.length()-1 };
std::string ret;
std::generate_n(std::back_inserter(ret), len, [&] { return allowed_chars[dist(gen)]; });
return ret;
}
// FIXME: make configurable
#define SERVER "8.8.8.8"
#define PORT 53
/*
/// check_online_request hook definition
typedef void (*check_query_request_hook_func)(struct check_query_request *);
struct check_query_request
{
bool done;
///hook
check_query_request_hook_func hook;
};
void
llarp_dnsd_checkQuery_resolved(struct check_query_request *request)
{
}
*/
struct check_query_simple_request
{
const struct sockaddr *from;
dnsd_question_request *request;
};
void
llarp_dnsd_checkQuery(void *u, uint64_t orig, uint64_t left)
{
if(left)
return;
//struct check_query_request *request = static_cast< struct check_query_request * >(u);
struct check_query_simple_request *qr = static_cast< struct check_query_simple_request * >(u);
llarp::LogInfo("Sending cname to delay");
writecname_dnss_response(random_string(32, "abcdefghijklmnopqrstuvwxyz")+"bob.loki", qr->from, qr->request);
delete qr;
}
dnsd_query_hook_response *
hookChecker(std::string name, const struct sockaddr *from,
struct dnsd_question_request *request)
{
dnsd_query_hook_response *response = new dnsd_query_hook_response;
response->dontLookUp = false;
response->dontSendResponse = false;
response->returnThis = nullptr;
llarp::LogInfo("Hooked ", name);
std::string lName = name;
std::transform(lName.begin(), lName.end(), lName.begin(), ::tolower);
// FIXME: probably should just read the last 5 bytes
if (lName.find(".loki") != std::string::npos)
{
llarp::LogInfo("Detect Loki Lookup");
//check_query_request *query_request = new check_query_request;
//query_request->hook = &llarp_dnsd_checkQuery_resolved;
check_query_simple_request *qr = new check_query_simple_request;
qr->from = from;
qr->request = request;
// nslookup on osx is about 5 sec before a retry
llarp_logic_call_later(request->context->logic,
{5000, qr, &llarp_dnsd_checkQuery});
response->dontSendResponse = true;
}
// cast your context->user;
return response;
}
struct dns_relay_config
{
@ -92,6 +160,8 @@ main(int argc, char *argv[])
iter.visit = &dns_iter_config;
llarp_config_iter(config_reader, &iter);
llarp::LogInfo("config [", conffname, "] loaded");
const uint16_t server_port = 1053;
// llarp::SetLogLevel(llarp::eLogDebug);
@ -101,12 +171,14 @@ main(int argc, char *argv[])
llarp_ev_loop *netloop = nullptr;
llarp_threadpool *worker = nullptr;
llarp_logic *logic = nullptr;
llarp_ev_loop_alloc(&netloop);
llarp_ev_loop_alloc(&netloop); // set up netio worker
worker = llarp_init_same_process_threadpool();
logic = llarp_init_single_process_logic(worker); // set up logic worker
// configure main netloop
struct dnsd_context dnsd;
if(!llarp_dnsd_init(&dnsd, netloop, "*", 1053,
if(!llarp_dnsd_init(&dnsd, netloop, logic, "*", server_port,
(const char *)dnsr_config.upstream_host.c_str(),
dnsr_config.upstream_port))
{
@ -118,18 +190,21 @@ main(int argc, char *argv[])
dnsd.intercept = &hookChecker;
llarp::LogInfo("singlethread start");
worker = llarp_init_same_process_threadpool();
logic = llarp_init_single_process_logic(worker);
llarp_ev_loop_run_single_process(netloop, worker, logic);
llarp::LogInfo("singlethread end");
llarp_ev_loop_free(&netloop);
}
else
{
// need this for timer stuff
llarp_threadpool *worker = nullptr;
llarp_logic *logic = nullptr;
worker = llarp_init_same_process_threadpool();
logic = llarp_init_single_process_logic(worker); // set up logic worker
// configure main netloop
struct dnsd_context dnsd;
if(!llarp_dnsd_init(&dnsd, nullptr, "*", 1053,
if(!llarp_dnsd_init(&dnsd, nullptr, logic, "*", server_port,
(const char *)dnsr_config.upstream_host.c_str(),
dnsr_config.upstream_port))
{

View File

@ -2,6 +2,34 @@
#include "dnsd.hpp" // for llarp_handle_dnsd_recvfrom, dnsc
#include "logger.hpp"
/*
<domain-name> is a domain name represented as a series of labels, and
terminated by a label with zero length. <character-string> is a single
length octet followed by that number of characters. <character-string>
is treated as binary information, and can be up to 256 characters in
length (including the length octet).
*/
std::string getDNSstring(const char *buffer)
{
std::string str = "";
uint8_t length = *buffer++;
//printf("dnsStringLen[%d]\n", length);
//llarp::LogInfo("dnsStringLen ", length);
if (!length) return str;
while(length != 0)
{
for(int i = 0; i < length; i++)
{
char c = *buffer++;
str.append(1, c);
}
length = *buffer++;
if(length != 0)
str.append(1, '.');
}
return str;
}
extern "C"
{
uint16_t
@ -14,7 +42,6 @@ extern "C"
return value;
}
// uint32_t
uint32_t
get32bits(const char *&buffer) throw()
{
@ -52,11 +79,14 @@ extern "C"
hdr->arCount = get16bits(buffer);
return hdr;
}
dns_msg_question *
decode_question(const char *buffer)
{
dns_msg_question *question = new dns_msg_question;
std::string m_qName = getDNSstring(buffer);
//buffer += m_qName.size() + 1;
/*
std::string m_qName = "";
int length = *buffer++;
// llarp::LogInfo("qNamLen", length);
@ -71,6 +101,7 @@ extern "C"
if(length != 0)
m_qName.append(1, '.');
}
*/
question->name = m_qName;
question->type = get16bits(buffer);
question->qClass = get16bits(buffer);
@ -81,6 +112,17 @@ extern "C"
decode_answer(const char *buffer)
{
dns_msg_answer *answer = new dns_msg_answer;
// skip for now until we can handle compressed labels
/*
std::string aName = getDNSstring((char *)buffer);
buffer += aName.size() + 1;
*/
uint8_t first = *buffer++;
// SOA hack
if (first != 12)
{
buffer --; // rewind buffer one byte
}
answer->type = get16bits(buffer);
// assert(answer->type < 259);
if(answer->type > 259)
@ -97,6 +139,33 @@ extern "C"
}
else
{
switch(answer->type)
{
case 6: // type 6 = SOA
{
// 2 names, then 4x 32bit
std::string mname = getDNSstring((char *)buffer);
std::string rname = getDNSstring((char *)buffer);
uint32_t serial = get32bits(buffer);
uint32_t refresh = get32bits(buffer);
uint32_t retry = get32bits(buffer);
uint32_t expire = get32bits(buffer);
uint32_t minimum = get32bits(buffer);
llarp::LogInfo("mname : ", mname);
llarp::LogInfo("rname : ", rname);
llarp::LogDebug("serial : ", serial);
llarp::LogDebug("refresh : ", refresh);
llarp::LogDebug("retry : ", retry);
llarp::LogDebug("expire : ", expire);
llarp::LogDebug("minimum : ", minimum);
}
break;
default:
{
//llarp::LogWarn("Unknown Type ", answer->type);
}
break;
}
llarp::LogWarn("Unknown Type ", answer->type);
}
return answer;

View File

@ -5,6 +5,7 @@
#include <sys/types.h> // for uint & ssize_t
#include <map>
#include <string>
#include <vector>
// dnsc can work over any UDP socket
// however we can't ignore udp->user
@ -61,6 +62,15 @@ struct dns_msg_answer
uint8_t *rData;
};
struct dns_packet
{
struct dns_msg_header *header;
std::vector<dns_msg_question *> questions;
std::vector<dns_msg_answer *> answers;
std::vector<dns_msg_answer *> auth_rrs;
std::vector<dns_msg_answer *> additional_rrs;
};
extern "C"
{
uint16_t

View File

@ -123,6 +123,7 @@ answer_request_alloc(struct dnsc_context *dnsc, void *sock, const char *url,
// register our self with the tracker
dns_tracker *tracker = request->context->tracker;
uint16_t id = ++tracker->c_requests;
if (id == 65535) id = 0;
tracker->client_request[id] = request;
dns_query *dns_packet = build_dns_packet((char *)request->question.name.c_str(), id, 1);
@ -215,7 +216,10 @@ generic_handle_dnsc_recvfrom(dnsc_answer_request *request,
{
question = decode_question((const char *)castBuf);
llarp::LogDebug("Read a question");
castBuf += question->name.length() + 8;
// 1 dot: 1 byte for length + length
// 4 bytes for class/type
castBuf += question->name.length() + 1 + 4;
castBuf += 2; // skip answer label
}
// FIXME: only handling one atm
@ -225,6 +229,11 @@ generic_handle_dnsc_recvfrom(dnsc_answer_request *request,
answer = decode_answer((const char *)castBuf);
llarp::LogDebug("Read an answer");
castBuf += answer->name.length() + 4 + 4 + 4 + answer->rdLen;
auto diff = castBuf - (unsigned char *)buf;
if (diff > sz)
{
break;
}
}
// handle authority records (usually no answers with these, so we'll just
// stomp) usually NS records tho

View File

@ -47,7 +47,7 @@ raw_handle_recvfrom(int *sockfd, const struct sockaddr *saddr, const void *buf,
struct dnsc_context
{
/// Target: DNS server hostname/port to use
// FIXME: ipv6 it
// FIXME: ipv6 it & make it a vector
sockaddr *server;
/// tracker
struct dns_tracker *tracker;

View File

@ -1,3 +1,5 @@
#include <llarp/logic.h>
#include "dnsd.hpp"
#include <llarp/dns.h>
#include <string>
@ -35,22 +37,6 @@ llarp_sendto_dns_hook_func(void *sock, const struct sockaddr *from,
return llarp_ev_udp_sendto(udp, from, buffer, length);
}
std::string const default_chars =
"abcdefghijklmnaoqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
#include <random>
std::string random_string(size_t len = 15, std::string const &allowed_chars = default_chars) {
std::mt19937_64 gen { std::random_device()() };
std::uniform_int_distribution<size_t> dist { 0, allowed_chars.length()-1 };
std::string ret;
std::generate_n(std::back_inserter(ret), len, [&] { return allowed_chars[dist(gen)]; });
return ret;
}
void
write404_dnss_response(const struct sockaddr *from, dnsd_question_request *request)
{
@ -87,7 +73,7 @@ write404_dnss_response(const struct sockaddr *from, dnsd_question_request *reque
*write_buffer++ = 0; // write a null byte
uint out_bytes = write_buffer - bufferBegin;
llarp::LogDebug("Sending ", out_bytes, " bytes");
llarp::LogDebug("Sending 404, ", out_bytes, " bytes");
// struct llarp_udp_io *udp = (struct llarp_udp_io *)request->user;
request->sendto_hook(request->user, from, buf, out_bytes);
}
@ -152,13 +138,13 @@ writecname_dnss_response(std::string cname, const struct sockaddr *from,
put32bits(write_buffer, 1); // ttl
put16bits(write_buffer, 4); // rdLength
*write_buffer++ = 172;
*write_buffer++ = 16;
*write_buffer++ = 127;
*write_buffer++ = 0;
*write_buffer++ = 117;
*write_buffer++ = 0;
*write_buffer++ = 1;
uint out_bytes = write_buffer - bufferBegin;
llarp::LogDebug("Sending ", out_bytes, " bytes");
llarp::LogDebug("Sending cname, ", out_bytes, " bytes");
// struct llarp_udp_io *udp = (struct llarp_udp_io *)request->user;
request->sendto_hook(request->user, from, buf, out_bytes);
}
@ -169,13 +155,12 @@ void
writesend_dnss_response(struct sockaddr *hostRes, const struct sockaddr *from,
dnsd_question_request *request)
{
//llarp::Addr test(*from);
//llarp::LogInfo("from ", test);
if(!hostRes)
{
llarp::LogWarn("Failed to resolve");
// FIXME: actually return correct packet
//write404_dnss_response(from, request);
usleep(1000*1000);
writecname_dnss_response(random_string(32, "abcdefghijklmnopqrstuvwxyz")+"bob.loki", from, request);
write404_dnss_response(from, request);
return;
}
@ -218,7 +203,7 @@ writesend_dnss_response(struct sockaddr *hostRes, const struct sockaddr *from,
*write_buffer++ = ip[3];
uint out_bytes = write_buffer - bufferBegin;
llarp::LogDebug("Sending ", out_bytes, " bytes");
llarp::LogDebug("Sending found, ", out_bytes, " bytes");
// struct llarp_udp_io *udp = (struct llarp_udp_io *)request->user;
request->sendto_hook(request->user, from, buf, out_bytes);
}
@ -281,26 +266,38 @@ handle_recvfrom(const char *buffer, ssize_t nbytes, const struct sockaddr *from,
llarp::LogInfo("DNS request from ", test2);
*/
sockaddr *fromCopy = new sockaddr(*from); // make our own sockaddr that won't get cleaned up
if(request->context->intercept)
{
sockaddr *intercept = request->context->intercept(request->question.name, request->context);
//llarp::Addr test(*from);
//llarp::LogInfo("from ", test);
dnsd_query_hook_response *intercept = request->context->intercept(request->question.name, fromCopy, request);
if(intercept != nullptr)
{
// told that hook will handle overrides
sockaddr *fromCopy = new sockaddr(*from);
writesend_dnss_response(intercept, fromCopy, request);
return;
llarp::LogDebug("hook returned a response");
if (intercept->dontSendResponse)
{
llarp::LogDebug("HOOKED: Not sending a response");
return;
}
if (intercept->dontLookUp == true && intercept->returnThis)
{
llarp::LogDebug("HOOKED: sending an immediate override");
// told that hook will handle overrides
writesend_dnss_response(intercept->returnThis, fromCopy, request);
return;
}
}
}
// FIXME: check request's context
// FIXME: check request and context's client
if (!request->context)
{
llarp::LogError("dnsd request context was not a dnsd context");
sockaddr *fromCopy = new sockaddr(*from);
writesend_dnss_response(nullptr, fromCopy, request);
return;
}
/*
struct dns_tracker *tracker = (struct dns_tracker *)request->context->tracker;
if (!tracker)
{
@ -317,16 +314,18 @@ handle_recvfrom(const char *buffer, ssize_t nbytes, const struct sockaddr *from,
writesend_dnss_response(nullptr, fromCopy, request);
return;
}
*/
if(request->llarp)
{
// make async request
llarp_resolve_host(&dnsd->client, m_qName.c_str(), &handle_dnsc_result,
llarp_resolve_host(&request->context->client, m_qName.c_str(), &handle_dnsc_result,
(void *)request);
}
else
{
// make raw/sync request
raw_resolve_host(&dnsd->client, m_qName.c_str(), &handle_dnsc_result,
raw_resolve_host(&request->context->client, m_qName.c_str(), &handle_dnsc_result,
(void *)request);
}
}
@ -373,6 +372,7 @@ raw_handle_recvfrom(int *sockfd, const struct sockaddr *saddr, const void *buf,
bool
llarp_dnsd_init(struct dnsd_context *dnsd, struct llarp_ev_loop *netloop,
struct llarp_logic *logic,
const char *dnsd_ifname, uint16_t dnsd_port,
const char *dnsc_hostname, uint16_t dnsc_port)
{
@ -388,6 +388,7 @@ llarp_dnsd_init(struct dnsd_context *dnsd, struct llarp_ev_loop *netloop,
dns_udp_tracker.dnsd = dnsd;
dnsd->tracker = &dns_udp_tracker; // register global tracker with context
dnsd->logic = logic; // set logic worker for timers
dnsd->intercept = nullptr; // set default intercepter
// configure dns client

View File

@ -31,16 +31,29 @@ struct dnsd_question_request
dnsd_context *context; // or you can access it via user (udp)
};
// FIXME: made better as a two way structure, collapse the request and response together
struct dnsd_query_hook_response
{
/// turn off communication
bool dontSendResponse;
/// turn off recursion
bool dontLookUp;
/// potential address
sockaddr *returnThis;
};
/// intercept query hook functor
// we could have passed in the source sockaddr in case you wanted to
// handle the response yourself
typedef sockaddr *(*intercept_query_hook)(std::string name, struct dnsd_context *context);
typedef dnsd_query_hook_response *(*intercept_query_hook)(std::string name,
const struct sockaddr *from,
struct dnsd_question_request *request);
/// DNS Server context
struct dnsd_context
{
/// DNS daemon socket to listen on
struct llarp_udp_io udp;
/// for timers (MAYBEFIXME? maybe we decouple this)
struct llarp_logic *logic;
/// tracker
struct dns_tracker *tracker;
/// upstream DNS client context to use
@ -57,10 +70,17 @@ llarp_handle_dnsd_recvfrom(struct llarp_udp_io *udp,
const struct sockaddr *saddr, const void *buf,
ssize_t sz);
/// for hook functions to use
void
writecname_dnss_response(std::string cname, const struct sockaddr *from,
dnsd_question_request *request);
/// initialize dns subsystem and bind socket
/// returns true on bind success otherwise returns false
bool
llarp_dnsd_init(struct dnsd_context *dnsd, struct llarp_ev_loop *netloop,
struct llarp_logic *logic,
const char *dnsd_ifname, uint16_t dnsd_port,
const char *dnsc_hostname, uint16_t dnsc_port);