Skip to content

Poisonlicious #1250

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
918 changes: 495 additions & 423 deletions Makefile.in

Large diffs are not rendered by default.

102 changes: 90 additions & 12 deletions daemon/worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "util/log.h"
#include "util/net_help.h"
#include "util/random.h"
#include "util/tsig.h"
#include "daemon/worker.h"
#include "daemon/daemon.h"
#include "daemon/remote.h"
Expand Down Expand Up @@ -78,6 +79,7 @@
#include "respip/respip.h"
#include "libunbound/context.h"
#include "libunbound/libworker.h"
#include "sldns/parseutil.h"
#include "sldns/sbuffer.h"
#include "sldns/wire2str.h"
#include "util/shm_side/shm_main.h"
Expand Down Expand Up @@ -272,6 +274,11 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
return 0;
}

#define REQUEST_OK 0
#define DROP_REQUEST -1
#define RESPONSE_MESSAGE -2


/** ratelimit error replies
* @param worker: the worker struct with ratelimit counter
* @param err: error code that would be wanted.
Expand All @@ -283,7 +290,7 @@ worker_err_ratelimit(struct worker* worker, int err)
if(worker->err_limit_time == *worker->env.now) {
/* see if limit is exceeded for this second */
if(worker->err_limit_count++ > ERROR_RATELIMIT)
return -1;
return DROP_REQUEST;
} else {
/* new second, new limits */
worker->err_limit_time = *worker->env.now;
Expand All @@ -296,6 +303,9 @@ worker_err_ratelimit(struct worker* worker, int err)
* Structure holding the result of the worker_check_request function.
* Based on configuration it could be called up to four times; ideally should
* be called once.
* When value is a positive number, it countains the error to return.
* Otherwise DROP_REQUEST (-1) is returned, or RESPONSE_MESSAGE (-2) in
* case the qr bit was set. Value is set to REQUEST_OK (0) if all is good.
*/
struct check_request_result {
int checked;
Expand All @@ -314,18 +324,18 @@ worker_check_request(sldns_buffer* pkt, struct worker* worker,
out->checked = 1;
if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
verbose(VERB_QUERY, "request too short, discarded");
out->value = -1;
out->value = DROP_REQUEST;
return;
}
if(sldns_buffer_limit(pkt) > NORMAL_UDP_SIZE &&
worker->daemon->cfg->harden_large_queries) {
verbose(VERB_QUERY, "request too large, discarded");
out->value = -1;
out->value = DROP_REQUEST;
return;
}
if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) {
verbose(VERB_QUERY, "request has QR bit on, discarded");
out->value = -1;
/* verbose(VERB_QUERY, "request has QR bit on, discarded"); */
out->value = RESPONSE_MESSAGE;
return;
}
if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
Expand Down Expand Up @@ -367,10 +377,39 @@ worker_check_request(sldns_buffer* pkt, struct worker* worker,
out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
return;
}
out->value = 0;
out->value = REQUEST_OK;
return;
}

/** check response sanity.
* @param pkt: the wire packet to examine for sanity.
* @param worker: parameters for checking.
* @param out: 1 on success, otherwise 0.
*/
static int
worker_check_response(sldns_buffer* pkt, struct worker* worker)
{
if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
LDNS_TC_CLR(sldns_buffer_begin(pkt));
verbose(VERB_QUERY, "response bad, has TC bit on");
return 0;
}
if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) {
verbose(VERB_QUERY, "not a query response");
return 0;
}
if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) {
verbose(VERB_QUERY, "request wrong nr qd=%d",
LDNS_QDCOUNT(sldns_buffer_begin(pkt)));
return 0;
}
if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) == 0) {
verbose(VERB_QUERY, "response must be an answer message");
return 0;
}
return 1;
}

void
worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg,
size_t len, int error, void* arg)
Expand Down Expand Up @@ -1138,8 +1177,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
if(worker->stats.extended)
worker->stats.unwanted_queries++;
worker_check_request(c->buffer, worker, check_result);
if(check_result->value != 0) {
if(check_result->value != -1) {
if(check_result->value != REQUEST_OK) {
if(check_result->value > 0) {
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
check_result->value);
Expand Down Expand Up @@ -1416,7 +1455,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
char buf[LDNS_MAX_DOMAINLEN];
/* Check if this is unencrypted and asking for certs */
worker_check_request(c->buffer, worker, &check_result);
if(check_result.value != 0) {
if(check_result.value != REQUEST_OK) {
verbose(VERB_ALGO,
"dnscrypt: worker check request: bad query.");
log_addr(VERB_CLIENT,"from",&repinfo->client_addr,
Expand Down Expand Up @@ -1479,10 +1518,49 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
}

worker_check_request(c->buffer, worker, &check_result);
if(check_result.value != 0) {
if (check_result.value == RESPONSE_MESSAGE) {
struct reply_info *rep = NULL;
int r;
const char* tsig_name = "\x19""foobar-example-dyn-update\x00";
const char* alg = "\x0b""hmac-sha256\x00";
const char* tsig_secret =
"\x59\x2E\xD3\xD0\x84\xA8\x69\x5F\x8C\xCA\x07\xBE\x1B\xFC\x1E\x98\x74\xE7\xF6\x64\x30\x32\x10\xC6\x33\x09\x93\x94\x9D\xF1\x71\x74\x42\x27\xAB\xF5\x11\x59\x0D\x2E\x52\x2F\xBD\xA8\x7E\xD9\xEA\xD6\x8F\x3D\x6F\xD2\x60\x56\xD8\xD3\xCA\x02\xB7\x16\x1C\x43\x6D\xB8";
const size_t tsig_secret_len = 64;

if (!worker_check_response(c->buffer, worker)) {
verbose(VERB_ALGO, "Bad response");
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
comm_point_drop_reply(repinfo);
return 0;
}
if((r = tsig_verify(c->buffer, tsig_name, alg, tsig_secret,
tsig_secret_len, *worker->env.now))) {
verbose(VERB_ALGO, "worker tsig very of response: %s",
sldns_lookup_by_id(sldns_tsig_errors, r)?
sldns_lookup_by_id(sldns_tsig_errors, r)->name:"??");
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
comm_point_drop_reply(repinfo);
return 0;
}
if((r = reply_info_parse(c->buffer, worker->env.alloc, &qinfo,
&rep, worker->scratchpad, &edns))) {
verbose(VERB_ALGO, "worker parse response: %s",
sldns_lookup_by_id(sldns_rcodes, r)?
sldns_lookup_by_id(sldns_rcodes, r)->name:"??");
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
comm_point_drop_reply(repinfo);
return 0;
}
dns_cache_store(&worker->env, &qinfo, rep, 0 /* is_referral */,
0 /* leeway */, 0 /* pside */,
NULL /* region */, 0 /* flags */,
*worker->env.now, 0 /* is_valrec */);
comm_point_drop_reply(repinfo);
return 0;
} else if(check_result.value != REQUEST_OK) {
verbose(VERB_ALGO, "worker check request: bad query.");
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
if(check_result.value != -1) {
if(check_result.value > REQUEST_OK) {
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
check_result.value);
Expand Down Expand Up @@ -2195,7 +2273,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
worker->daemon->connect_dot_sslctx, cfg->delay_close,
cfg->tls_use_sni, dtenv, cfg->udp_connect,
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
cfg->tcp_auth_query_timeout);
cfg->tcp_auth_query_timeout, cfg->dist, cfg->num_dist);
if(!worker->back) {
log_err("could not create outgoing sockets");
worker_delete(worker);
Expand Down
2 changes: 1 addition & 1 deletion libunbound/libworker.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx,
cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect,
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
cfg->tcp_auth_query_timeout);
cfg->tcp_auth_query_timeout, cfg->dist, cfg->num_dist);
w->env->outnet = w->back;
if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock);
Expand Down
21 changes: 21 additions & 0 deletions services/mesh.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "config.h"
#include "services/mesh.h"
#include "services/outbound_list.h"
#include "services/outside_network.h"
#include "services/cache/dns.h"
#include "services/cache/rrset.h"
#include "services/cache/infra.h"
Expand Down Expand Up @@ -1523,6 +1524,26 @@ void mesh_query_done(struct mesh_state* mstate)
if(err) { log_err("%s", err); }
}
}
if(mstate->reply_list && rep) {
uint8_t data[8192];
struct sldns_buffer dest;
int i;

sldns_buffer_init_frm_data(&dest, data, sizeof(data));
reply_info_answer_encode(&mstate->s.qinfo, rep, 0 /* id */,
0 /* qflags */, &dest, 0 /* current time */,
1 /* cached */, mstate->s.env->scratch,
sizeof(data) /* udpsize */, NULL /* edns */,
1 /* dnssec */, 0 /* secure */);
log_err("Answer to be send to other unbounds, size: %d",
(int)sldns_buffer_limit(&dest));
for(i = 0; i < mstate->s.env->outnet->num_dist; i++) {
if(mstate->s.env->outnet->dist[i] != -1)
send(mstate->s.env->outnet->dist[i],
data, sldns_buffer_limit(&dest), 0);
}

}
for(r = mstate->reply_list; r; r = r->next) {
struct timeval old;
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
Expand Down
23 changes: 22 additions & 1 deletion services/outside_network.c
Original file line number Diff line number Diff line change
Expand Up @@ -1678,7 +1678,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv,
int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout,
int tcp_auth_query_timeout)
int tcp_auth_query_timeout, char** dist, int num_dist)
{
struct outside_network* outnet = (struct outside_network*)
calloc(1, sizeof(struct outside_network));
Expand Down Expand Up @@ -1819,6 +1819,27 @@ outside_network_create(struct comm_base *base, size_t bufsize,
}
}
}
if (!(outnet->num_dist = num_dist))
outnet->dist = NULL;
else if ((outnet->dist = calloc(num_dist, sizeof(int)))) {
int i;

for(i = 0; i < num_dist; i++) {
struct sockaddr_storage addr;
socklen_t addrlen;
int s = -1;

if(!extstrtoaddr(dist[i], &addr, &addrlen, UNBOUND_DNS_PORT)
|| (s = socket(addr.ss_family, SOCK_DGRAM, 0)) == -1
|| !fd_set_nonblock(s)
|| connect(s, (struct sockaddr*)&addr, addrlen)) {
if(s != -1)
close(s);
s = -1;
}
outnet->dist[i] = s;
}
}
return outnet;
}

Expand Down
6 changes: 5 additions & 1 deletion services/outside_network.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ struct outside_network {
struct waiting_tcp* tcp_wait_first;
/** last of waiting query list */
struct waiting_tcp* tcp_wait_last;
/** number of IP addresses to send to be cached responses to */
int num_dist;
/** udp sockets to the addresses to send to be cached responses to */
int* dist;
};

/**
Expand Down Expand Up @@ -570,7 +574,7 @@ struct outside_network* outside_network_create(struct comm_base* base,
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
void* sslctx, int delayclose, int tls_use_sni, struct dt_env *dtenv,
int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout,
int tcp_auth_query_timeout);
int tcp_auth_query_timeout, char** dist, int num_dist);

/**
* Delete outside_network structure.
Expand Down
38 changes: 38 additions & 0 deletions sldns/sbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ sldns_read_uint32(const void *src)
#endif
}

INLINE uint64_t
sldns_read_uint48(const void *src)
{
const uint8_t *p = (const uint8_t *) src;
return ( ((uint64_t) p[0] << 40)
| ((uint64_t) p[1] << 32)
| ((uint64_t) p[2] << 24)
| ((uint64_t) p[3] << 16)
| ((uint64_t) p[4] << 8)
| (uint64_t) p[5]);
}

/*
* Copy data allowing for unaligned accesses in network byte order
* (big endian).
Expand Down Expand Up @@ -693,6 +705,32 @@ sldns_buffer_read_u32(sldns_buffer *buffer)
return result;
}

/**
* returns the 6-byte integer value at the given position in the buffer
* \param[in] buffer the buffer
* \param[in] at position in the buffer
* \return 6 byte integer
*/
INLINE uint64_t
sldns_buffer_read_u48_at(sldns_buffer *buffer, size_t at)
{
assert(sldns_buffer_available_at(buffer, at, 6));
return sldns_read_uint48(buffer->_data + at);
}

/**
* returns the 6-byte integer value at the current position in the buffer
* \param[in] buffer the buffer
* \return 6 byte integer
*/
INLINE uint64_t
sldns_buffer_read_u48(sldns_buffer *buffer)
{
uint64_t result = sldns_buffer_read_u48_at(buffer, buffer->_position);
buffer->_position += 6;
return result;
}

/**
* returns the status of the buffer
* \param[in] buffer
Expand Down
3 changes: 2 additions & 1 deletion testcode/fake_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -1118,7 +1118,8 @@ outside_network_create(struct comm_base* base, size_t bufsize,
int ATTR_UNUSED(delayclose), int ATTR_UNUSED(tls_use_sni),
struct dt_env* ATTR_UNUSED(dtenv), int ATTR_UNUSED(udp_connect),
int ATTR_UNUSED(max_reuse_tcp_queries), int ATTR_UNUSED(tcp_reuse_timeout),
int ATTR_UNUSED(tcp_auth_query_timeout))
int ATTR_UNUSED(tcp_auth_query_timeout), char** ATTR_UNUSED(num_dist),
int ATTR_UNUSED(dist))
{
struct replay_runtime* runtime = (struct replay_runtime*)base;
struct outside_network* outnet = calloc(1,
Expand Down
4 changes: 4 additions & 0 deletions util/config_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ config_create(void)
cfg->ip_dscp = 0;
cfg->num_ifs = 0;
cfg->ifs = NULL;
cfg->num_dist = 0;
cfg->dist = NULL;
cfg->num_out_ifs = 0;
cfg->out_ifs = NULL;
cfg->stubs = NULL;
Expand Down Expand Up @@ -1090,6 +1092,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_YNO(opt, "log-time-iso", log_time_iso)
else O_DEC(opt, "num-threads", num_threads)
else O_IFC(opt, "interface", num_ifs, ifs)
else O_IFC(opt, "distribute", num_dist, dist)
else O_IFC(opt, "outgoing-interface", num_out_ifs, out_ifs)
else O_YNO(opt, "interface-automatic", if_automatic)
else O_STR(opt, "interface-automatic-ports", if_automatic_ports)
Expand Down Expand Up @@ -1692,6 +1695,7 @@ config_delete(struct config_file* cfg)
free(cfg->log_identity);
}
config_del_strarray(cfg->ifs, cfg->num_ifs);
config_del_strarray(cfg->dist, cfg->num_dist);
config_del_strarray(cfg->out_ifs, cfg->num_out_ifs);
config_delstubs(cfg->stubs);
config_delstubs(cfg->forwards);
Expand Down
5 changes: 5 additions & 0 deletions util/config_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@ struct config_file {
/** interface description strings (IP addresses) */
char **ifs;

/** number of addresses to distribute new responses. */
int num_dist;
/** distribute description strings (IP addresses) */
char **dist;

/** number of outgoing interfaces to open.
* If 0 default all interfaces. */
int num_out_ifs;
Expand Down
1 change: 1 addition & 0 deletions util/configlexer.lex
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ use-systemd{COLON} { YDVAR(1, VAR_USE_SYSTEMD) }
do-daemonize{COLON} { YDVAR(1, VAR_DO_DAEMONIZE) }
interface{COLON} { YDVAR(1, VAR_INTERFACE) }
ip-address{COLON} { YDVAR(1, VAR_INTERFACE) }
distribute{COLON} { YDVAR(1, VAR_DISTRIBUTE ) }
outgoing-interface{COLON} { YDVAR(1, VAR_OUTGOING_INTERFACE) }
interface-automatic{COLON} { YDVAR(1, VAR_INTERFACE_AUTOMATIC) }
interface-automatic-ports{COLON} { YDVAR(1, VAR_INTERFACE_AUTOMATIC_PORTS) }
Expand Down
Loading