mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
- dns over ssl support, ssl-service-pem and ssl-service-key files
can be given and then TCP queries are serviced wrapped in SSL. git-svn-id: file:///svn/unbound/trunk@2530 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
28131d5845
commit
aa0536dcb5
26 changed files with 2315 additions and 1601 deletions
20
Makefile.in
20
Makefile.in
|
|
@ -239,7 +239,7 @@ endif
|
||||||
libunbound.la: $(LIBUNBOUND_OBJ)
|
libunbound.la: $(LIBUNBOUND_OBJ)
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
ifeq ($(CHECKLOCK_SRC),)
|
ifeq ($(CHECKLOCK_SRC),)
|
||||||
$Q$(LINK_LIB) $(UBSYMS) -o $@ $(sort $(LIBUNBOUND_OBJ)) -rpath $(libdir) $(LIBS)
|
$Q$(LINK_LIB) $(UBSYMS) -o $@ $(sort $(LIBUNBOUND_OBJ)) -rpath $(libdir) -lssl $(LIBS)
|
||||||
else
|
else
|
||||||
cp $(srcdir)/libunbound/ubsyms.def $(BUILD)clubsyms.def
|
cp $(srcdir)/libunbound/ubsyms.def $(BUILD)clubsyms.def
|
||||||
echo lock_protect >> $(BUILD)clubsyms.def
|
echo lock_protect >> $(BUILD)clubsyms.def
|
||||||
|
|
@ -252,7 +252,7 @@ else
|
||||||
echo checklock_init >> $(BUILD)clubsyms.def
|
echo checklock_init >> $(BUILD)clubsyms.def
|
||||||
echo checklock_thrcreate >> $(BUILD)clubsyms.def
|
echo checklock_thrcreate >> $(BUILD)clubsyms.def
|
||||||
echo checklock_thrjoin >> $(BUILD)clubsyms.def
|
echo checklock_thrjoin >> $(BUILD)clubsyms.def
|
||||||
$Q$(LINK_LIB) $(CLUBSYMS) -o $@ $(sort $(LIBUNBOUND_OBJ)) -rpath $(libdir) $(LIBS)
|
$Q$(LINK_LIB) $(CLUBSYMS) -o $@ $(sort $(LIBUNBOUND_OBJ)) -rpath $(libdir) -lssl $(LIBS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
unbound$(EXEEXT): $(DAEMON_OBJ) libunbound.la
|
unbound$(EXEEXT): $(DAEMON_OBJ) libunbound.la
|
||||||
|
|
@ -289,7 +289,7 @@ anchor-update$(EXEEXT): $(ANCHORUPD_OBJ) libunbound.la
|
||||||
|
|
||||||
unittest$(EXEEXT): $(UNITTEST_OBJ)
|
unittest$(EXEEXT): $(UNITTEST_OBJ)
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
$Q$(LINK) -o $@ $(sort $(UNITTEST_OBJ)) $(LIBS)
|
$Q$(LINK) -o $@ $(sort $(UNITTEST_OBJ)) -lssl $(LIBS)
|
||||||
|
|
||||||
testbound$(EXEEXT): $(TESTBOUND_OBJ)
|
testbound$(EXEEXT): $(TESTBOUND_OBJ)
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
|
|
@ -297,7 +297,7 @@ testbound$(EXEEXT): $(TESTBOUND_OBJ)
|
||||||
|
|
||||||
lock-verify$(EXEEXT): $(LOCKVERIFY_OBJ)
|
lock-verify$(EXEEXT): $(LOCKVERIFY_OBJ)
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
$Q$(LINK) -o $@ $(sort $(LOCKVERIFY_OBJ)) $(LIBS)
|
$Q$(LINK) -o $@ $(sort $(LOCKVERIFY_OBJ)) -lssl $(LIBS)
|
||||||
|
|
||||||
petal$(EXEEXT): $(PETAL_OBJ)
|
petal$(EXEEXT): $(PETAL_OBJ)
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
|
|
@ -305,15 +305,15 @@ petal$(EXEEXT): $(PETAL_OBJ)
|
||||||
|
|
||||||
pktview$(EXEEXT): $(PKTVIEW_OBJ)
|
pktview$(EXEEXT): $(PKTVIEW_OBJ)
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
$Q$(LINK) -o $@ $(sort $(PKTVIEW_OBJ)) $(LIBS)
|
$Q$(LINK) -o $@ $(sort $(PKTVIEW_OBJ)) -lssl $(LIBS)
|
||||||
|
|
||||||
signit$(EXEEXT): $(SIGNIT_OBJ)
|
signit$(EXEEXT): $(SIGNIT_OBJ)
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
$Q$(LINK) -o $@ $(sort $(SIGNIT_OBJ)) $(LIBS)
|
$Q$(LINK) -o $@ $(sort $(SIGNIT_OBJ)) -lssl $(LIBS)
|
||||||
|
|
||||||
memstats$(EXEEXT): $(MEMSTATS_OBJ)
|
memstats$(EXEEXT): $(MEMSTATS_OBJ)
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
$Q$(LINK) -o $@ $(sort $(MEMSTATS_OBJ)) $(LIBS)
|
$Q$(LINK) -o $@ $(sort $(MEMSTATS_OBJ)) -lssl $(LIBS)
|
||||||
|
|
||||||
asynclook$(EXEEXT): $(ASYNCLOOK_OBJ) libunbound.la
|
asynclook$(EXEEXT): $(ASYNCLOOK_OBJ) libunbound.la
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
|
|
@ -321,15 +321,15 @@ asynclook$(EXEEXT): $(ASYNCLOOK_OBJ) libunbound.la
|
||||||
|
|
||||||
streamtcp$(EXEEXT): $(STREAMTCP_OBJ)
|
streamtcp$(EXEEXT): $(STREAMTCP_OBJ)
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
$Q$(LINK) -o $@ $(sort $(STREAMTCP_OBJ)) $(LIBS)
|
$Q$(LINK) -o $@ $(sort $(STREAMTCP_OBJ)) -lssl $(LIBS)
|
||||||
|
|
||||||
perf$(EXEEXT): $(PERF_OBJ)
|
perf$(EXEEXT): $(PERF_OBJ)
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
$Q$(LINK) -o $@ $(sort $(PERF_OBJ)) $(LIBS)
|
$Q$(LINK) -o $@ $(sort $(PERF_OBJ)) -lssl $(LIBS)
|
||||||
|
|
||||||
delayer$(EXEEXT): $(DELAYER_OBJ)
|
delayer$(EXEEXT): $(DELAYER_OBJ)
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
$Q$(LINK) -o $@ $(sort $(DELAYER_OBJ)) $(LIBS)
|
$Q$(LINK) -o $@ $(sort $(DELAYER_OBJ)) -lssl $(LIBS)
|
||||||
|
|
||||||
harvest$(EXEEXT): $(HARVEST_OBJ) libunbound.la
|
harvest$(EXEEXT): $(HARVEST_OBJ) libunbound.la
|
||||||
$(INFO) Link $@
|
$(INFO) Link $@
|
||||||
|
|
|
||||||
|
|
@ -528,6 +528,8 @@ daemon_delete(struct daemon* daemon)
|
||||||
free(daemon->chroot);
|
free(daemon->chroot);
|
||||||
free(daemon->pidfile);
|
free(daemon->pidfile);
|
||||||
free(daemon->env);
|
free(daemon->env);
|
||||||
|
SSL_CTX_free((SSL_CTX*)daemon->listen_sslctx);
|
||||||
|
SSL_CTX_free((SSL_CTX*)daemon->connect_sslctx);
|
||||||
free(daemon);
|
free(daemon);
|
||||||
#ifdef LEX_HAS_YYLEX_DESTROY
|
#ifdef LEX_HAS_YYLEX_DESTROY
|
||||||
/* lex cleanup */
|
/* lex cleanup */
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,8 @@ struct daemon {
|
||||||
struct listen_port* rc_ports;
|
struct listen_port* rc_ports;
|
||||||
/** remote control connections management (for first worker) */
|
/** remote control connections management (for first worker) */
|
||||||
struct daemon_remote* rc;
|
struct daemon_remote* rc;
|
||||||
|
/** ssl context for listening to dnstcp over ssl, and connecting ssl */
|
||||||
|
void* listen_sslctx, *connect_sslctx;
|
||||||
/** num threads allocated */
|
/** num threads allocated */
|
||||||
int num;
|
int num;
|
||||||
/** the worker entries */
|
/** the worker entries */
|
||||||
|
|
|
||||||
|
|
@ -92,21 +92,6 @@
|
||||||
/** if true, inhibits a lot of =0 lines from the stats output */
|
/** if true, inhibits a lot of =0 lines from the stats output */
|
||||||
static const int inhibit_zero = 1;
|
static const int inhibit_zero = 1;
|
||||||
|
|
||||||
/** log ssl crypto err */
|
|
||||||
static void
|
|
||||||
log_crypto_err(const char* str)
|
|
||||||
{
|
|
||||||
/* error:[error code]:[library name]:[function name]:[reason string] */
|
|
||||||
char buf[128];
|
|
||||||
unsigned long e;
|
|
||||||
ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
|
|
||||||
log_err("%s crypto %s", str, buf);
|
|
||||||
while( (e=ERR_get_error()) ) {
|
|
||||||
ERR_error_string_n(e, buf, sizeof(buf));
|
|
||||||
log_err("and additionally crypto %s", buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** subtract timers and the values do not overflow or become negative */
|
/** subtract timers and the values do not overflow or become negative */
|
||||||
static void
|
static void
|
||||||
timeval_subtract(struct timeval* d, const struct timeval* end,
|
timeval_subtract(struct timeval* d, const struct timeval* end,
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
#include "services/cache/infra.h"
|
#include "services/cache/infra.h"
|
||||||
#include "util/data/msgreply.h"
|
#include "util/data/msgreply.h"
|
||||||
#include "util/module.h"
|
#include "util/module.h"
|
||||||
|
#include "util/net_help.h"
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
|
|
@ -446,6 +447,13 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
|
||||||
/* read ssl keys while superuser and outside chroot */
|
/* read ssl keys while superuser and outside chroot */
|
||||||
if(!(daemon->rc = daemon_remote_create(cfg)))
|
if(!(daemon->rc = daemon_remote_create(cfg)))
|
||||||
fatal_exit("could not set up remote-control");
|
fatal_exit("could not set up remote-control");
|
||||||
|
if(cfg->ssl_service_key && cfg->ssl_service_key[0]) {
|
||||||
|
if(!(daemon->listen_sslctx = listen_sslctx_create(
|
||||||
|
cfg->ssl_service_key, cfg->ssl_service_pem, NULL)))
|
||||||
|
fatal_exit("could not set up listen SSL_CTX");
|
||||||
|
}
|
||||||
|
if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL, NULL)))
|
||||||
|
fatal_exit("could not set up connect SSL_CTX");
|
||||||
|
|
||||||
#ifdef HAVE_KILL
|
#ifdef HAVE_KILL
|
||||||
/* check old pid file before forking */
|
/* check old pid file before forking */
|
||||||
|
|
|
||||||
|
|
@ -1092,7 +1092,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||||
}
|
}
|
||||||
worker->front = listen_create(worker->base, ports,
|
worker->front = listen_create(worker->base, ports,
|
||||||
cfg->msg_buffer_size, (int)cfg->incoming_num_tcp,
|
cfg->msg_buffer_size, (int)cfg->incoming_num_tcp,
|
||||||
worker_handle_request, worker);
|
worker->daemon->listen_sslctx, worker_handle_request, worker);
|
||||||
if(!worker->front) {
|
if(!worker->front) {
|
||||||
log_err("could not create listening sockets");
|
log_err("could not create listening sockets");
|
||||||
worker_delete(worker);
|
worker_delete(worker);
|
||||||
|
|
@ -1105,7 +1105,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||||
worker->daemon->env->infra_cache, worker->rndstate,
|
worker->daemon->env->infra_cache, worker->rndstate,
|
||||||
cfg->use_caps_bits_for_id, worker->ports, worker->numports,
|
cfg->use_caps_bits_for_id, worker->ports, worker->numports,
|
||||||
cfg->unwanted_threshold, &worker_alloc_cleanup, worker,
|
cfg->unwanted_threshold, &worker_alloc_cleanup, worker,
|
||||||
cfg->do_udp);
|
cfg->do_udp, worker->daemon->connect_sslctx);
|
||||||
if(!worker->back) {
|
if(!worker->back) {
|
||||||
log_err("could not create outgoing sockets");
|
log_err("could not create outgoing sockets");
|
||||||
worker_delete(worker);
|
worker_delete(worker);
|
||||||
|
|
@ -1255,9 +1255,9 @@ worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||||
e->qstate = q;
|
e->qstate = q;
|
||||||
e->qsent = outnet_serviced_query(worker->back, qname,
|
e->qsent = outnet_serviced_query(worker->back, qname,
|
||||||
qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
|
qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
|
||||||
q->env->cfg->tcp_upstream, addr, addrlen, zone, zonelen,
|
q->env->cfg->tcp_upstream || q->env->cfg->ssl_upstream, addr,
|
||||||
worker_handle_service_reply, e, worker->back->udp_buff,
|
addrlen, zone, zonelen, worker_handle_service_reply, e,
|
||||||
&outbound_entry_compare);
|
worker->back->udp_buff, &outbound_entry_compare);
|
||||||
if(!e->qsent) {
|
if(!e->qsent) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
31 October 2011: Wouter
|
||||||
|
- dns over ssl support, ssl-service-pem and ssl-service-key files
|
||||||
|
can be given and then TCP queries are serviced wrapped in SSL.
|
||||||
|
|
||||||
27 October 2011: Wouter
|
27 October 2011: Wouter
|
||||||
- lame-ttl and lame-size options no longer exist, it is integrated
|
- lame-ttl and lame-size options no longer exist, it is integrated
|
||||||
with the host info. They are ignored (with verbose warning) if
|
with the host info. They are ignored (with verbose warning) if
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <ldns/dname.h>
|
#include <ldns/dname.h>
|
||||||
#include <ldns/wire2host.h>
|
#include <ldns/wire2host.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
#include "libunbound/libworker.h"
|
#include "libunbound/libworker.h"
|
||||||
#include "libunbound/context.h"
|
#include "libunbound/context.h"
|
||||||
#include "libunbound/unbound.h"
|
#include "libunbound/unbound.h"
|
||||||
|
|
@ -84,6 +85,7 @@ libworker_delete(struct libworker* w)
|
||||||
ub_randfree(w->env->rnd);
|
ub_randfree(w->env->rnd);
|
||||||
free(w->env);
|
free(w->env);
|
||||||
}
|
}
|
||||||
|
SSL_CTX_free(w->sslctx);
|
||||||
outside_network_delete(w->back);
|
outside_network_delete(w->back);
|
||||||
comm_base_delete(w->base);
|
comm_base_delete(w->base);
|
||||||
free(w);
|
free(w);
|
||||||
|
|
@ -124,6 +126,13 @@ libworker_setup(struct ub_ctx* ctx, int is_bg)
|
||||||
forwards_delete(w->env->fwds);
|
forwards_delete(w->env->fwds);
|
||||||
w->env->fwds = NULL;
|
w->env->fwds = NULL;
|
||||||
}
|
}
|
||||||
|
if(cfg->ssl_upstream) {
|
||||||
|
w->sslctx = connect_sslctx_create(NULL, NULL, NULL);
|
||||||
|
if(!w->sslctx) {
|
||||||
|
libworker_delete(w);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(!w->is_bg || w->is_bg_thread) {
|
if(!w->is_bg || w->is_bg_thread) {
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
}
|
}
|
||||||
|
|
@ -171,7 +180,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg)
|
||||||
cfg->do_tcp?cfg->outgoing_num_tcp:0,
|
cfg->do_tcp?cfg->outgoing_num_tcp:0,
|
||||||
w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
|
w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
|
||||||
ports, numports, cfg->unwanted_threshold,
|
ports, numports, cfg->unwanted_threshold,
|
||||||
&libworker_alloc_cleanup, w, cfg->do_udp);
|
&libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx);
|
||||||
if(!w->is_bg || w->is_bg_thread) {
|
if(!w->is_bg || w->is_bg_thread) {
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
}
|
}
|
||||||
|
|
@ -695,9 +704,9 @@ struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
|
||||||
e->qstate = q;
|
e->qstate = q;
|
||||||
e->qsent = outnet_serviced_query(w->back, qname,
|
e->qsent = outnet_serviced_query(w->back, qname,
|
||||||
qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
|
qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
|
||||||
q->env->cfg->tcp_upstream, addr, addrlen, zone, zonelen,
|
q->env->cfg->tcp_upstream || q->env->cfg->ssl_upstream, addr,
|
||||||
libworker_handle_service_reply, e, w->back->udp_buff,
|
addrlen, zone, zonelen, libworker_handle_service_reply, e,
|
||||||
&outbound_entry_compare);
|
w->back->udp_buff, &outbound_entry_compare);
|
||||||
if(!e->qsent) {
|
if(!e->qsent) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,8 @@ struct libworker {
|
||||||
struct outside_network* back;
|
struct outside_network* back;
|
||||||
/** random() table for this worker. */
|
/** random() table for this worker. */
|
||||||
struct ub_randstate* rndstate;
|
struct ub_randstate* rndstate;
|
||||||
|
/** sslcontext for SSL wrapped DNS over TCP queries */
|
||||||
|
void* sslctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -723,7 +723,7 @@ listen_cp_insert(struct comm_point* c, struct listen_dnsport* front)
|
||||||
|
|
||||||
struct listen_dnsport*
|
struct listen_dnsport*
|
||||||
listen_create(struct comm_base* base, struct listen_port* ports,
|
listen_create(struct comm_base* base, struct listen_port* ports,
|
||||||
size_t bufsize, int tcp_accept_count,
|
size_t bufsize, int tcp_accept_count, void* sslctx,
|
||||||
comm_point_callback_t* cb, void *cb_arg)
|
comm_point_callback_t* cb, void *cb_arg)
|
||||||
{
|
{
|
||||||
struct listen_dnsport* front = (struct listen_dnsport*)
|
struct listen_dnsport* front = (struct listen_dnsport*)
|
||||||
|
|
@ -736,6 +736,9 @@ listen_create(struct comm_base* base, struct listen_port* ports,
|
||||||
free(front);
|
free(front);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if(sslctx) {
|
||||||
|
verbose(VERB_ALGO, "setup for SSL-wrapped TCP service");
|
||||||
|
}
|
||||||
|
|
||||||
/* create comm points as needed */
|
/* create comm points as needed */
|
||||||
while(ports) {
|
while(ports) {
|
||||||
|
|
@ -743,10 +746,11 @@ listen_create(struct comm_base* base, struct listen_port* ports,
|
||||||
if(ports->ftype == listen_type_udp)
|
if(ports->ftype == listen_type_udp)
|
||||||
cp = comm_point_create_udp(base, ports->fd,
|
cp = comm_point_create_udp(base, ports->fd,
|
||||||
front->udp_buff, cb, cb_arg);
|
front->udp_buff, cb, cb_arg);
|
||||||
else if(ports->ftype == listen_type_tcp)
|
else if(ports->ftype == listen_type_tcp) {
|
||||||
cp = comm_point_create_tcp(base, ports->fd,
|
cp = comm_point_create_tcp(base, ports->fd,
|
||||||
tcp_accept_count, bufsize, cb, cb_arg);
|
tcp_accept_count, bufsize, cb, cb_arg);
|
||||||
else if(ports->ftype == listen_type_udpancil)
|
cp->ssl = sslctx;
|
||||||
|
} else if(ports->ftype == listen_type_udpancil)
|
||||||
cp = comm_point_create_udp_ancil(base, ports->fd,
|
cp = comm_point_create_udp_ancil(base, ports->fd,
|
||||||
front->udp_buff, cb, cb_arg);
|
front->udp_buff, cb, cb_arg);
|
||||||
if(!cp) {
|
if(!cp) {
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,7 @@ void listening_ports_free(struct listen_port* list);
|
||||||
* @param bufsize: size of datagram buffer.
|
* @param bufsize: size of datagram buffer.
|
||||||
* @param tcp_accept_count: max number of simultaneous TCP connections
|
* @param tcp_accept_count: max number of simultaneous TCP connections
|
||||||
* from clients.
|
* from clients.
|
||||||
|
* @param sslctx: nonNULL if ssl context.
|
||||||
* @param cb: callback function when a request arrives. It is passed
|
* @param cb: callback function when a request arrives. It is passed
|
||||||
* the packet and user argument. Return true to send a reply.
|
* the packet and user argument. Return true to send a reply.
|
||||||
* @param cb_arg: user data argument for callback function.
|
* @param cb_arg: user data argument for callback function.
|
||||||
|
|
@ -128,7 +129,7 @@ void listening_ports_free(struct listen_port* list);
|
||||||
*/
|
*/
|
||||||
struct listen_dnsport* listen_create(struct comm_base* base,
|
struct listen_dnsport* listen_create(struct comm_base* base,
|
||||||
struct listen_port* ports, size_t bufsize, int tcp_accept_count,
|
struct listen_port* ports, size_t bufsize, int tcp_accept_count,
|
||||||
comm_point_callback_t* cb, void* cb_arg);
|
void* sslctx, comm_point_callback_t* cb, void* cb_arg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* delete the listening structure
|
* delete the listening structure
|
||||||
|
|
|
||||||
|
|
@ -535,7 +535,8 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||||
int do_ip6, size_t num_tcp, struct infra_cache* infra,
|
int do_ip6, size_t num_tcp, struct infra_cache* infra,
|
||||||
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
|
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
|
||||||
int numavailports, size_t unwanted_threshold,
|
int numavailports, size_t unwanted_threshold,
|
||||||
void (*unwanted_action)(void*), void* unwanted_param, int do_udp)
|
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
|
||||||
|
void* sslctx)
|
||||||
{
|
{
|
||||||
struct outside_network* outnet = (struct outside_network*)
|
struct outside_network* outnet = (struct outside_network*)
|
||||||
calloc(1, sizeof(struct outside_network));
|
calloc(1, sizeof(struct outside_network));
|
||||||
|
|
@ -549,6 +550,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||||
outnet->num_tcp = num_tcp;
|
outnet->num_tcp = num_tcp;
|
||||||
outnet->infra = infra;
|
outnet->infra = infra;
|
||||||
outnet->rnd = rnd;
|
outnet->rnd = rnd;
|
||||||
|
outnet->sslctx = sslctx;
|
||||||
outnet->svcd_overhead = 0;
|
outnet->svcd_overhead = 0;
|
||||||
outnet->want_to_quit = 0;
|
outnet->want_to_quit = 0;
|
||||||
outnet->unwanted_threshold = unwanted_threshold;
|
outnet->unwanted_threshold = unwanted_threshold;
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,8 @@ struct outside_network {
|
||||||
struct infra_cache* infra;
|
struct infra_cache* infra;
|
||||||
/** where to get random numbers */
|
/** where to get random numbers */
|
||||||
struct ub_randstate* rnd;
|
struct ub_randstate* rnd;
|
||||||
|
/** ssl context to create ssl wrapped TCP with DNS connections */
|
||||||
|
void* sslctx;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of tcp pending used for outgoing TCP connections.
|
* Array of tcp pending used for outgoing TCP connections.
|
||||||
|
|
@ -369,6 +371,7 @@ struct serviced_query {
|
||||||
* @param unwanted_action: the action to take.
|
* @param unwanted_action: the action to take.
|
||||||
* @param unwanted_param: user parameter to action.
|
* @param unwanted_param: user parameter to action.
|
||||||
* @param do_udp: if udp is done.
|
* @param do_udp: if udp is done.
|
||||||
|
* @param sslctx: context to create outgoing connections with (if enabled).
|
||||||
* @return: the new structure (with no pending answers) or NULL on error.
|
* @return: the new structure (with no pending answers) or NULL on error.
|
||||||
*/
|
*/
|
||||||
struct outside_network* outside_network_create(struct comm_base* base,
|
struct outside_network* outside_network_create(struct comm_base* base,
|
||||||
|
|
@ -376,7 +379,8 @@ struct outside_network* outside_network_create(struct comm_base* base,
|
||||||
int do_ip4, int do_ip6, size_t num_tcp, struct infra_cache* infra,
|
int do_ip4, int do_ip6, size_t num_tcp, struct infra_cache* infra,
|
||||||
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
|
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
|
||||||
int numavailports, size_t unwanted_threshold,
|
int numavailports, size_t unwanted_threshold,
|
||||||
void (*unwanted_action)(void*), void* unwanted_param, int do_udp);
|
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
|
||||||
|
void* sslctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete outside_network structure.
|
* Delete outside_network structure.
|
||||||
|
|
|
||||||
|
|
@ -708,7 +708,7 @@ run_scenario(struct replay_runtime* runtime)
|
||||||
struct listen_dnsport*
|
struct listen_dnsport*
|
||||||
listen_create(struct comm_base* base, struct listen_port* ATTR_UNUSED(ports),
|
listen_create(struct comm_base* base, struct listen_port* ATTR_UNUSED(ports),
|
||||||
size_t bufsize, int ATTR_UNUSED(tcp_accept_count),
|
size_t bufsize, int ATTR_UNUSED(tcp_accept_count),
|
||||||
comm_point_callback_t* cb, void* cb_arg)
|
void* ATTR_UNUSED(sslctx), comm_point_callback_t* cb, void* cb_arg)
|
||||||
{
|
{
|
||||||
struct replay_runtime* runtime = (struct replay_runtime*)base;
|
struct replay_runtime* runtime = (struct replay_runtime*)base;
|
||||||
struct listen_dnsport* l= calloc(1, sizeof(struct listen_dnsport));
|
struct listen_dnsport* l= calloc(1, sizeof(struct listen_dnsport));
|
||||||
|
|
@ -877,7 +877,7 @@ outside_network_create(struct comm_base* base, size_t bufsize,
|
||||||
int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports),
|
int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports),
|
||||||
int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold),
|
int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold),
|
||||||
void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param),
|
void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param),
|
||||||
int ATTR_UNUSED(do_udp))
|
int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx))
|
||||||
{
|
{
|
||||||
struct replay_runtime* runtime = (struct replay_runtime*)base;
|
struct replay_runtime* runtime = (struct replay_runtime*)base;
|
||||||
struct outside_network* outnet = calloc(1,
|
struct outside_network* outnet = calloc(1,
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "util/net_help.h"
|
#include "util/net_help.h"
|
||||||
#include "util/data/msgencode.h"
|
#include "util/data/msgencode.h"
|
||||||
|
#include "util/data/msgparse.h"
|
||||||
#include "util/data/msgreply.h"
|
#include "util/data/msgreply.h"
|
||||||
#include "util/data/dname.h"
|
#include "util/data/dname.h"
|
||||||
|
|
||||||
|
|
@ -65,6 +66,7 @@ static void usage(char* argv[])
|
||||||
printf("-f server what ipaddr@portnr to send the queries to\n");
|
printf("-f server what ipaddr@portnr to send the queries to\n");
|
||||||
printf("-u use UDP. No retries are attempted.\n");
|
printf("-u use UDP. No retries are attempted.\n");
|
||||||
printf("-n do not wait for an answer.\n");
|
printf("-n do not wait for an answer.\n");
|
||||||
|
printf("-s use ssl\n");
|
||||||
printf("-h this help text\n");
|
printf("-h this help text\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +107,7 @@ open_svr(const char* svr, int udp)
|
||||||
|
|
||||||
/** write a query over the TCP fd */
|
/** write a query over the TCP fd */
|
||||||
static void
|
static void
|
||||||
write_q(int fd, int udp, ldns_buffer* buf, int id,
|
write_q(int fd, int udp, SSL* ssl, ldns_buffer* buf, uint16_t id,
|
||||||
const char* strname, const char* strtype, const char* strclass)
|
const char* strname, const char* strtype, const char* strclass)
|
||||||
{
|
{
|
||||||
struct query_info qinfo;
|
struct query_info qinfo;
|
||||||
|
|
@ -128,14 +130,31 @@ write_q(int fd, int udp, ldns_buffer* buf, int id,
|
||||||
|
|
||||||
/* make query */
|
/* make query */
|
||||||
qinfo_query_encode(buf, &qinfo);
|
qinfo_query_encode(buf, &qinfo);
|
||||||
ldns_buffer_write_u16_at(buf, 0, (uint16_t)id);
|
ldns_buffer_write_u16_at(buf, 0, id);
|
||||||
ldns_buffer_write_u16_at(buf, 2, BIT_RD);
|
ldns_buffer_write_u16_at(buf, 2, BIT_RD);
|
||||||
|
|
||||||
|
if(1) {
|
||||||
|
/* add EDNS DO */
|
||||||
|
struct edns_data edns;
|
||||||
|
memset(&edns, 0, sizeof(edns));
|
||||||
|
edns.edns_present = 1;
|
||||||
|
edns.bits = EDNS_DO;
|
||||||
|
edns.udp_size = 4096;
|
||||||
|
attach_edns_record(buf, &edns);
|
||||||
|
}
|
||||||
|
|
||||||
/* send it */
|
/* send it */
|
||||||
if(!udp) {
|
if(!udp) {
|
||||||
len = (uint16_t)ldns_buffer_limit(buf);
|
len = (uint16_t)ldns_buffer_limit(buf);
|
||||||
len = htons(len);
|
len = htons(len);
|
||||||
if(send(fd, (void*)&len, sizeof(len), 0)<(ssize_t)sizeof(len)){
|
if(ssl) {
|
||||||
|
if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) {
|
||||||
|
log_crypto_err("cannot SSL_write");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(send(fd, (void*)&len, sizeof(len), 0) <
|
||||||
|
(ssize_t)sizeof(len)){
|
||||||
#ifndef USE_WINSOCK
|
#ifndef USE_WINSOCK
|
||||||
perror("send() len failed");
|
perror("send() len failed");
|
||||||
#else
|
#else
|
||||||
|
|
@ -145,7 +164,16 @@ write_q(int fd, int udp, ldns_buffer* buf, int id,
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(send(fd, (void*)ldns_buffer_begin(buf), ldns_buffer_limit(buf), 0) <
|
}
|
||||||
|
if(ssl) {
|
||||||
|
if(SSL_write(ssl, (void*)ldns_buffer_begin(buf),
|
||||||
|
(int)ldns_buffer_limit(buf)) <= 0) {
|
||||||
|
log_crypto_err("cannot SSL_write");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(send(fd, (void*)ldns_buffer_begin(buf),
|
||||||
|
ldns_buffer_limit(buf), 0) <
|
||||||
(ssize_t)ldns_buffer_limit(buf)) {
|
(ssize_t)ldns_buffer_limit(buf)) {
|
||||||
#ifndef USE_WINSOCK
|
#ifndef USE_WINSOCK
|
||||||
perror("send() data failed");
|
perror("send() data failed");
|
||||||
|
|
@ -154,19 +182,27 @@ write_q(int fd, int udp, ldns_buffer* buf, int id,
|
||||||
#endif
|
#endif
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
free(qinfo.qname);
|
free(qinfo.qname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** receive DNS datagram over TCP and print it */
|
/** receive DNS datagram over TCP and print it */
|
||||||
static void
|
static void
|
||||||
recv_one(int fd, int udp, ldns_buffer* buf)
|
recv_one(int fd, int udp, SSL* ssl, ldns_buffer* buf)
|
||||||
{
|
{
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
ldns_pkt* pkt;
|
ldns_pkt* pkt;
|
||||||
ldns_status status;
|
ldns_status status;
|
||||||
if(!udp) {
|
if(!udp) {
|
||||||
if(recv(fd, (void*)&len, sizeof(len), 0)<(ssize_t)sizeof(len)){
|
if(ssl) {
|
||||||
|
if(SSL_read(ssl, (void*)&len, (int)sizeof(len)) <= 0) {
|
||||||
|
log_crypto_err("could not SSL_read");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(recv(fd, (void*)&len, sizeof(len), 0) <
|
||||||
|
(ssize_t)sizeof(len)) {
|
||||||
#ifndef USE_WINSOCK
|
#ifndef USE_WINSOCK
|
||||||
perror("read() len failed");
|
perror("read() len failed");
|
||||||
#else
|
#else
|
||||||
|
|
@ -175,9 +211,20 @@ recv_one(int fd, int udp, ldns_buffer* buf)
|
||||||
#endif
|
#endif
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
len = ntohs(len);
|
len = ntohs(len);
|
||||||
ldns_buffer_clear(buf);
|
ldns_buffer_clear(buf);
|
||||||
ldns_buffer_set_limit(buf, len);
|
ldns_buffer_set_limit(buf, len);
|
||||||
|
if(ssl) {
|
||||||
|
int r = SSL_read(ssl, (void*)ldns_buffer_begin(buf),
|
||||||
|
(int)len);
|
||||||
|
if(r <= 0) {
|
||||||
|
log_crypto_err("could not SSL_read");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if(r != (int)len)
|
||||||
|
fatal_exit("ssl_read %d of %d", r, len);
|
||||||
|
} else {
|
||||||
if(recv(fd, (void*)ldns_buffer_begin(buf), len, 0) <
|
if(recv(fd, (void*)ldns_buffer_begin(buf), len, 0) <
|
||||||
(ssize_t)len) {
|
(ssize_t)len) {
|
||||||
#ifndef USE_WINSOCK
|
#ifndef USE_WINSOCK
|
||||||
|
|
@ -188,6 +235,7 @@ recv_one(int fd, int udp, ldns_buffer* buf)
|
||||||
#endif
|
#endif
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ssize_t l;
|
ssize_t l;
|
||||||
ldns_buffer_clear(buf);
|
ldns_buffer_clear(buf);
|
||||||
|
|
@ -220,20 +268,34 @@ recv_one(int fd, int udp, ldns_buffer* buf)
|
||||||
|
|
||||||
/** send the TCP queries and print answers */
|
/** send the TCP queries and print answers */
|
||||||
static void
|
static void
|
||||||
send_em(const char* svr, int udp, int noanswer, int num, char** qs)
|
send_em(const char* svr, int udp, int usessl, int noanswer, int num, char** qs)
|
||||||
{
|
{
|
||||||
ldns_buffer* buf = ldns_buffer_new(65553);
|
ldns_buffer* buf = ldns_buffer_new(65553);
|
||||||
int fd = open_svr(svr, udp);
|
int fd = open_svr(svr, udp);
|
||||||
int i;
|
int i;
|
||||||
|
SSL_CTX* ctx;
|
||||||
|
SSL* ssl;
|
||||||
if(!buf) fatal_exit("out of memory");
|
if(!buf) fatal_exit("out of memory");
|
||||||
|
if(usessl) {
|
||||||
|
ctx = connect_sslctx_create(NULL, NULL, NULL);
|
||||||
|
if(!ctx) fatal_exit("cannot create ssl ctx");
|
||||||
|
ssl = outgoing_ssl_fd(ctx, fd);
|
||||||
|
if(!ssl) fatal_exit("cannot create ssl");
|
||||||
|
}
|
||||||
for(i=0; i<num; i+=3) {
|
for(i=0; i<num; i+=3) {
|
||||||
printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
|
printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
|
||||||
write_q(fd, udp, buf, i, qs[i], qs[i+1], qs[i+2]);
|
write_q(fd, udp, ssl, buf, ldns_get_random(), qs[i],
|
||||||
|
qs[i+1], qs[i+2]);
|
||||||
/* print at least one result */
|
/* print at least one result */
|
||||||
if(!noanswer)
|
if(!noanswer)
|
||||||
recv_one(fd, udp, buf);
|
recv_one(fd, udp, ssl, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(usessl) {
|
||||||
|
SSL_shutdown(ssl);
|
||||||
|
SSL_free(ssl);
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
}
|
||||||
#ifndef USE_WINSOCK
|
#ifndef USE_WINSOCK
|
||||||
close(fd);
|
close(fd);
|
||||||
#else
|
#else
|
||||||
|
|
@ -268,6 +330,7 @@ int main(int argc, char** argv)
|
||||||
const char* svr = "127.0.0.1";
|
const char* svr = "127.0.0.1";
|
||||||
int udp = 0;
|
int udp = 0;
|
||||||
int noanswer = 0;
|
int noanswer = 0;
|
||||||
|
int usessl = 0;
|
||||||
|
|
||||||
#ifdef USE_WINSOCK
|
#ifdef USE_WINSOCK
|
||||||
WSADATA wsa_data;
|
WSADATA wsa_data;
|
||||||
|
|
@ -292,7 +355,7 @@ int main(int argc, char** argv)
|
||||||
if(argc == 1) {
|
if(argc == 1) {
|
||||||
usage(argv);
|
usage(argv);
|
||||||
}
|
}
|
||||||
while( (c=getopt(argc, argv, "f:hnu")) != -1) {
|
while( (c=getopt(argc, argv, "f:hnsu")) != -1) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'f':
|
case 'f':
|
||||||
svr = optarg;
|
svr = optarg;
|
||||||
|
|
@ -303,6 +366,9 @@ int main(int argc, char** argv)
|
||||||
case 'u':
|
case 'u':
|
||||||
udp = 1;
|
udp = 1;
|
||||||
break;
|
break;
|
||||||
|
case 's':
|
||||||
|
usessl = 1;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
default:
|
default:
|
||||||
|
|
@ -316,7 +382,12 @@ int main(int argc, char** argv)
|
||||||
printf("queries must be multiples of name,type,class\n");
|
printf("queries must be multiples of name,type,class\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
send_em(svr, udp, noanswer, argc, argv);
|
if(usessl) {
|
||||||
|
ERR_load_SSL_strings();
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
SSL_library_init();
|
||||||
|
}
|
||||||
|
send_em(svr, udp, usessl, noanswer, argc, argv);
|
||||||
checklock_stop();
|
checklock_stop();
|
||||||
#ifdef USE_WINSOCK
|
#ifdef USE_WINSOCK
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,9 @@ config_create(void)
|
||||||
cfg->do_udp = 1;
|
cfg->do_udp = 1;
|
||||||
cfg->do_tcp = 1;
|
cfg->do_tcp = 1;
|
||||||
cfg->tcp_upstream = 0;
|
cfg->tcp_upstream = 0;
|
||||||
|
cfg->ssl_service_key = NULL;
|
||||||
|
cfg->ssl_service_pem = NULL;
|
||||||
|
cfg->ssl_upstream = 0;
|
||||||
cfg->use_syslog = 1;
|
cfg->use_syslog = 1;
|
||||||
cfg->log_time_ascii = 0;
|
cfg->log_time_ascii = 0;
|
||||||
cfg->log_queries = 0;
|
cfg->log_queries = 0;
|
||||||
|
|
@ -326,6 +329,9 @@ int config_set_option(struct config_file* cfg, const char* opt,
|
||||||
else S_YNO("do-udp:", do_udp)
|
else S_YNO("do-udp:", do_udp)
|
||||||
else S_YNO("do-tcp:", do_tcp)
|
else S_YNO("do-tcp:", do_tcp)
|
||||||
else S_YNO("tcp-upstream:", tcp_upstream)
|
else S_YNO("tcp-upstream:", tcp_upstream)
|
||||||
|
else S_YNO("ssl-upstream:", ssl_upstream)
|
||||||
|
else S_STR("ssl-service-key:", ssl_service_key)
|
||||||
|
else S_STR("ssl-service-pem:", ssl_service_pem)
|
||||||
else S_YNO("interface-automatic:", if_automatic)
|
else S_YNO("interface-automatic:", if_automatic)
|
||||||
else S_YNO("do-daemonize:", do_daemonize)
|
else S_YNO("do-daemonize:", do_daemonize)
|
||||||
else S_NUMBER_NONZERO("port:", port)
|
else S_NUMBER_NONZERO("port:", port)
|
||||||
|
|
@ -574,6 +580,9 @@ config_get_option(struct config_file* cfg, const char* opt,
|
||||||
else O_YNO(opt, "do-udp", do_udp)
|
else O_YNO(opt, "do-udp", do_udp)
|
||||||
else O_YNO(opt, "do-tcp", do_tcp)
|
else O_YNO(opt, "do-tcp", do_tcp)
|
||||||
else O_YNO(opt, "tcp-upstream", tcp_upstream)
|
else O_YNO(opt, "tcp-upstream", tcp_upstream)
|
||||||
|
else O_YNO(opt, "ssl-upstream", ssl_upstream)
|
||||||
|
else O_STR(opt, "ssl-service-key", ssl_service_key)
|
||||||
|
else O_STR(opt, "ssl-service-pem", ssl_service_pem)
|
||||||
else O_YNO(opt, "do-daemonize", do_daemonize)
|
else O_YNO(opt, "do-daemonize", do_daemonize)
|
||||||
else O_STR(opt, "chroot", chrootdir)
|
else O_STR(opt, "chroot", chrootdir)
|
||||||
else O_STR(opt, "username", username)
|
else O_STR(opt, "username", username)
|
||||||
|
|
@ -728,6 +737,8 @@ config_delete(struct config_file* cfg)
|
||||||
free(cfg->logfile);
|
free(cfg->logfile);
|
||||||
free(cfg->pidfile);
|
free(cfg->pidfile);
|
||||||
free(cfg->target_fetch_policy);
|
free(cfg->target_fetch_policy);
|
||||||
|
free(cfg->ssl_service_key);
|
||||||
|
free(cfg->ssl_service_pem);
|
||||||
if(cfg->ifs) {
|
if(cfg->ifs) {
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<cfg->num_ifs; i++)
|
for(i=0; i<cfg->num_ifs; i++)
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,13 @@ struct config_file {
|
||||||
/** tcp upstream queries (no UDP upstream queries) */
|
/** tcp upstream queries (no UDP upstream queries) */
|
||||||
int tcp_upstream;
|
int tcp_upstream;
|
||||||
|
|
||||||
|
/** private key file for dnstcp-ssl service (enabled if not NULL) */
|
||||||
|
char* ssl_service_key;
|
||||||
|
/** public key file for dnstcp-ssl service */
|
||||||
|
char* ssl_service_pem;
|
||||||
|
/** if outgoing tcp connections use SSL */
|
||||||
|
int ssl_upstream;
|
||||||
|
|
||||||
/** outgoing port range number of ports (per thread) */
|
/** outgoing port range number of ports (per thread) */
|
||||||
int outgoing_num_ports;
|
int outgoing_num_ports;
|
||||||
/** number of outgoing tcp buffers per (per thread) */
|
/** number of outgoing tcp buffers per (per thread) */
|
||||||
|
|
|
||||||
2149
util/configlexer.c
2149
util/configlexer.c
File diff suppressed because it is too large
Load diff
|
|
@ -137,6 +137,9 @@ do-ip6{COLON} { YDVAR(1, VAR_DO_IP6) }
|
||||||
do-udp{COLON} { YDVAR(1, VAR_DO_UDP) }
|
do-udp{COLON} { YDVAR(1, VAR_DO_UDP) }
|
||||||
do-tcp{COLON} { YDVAR(1, VAR_DO_TCP) }
|
do-tcp{COLON} { YDVAR(1, VAR_DO_TCP) }
|
||||||
tcp-upstream{COLON} { YDVAR(1, VAR_TCP_UPSTREAM) }
|
tcp-upstream{COLON} { YDVAR(1, VAR_TCP_UPSTREAM) }
|
||||||
|
ssl-upstream{COLON} { YDVAR(1, VAR_SSL_UPSTREAM) }
|
||||||
|
ssl-service-key{COLON} { YDVAR(1, VAR_SSL_SERVICE_KEY) }
|
||||||
|
ssl-service-pem{COLON} { YDVAR(1, VAR_SSL_SERVICE_PEM) }
|
||||||
do-daemonize{COLON} { YDVAR(1, VAR_DO_DAEMONIZE) }
|
do-daemonize{COLON} { YDVAR(1, VAR_DO_DAEMONIZE) }
|
||||||
interface{COLON} { YDVAR(1, VAR_INTERFACE) }
|
interface{COLON} { YDVAR(1, VAR_INTERFACE) }
|
||||||
outgoing-interface{COLON} { YDVAR(1, VAR_OUTGOING_INTERFACE) }
|
outgoing-interface{COLON} { YDVAR(1, VAR_OUTGOING_INTERFACE) }
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -156,7 +156,10 @@
|
||||||
VAR_HARDEN_BELOW_NXDOMAIN = 373,
|
VAR_HARDEN_BELOW_NXDOMAIN = 373,
|
||||||
VAR_IGNORE_CD_FLAG = 374,
|
VAR_IGNORE_CD_FLAG = 374,
|
||||||
VAR_LOG_QUERIES = 375,
|
VAR_LOG_QUERIES = 375,
|
||||||
VAR_TCP_UPSTREAM = 376
|
VAR_TCP_UPSTREAM = 376,
|
||||||
|
VAR_SSL_UPSTREAM = 377,
|
||||||
|
VAR_SSL_SERVICE_KEY = 378,
|
||||||
|
VAR_SSL_SERVICE_PEM = 379
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
/* Tokens. */
|
/* Tokens. */
|
||||||
|
|
@ -279,6 +282,9 @@
|
||||||
#define VAR_IGNORE_CD_FLAG 374
|
#define VAR_IGNORE_CD_FLAG 374
|
||||||
#define VAR_LOG_QUERIES 375
|
#define VAR_LOG_QUERIES 375
|
||||||
#define VAR_TCP_UPSTREAM 376
|
#define VAR_TCP_UPSTREAM 376
|
||||||
|
#define VAR_SSL_UPSTREAM 377
|
||||||
|
#define VAR_SSL_SERVICE_KEY 378
|
||||||
|
#define VAR_SSL_SERVICE_PEM 379
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -295,7 +301,7 @@ typedef union YYSTYPE
|
||||||
|
|
||||||
|
|
||||||
/* Line 1685 of yacc.c */
|
/* Line 1685 of yacc.c */
|
||||||
#line 299 "util/configparser.h"
|
#line 305 "util/configparser.h"
|
||||||
} YYSTYPE;
|
} YYSTYPE;
|
||||||
# define YYSTYPE_IS_TRIVIAL 1
|
# define YYSTYPE_IS_TRIVIAL 1
|
||||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,8 @@ extern struct config_parser_state* cfg_parser;
|
||||||
%token VAR_AUTO_TRUST_ANCHOR_FILE VAR_KEEP_MISSING VAR_ADD_HOLDDOWN
|
%token VAR_AUTO_TRUST_ANCHOR_FILE VAR_KEEP_MISSING VAR_ADD_HOLDDOWN
|
||||||
%token VAR_DEL_HOLDDOWN VAR_SO_RCVBUF VAR_EDNS_BUFFER_SIZE VAR_PREFETCH
|
%token VAR_DEL_HOLDDOWN VAR_SO_RCVBUF VAR_EDNS_BUFFER_SIZE VAR_PREFETCH
|
||||||
%token VAR_PREFETCH_KEY VAR_SO_SNDBUF VAR_HARDEN_BELOW_NXDOMAIN
|
%token VAR_PREFETCH_KEY VAR_SO_SNDBUF VAR_HARDEN_BELOW_NXDOMAIN
|
||||||
%token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_TCP_UPSTREAM
|
%token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_TCP_UPSTREAM VAR_SSL_UPSTREAM
|
||||||
|
%token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM
|
||||||
|
|
||||||
%%
|
%%
|
||||||
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
|
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
|
||||||
|
|
@ -157,7 +158,8 @@ content_server: server_num_threads | server_verbosity | server_port |
|
||||||
server_del_holddown | server_keep_missing | server_so_rcvbuf |
|
server_del_holddown | server_keep_missing | server_so_rcvbuf |
|
||||||
server_edns_buffer_size | server_prefetch | server_prefetch_key |
|
server_edns_buffer_size | server_prefetch | server_prefetch_key |
|
||||||
server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag |
|
server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag |
|
||||||
server_log_queries | server_tcp_upstream
|
server_log_queries | server_tcp_upstream | server_ssl_upstream |
|
||||||
|
server_ssl_service_key | server_ssl_service_pem
|
||||||
;
|
;
|
||||||
stubstart: VAR_STUB_ZONE
|
stubstart: VAR_STUB_ZONE
|
||||||
{
|
{
|
||||||
|
|
@ -374,6 +376,29 @@ server_tcp_upstream: VAR_TCP_UPSTREAM STRING_ARG
|
||||||
free($2);
|
free($2);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
server_ssl_upstream: VAR_SSL_UPSTREAM STRING_ARG
|
||||||
|
{
|
||||||
|
OUTYY(("P(server_ssl_upstream:%s)\n", $2));
|
||||||
|
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
|
||||||
|
yyerror("expected yes or no.");
|
||||||
|
else cfg_parser->cfg->ssl_upstream = (strcmp($2, "yes")==0);
|
||||||
|
free($2);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
server_ssl_service_key: VAR_SSL_SERVICE_KEY STRING_ARG
|
||||||
|
{
|
||||||
|
OUTYY(("P(server_ssl_service_key:%s)\n", $2));
|
||||||
|
free(cfg_parser->cfg->ssl_service_key);
|
||||||
|
cfg_parser->cfg->ssl_service_key = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
server_ssl_service_pem: VAR_SSL_SERVICE_PEM STRING_ARG
|
||||||
|
{
|
||||||
|
OUTYY(("P(server_ssl_service_pem:%s)\n", $2));
|
||||||
|
free(cfg_parser->cfg->ssl_service_pem);
|
||||||
|
cfg_parser->cfg->ssl_service_pem = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
server_do_daemonize: VAR_DO_DAEMONIZE STRING_ARG
|
server_do_daemonize: VAR_DO_DAEMONIZE STRING_ARG
|
||||||
{
|
{
|
||||||
OUTYY(("P(server_do_daemonize:%s)\n", $2));
|
OUTYY(("P(server_do_daemonize:%s)\n", $2));
|
||||||
|
|
|
||||||
138
util/net_help.c
138
util/net_help.c
|
|
@ -45,6 +45,8 @@
|
||||||
#include "util/module.h"
|
#include "util/module.h"
|
||||||
#include "util/regional.h"
|
#include "util/regional.h"
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
|
||||||
/** max length of an IP address (the address portion) that we allow */
|
/** max length of an IP address (the address portion) that we allow */
|
||||||
#define MAX_ADDR_STRLEN 128 /* characters */
|
#define MAX_ADDR_STRLEN 128 /* characters */
|
||||||
|
|
@ -553,3 +555,139 @@ void sock_list_merge(struct sock_list** list, struct regional* region,
|
||||||
sock_list_insert(list, &p->addr, p->len, region);
|
sock_list_insert(list, &p->addr, p->len, region);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
log_crypto_err(const char* str)
|
||||||
|
{
|
||||||
|
/* error:[error code]:[library name]:[function name]:[reason string] */
|
||||||
|
char buf[128];
|
||||||
|
unsigned long e;
|
||||||
|
ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
|
||||||
|
log_err("%s crypto %s", str, buf);
|
||||||
|
while( (e=ERR_get_error()) ) {
|
||||||
|
ERR_error_string_n(e, buf, sizeof(buf));
|
||||||
|
log_err("and additionally crypto %s", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* listen_sslctx_create(char* key, char* pem, char* verifypem)
|
||||||
|
{
|
||||||
|
SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
|
||||||
|
if(!ctx) {
|
||||||
|
log_crypto_err("could not SSL_CTX_new");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* no SSLv2 because has defects */
|
||||||
|
if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)){
|
||||||
|
log_crypto_err("could not set SSL_OP_NO_SSLv2");
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) {
|
||||||
|
log_err("error for cert file: %s", pem);
|
||||||
|
log_crypto_err("error in SSL_CTX use_certificate_file");
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
|
||||||
|
log_err("error for private key file: %s", key);
|
||||||
|
log_crypto_err("Error in SSL_CTX use_PrivateKey_file");
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(!SSL_CTX_check_private_key(ctx)) {
|
||||||
|
log_err("error for key file: %s", key);
|
||||||
|
log_crypto_err("Error in SSL_CTX check_private_key");
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(verifypem && verifypem[0]) {
|
||||||
|
if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) {
|
||||||
|
log_crypto_err("Error in SSL_CTX verify locations");
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(
|
||||||
|
verifypem));
|
||||||
|
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* connect_sslctx_create(char* key, char* pem, char* verifypem)
|
||||||
|
{
|
||||||
|
SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
|
||||||
|
if(!ctx) {
|
||||||
|
log_crypto_err("could not allocate SSL_CTX pointer");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)) {
|
||||||
|
log_crypto_err("could not set SSL_OP_NO_SSLv2");
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(key && key[0]) {
|
||||||
|
if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) {
|
||||||
|
log_err("error in client certificate %s", pem);
|
||||||
|
log_crypto_err("error in certificate file");
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
|
||||||
|
log_err("error in client private key %s", key);
|
||||||
|
log_crypto_err("error in key file");
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(!SSL_CTX_check_private_key(ctx)) {
|
||||||
|
log_err("error in client key %s", key);
|
||||||
|
log_crypto_err("error in SSL_CTX_check_private_key");
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(verifypem && verifypem[0]) {
|
||||||
|
if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL) != 1) {
|
||||||
|
log_crypto_err("error in SSL_CTX verify");
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* incoming_ssl_fd(void* sslctx, int fd)
|
||||||
|
{
|
||||||
|
SSL* ssl = SSL_new((SSL_CTX*)sslctx);
|
||||||
|
if(!ssl) {
|
||||||
|
log_crypto_err("could not SSL_new");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
SSL_set_accept_state(ssl);
|
||||||
|
(void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
|
||||||
|
if(!SSL_set_fd(ssl, fd)) {
|
||||||
|
log_crypto_err("could not SSL_set_fd");
|
||||||
|
SSL_free(ssl);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return ssl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* outgoing_ssl_fd(void* sslctx, int fd)
|
||||||
|
{
|
||||||
|
SSL* ssl = SSL_new((SSL_CTX*)sslctx);
|
||||||
|
if(!ssl) {
|
||||||
|
log_crypto_err("could not SSL_new");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
SSL_set_connect_state(ssl);
|
||||||
|
(void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
|
||||||
|
if(!SSL_set_fd(ssl, fd)) {
|
||||||
|
log_crypto_err("could not SSL_set_fd");
|
||||||
|
SSL_free(ssl);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return ssl;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -323,4 +323,44 @@ int sock_list_find(struct sock_list* list, struct sockaddr_storage* addr,
|
||||||
void sock_list_merge(struct sock_list** list, struct regional* region,
|
void sock_list_merge(struct sock_list** list, struct regional* region,
|
||||||
struct sock_list* add);
|
struct sock_list* add);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log libcrypto error with descriptive string. Calls log_err().
|
||||||
|
* @param str: what failed.
|
||||||
|
*/
|
||||||
|
void log_crypto_err(const char* str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create SSL listen context
|
||||||
|
* @param key: private key file.
|
||||||
|
* @param pem: public key cert.
|
||||||
|
* @param verifypem: if nonNULL, verifylocation file.
|
||||||
|
* return SSL_CTX* or NULL on failure (logged).
|
||||||
|
*/
|
||||||
|
void* listen_sslctx_create(char* key, char* pem, char* verifypem);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create SSL connect context
|
||||||
|
* @param key: if nonNULL (also pem nonNULL), the client private key.
|
||||||
|
* @param pem: client public key (or NULL if key is NULL).
|
||||||
|
* @param verifypem: if nonNULL used for verifylocation file.
|
||||||
|
* @return SSL_CTX* or NULL on failure (logged).
|
||||||
|
*/
|
||||||
|
void* connect_sslctx_create(char* key, char* pem, char* verifypem);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* accept a new fd and wrap it in a BIO in SSL
|
||||||
|
* @param sslctx: the SSL_CTX to use (from listen_sslctx_create()).
|
||||||
|
* @param fd: from accept, nonblocking.
|
||||||
|
* @return SSL or NULL on alloc failure.
|
||||||
|
*/
|
||||||
|
void* incoming_ssl_fd(void* sslctx, int fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* connect a new fd and wrap it in a BIO in SSL
|
||||||
|
* @param sslctx: the SSL_CTX to use (from connect_sslctx_create())
|
||||||
|
* @param fd: from connect.
|
||||||
|
* @return SSL or NULL on alloc failure
|
||||||
|
*/
|
||||||
|
void* outgoing_ssl_fd(void* sslctx, int fd);
|
||||||
|
|
||||||
#endif /* NET_HELP_H */
|
#endif /* NET_HELP_H */
|
||||||
|
|
|
||||||
281
util/netevent.c
281
util/netevent.c
|
|
@ -44,6 +44,8 @@
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "util/net_help.h"
|
#include "util/net_help.h"
|
||||||
#include "util/fptr_wlist.h"
|
#include "util/fptr_wlist.h"
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
|
||||||
/* -------- Start of local definitions -------- */
|
/* -------- Start of local definitions -------- */
|
||||||
/** if CMSG_ALIGN is not defined on this platform, a workaround */
|
/** if CMSG_ALIGN is not defined on this platform, a workaround */
|
||||||
|
|
@ -683,6 +685,32 @@ int comm_point_perform_accept(struct comm_point* c,
|
||||||
return new_fd;
|
return new_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_WINSOCK
|
||||||
|
static long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp),
|
||||||
|
int ATTR_UNUSED(argi), long argl, long retvalue)
|
||||||
|
{
|
||||||
|
verbose(VERB_ALGO, "bio_cb %d, %s %s %s", oper,
|
||||||
|
(oper&BIO_CB_RETURN)?"return":"before",
|
||||||
|
(oper&BIO_CB_READ)?"read":((oper&BIO_CB_WRITE)?"write":"other"),
|
||||||
|
WSAGetLastError()==WSAEWOULDBLOCK?"wsawb":"");
|
||||||
|
/* on windows, check if previous operation caused EWOULDBLOCK */
|
||||||
|
if( (oper == (BIO_CB_READ|BIO_CB_RETURN) && argl == 0) ||
|
||||||
|
(oper == (BIO_CB_GETS|BIO_CB_RETURN) && argl == 0)) {
|
||||||
|
if(WSAGetLastError() == WSAEWOULDBLOCK)
|
||||||
|
winsock_tcp_wouldblock((struct event*)
|
||||||
|
BIO_get_callback_arg(b), EV_READ);
|
||||||
|
}
|
||||||
|
if( (oper == (BIO_CB_WRITE|BIO_CB_RETURN) && argl == 0) ||
|
||||||
|
(oper == (BIO_CB_PUTS|BIO_CB_RETURN) && argl == 0)) {
|
||||||
|
if(WSAGetLastError() == WSAEWOULDBLOCK)
|
||||||
|
winsock_tcp_wouldblock((struct event*)
|
||||||
|
BIO_get_callback_arg(b), EV_WRITE);
|
||||||
|
}
|
||||||
|
/* return original return value */
|
||||||
|
return retvalue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
comm_point_tcp_accept_callback(int fd, short event, void* arg)
|
comm_point_tcp_accept_callback(int fd, short event, void* arg)
|
||||||
{
|
{
|
||||||
|
|
@ -706,6 +734,21 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
|
||||||
&c_hdl->repinfo.addrlen);
|
&c_hdl->repinfo.addrlen);
|
||||||
if(new_fd == -1)
|
if(new_fd == -1)
|
||||||
return;
|
return;
|
||||||
|
if(c->ssl) {
|
||||||
|
c_hdl->ssl = incoming_ssl_fd(c->ssl, new_fd);
|
||||||
|
if(!c_hdl->ssl)
|
||||||
|
return;
|
||||||
|
c_hdl->ssl_shake_state = comm_ssl_shake_read;
|
||||||
|
#ifdef USE_WINSOCK
|
||||||
|
/* set them both just in case, but usually they are the same BIO */
|
||||||
|
BIO_set_callback(SSL_get_rbio(c_hdl->ssl), &win_bio_cb);
|
||||||
|
BIO_set_callback_arg(SSL_get_rbio(c_hdl->ssl),
|
||||||
|
(char*)comm_point_internal(c_hdl));
|
||||||
|
BIO_set_callback(SSL_get_wbio(c_hdl->ssl), &win_bio_cb);
|
||||||
|
BIO_set_callback_arg(SSL_get_wbio(c_hdl->ssl),
|
||||||
|
(char*)comm_point_internal(c_hdl));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* grab the tcp handler buffers */
|
/* grab the tcp handler buffers */
|
||||||
c->tcp_free = c_hdl->tcp_free;
|
c->tcp_free = c_hdl->tcp_free;
|
||||||
|
|
@ -722,6 +765,11 @@ static void
|
||||||
reclaim_tcp_handler(struct comm_point* c)
|
reclaim_tcp_handler(struct comm_point* c)
|
||||||
{
|
{
|
||||||
log_assert(c->type == comm_tcp);
|
log_assert(c->type == comm_tcp);
|
||||||
|
if(c->ssl) {
|
||||||
|
SSL_shutdown(c->ssl);
|
||||||
|
SSL_free(c->ssl);
|
||||||
|
c->ssl = NULL;
|
||||||
|
}
|
||||||
comm_point_close(c);
|
comm_point_close(c);
|
||||||
if(c->tcp_parent) {
|
if(c->tcp_parent) {
|
||||||
c->tcp_free = c->tcp_parent->tcp_free;
|
c->tcp_free = c->tcp_parent->tcp_free;
|
||||||
|
|
@ -764,6 +812,231 @@ tcp_callback_reader(struct comm_point* c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** continue ssl handshake */
|
||||||
|
static int
|
||||||
|
ssl_handshake(struct comm_point* c)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
if(c->ssl_shake_state == comm_ssl_shake_hs_read) {
|
||||||
|
/* read condition satisfied back to writing */
|
||||||
|
comm_point_listen_for_rw(c, 1, 1);
|
||||||
|
c->ssl_shake_state = comm_ssl_shake_none;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(c->ssl_shake_state == comm_ssl_shake_hs_write) {
|
||||||
|
/* write condition satisfied, back to reading */
|
||||||
|
comm_point_listen_for_rw(c, 1, 0);
|
||||||
|
c->ssl_shake_state = comm_ssl_shake_none;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_clear_error();
|
||||||
|
r = SSL_do_handshake(c->ssl);
|
||||||
|
if(r != 1) {
|
||||||
|
int want = SSL_get_error(c->ssl, r);
|
||||||
|
if(want == SSL_ERROR_WANT_READ) {
|
||||||
|
if(c->ssl_shake_state == comm_ssl_shake_read)
|
||||||
|
return 1;
|
||||||
|
c->ssl_shake_state = comm_ssl_shake_read;
|
||||||
|
comm_point_listen_for_rw(c, 1, 0);
|
||||||
|
return 1;
|
||||||
|
} else if(want == SSL_ERROR_WANT_WRITE) {
|
||||||
|
if(c->ssl_shake_state == comm_ssl_shake_write)
|
||||||
|
return 1;
|
||||||
|
c->ssl_shake_state = comm_ssl_shake_write;
|
||||||
|
comm_point_listen_for_rw(c, 0, 1);
|
||||||
|
return 1;
|
||||||
|
} else if(r == 0) {
|
||||||
|
return 0; /* closed */
|
||||||
|
} else if(want == SSL_ERROR_SYSCALL) {
|
||||||
|
/* SYSCALL and errno==0 means closed uncleanly */
|
||||||
|
if(errno != 0)
|
||||||
|
log_err("SSL_handshake syscall: %s",
|
||||||
|
strerror(errno));
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
log_crypto_err("ssl handshake failed");
|
||||||
|
log_addr(1, "ssl handshake failed", &c->repinfo.addr,
|
||||||
|
c->repinfo.addrlen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* this is where peer verification could take place */
|
||||||
|
log_addr(VERB_ALGO, "SSL connection from", &c->repinfo.addr,
|
||||||
|
c->repinfo.addrlen);
|
||||||
|
|
||||||
|
/* setup listen rw correctly */
|
||||||
|
if(c->tcp_is_reading) {
|
||||||
|
if(c->ssl_shake_state != comm_ssl_shake_read)
|
||||||
|
comm_point_listen_for_rw(c, 1, 0);
|
||||||
|
} else {
|
||||||
|
comm_point_listen_for_rw(c, 1, 1);
|
||||||
|
}
|
||||||
|
c->ssl_shake_state = comm_ssl_shake_none;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ssl read callback on TCP */
|
||||||
|
static int
|
||||||
|
ssl_handle_read(struct comm_point* c)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
if(c->ssl_shake_state != comm_ssl_shake_none) {
|
||||||
|
if(!ssl_handshake(c))
|
||||||
|
return 0;
|
||||||
|
if(c->ssl_shake_state != comm_ssl_shake_none)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(c->tcp_byte_count < sizeof(uint16_t)) {
|
||||||
|
/* read length bytes */
|
||||||
|
ERR_clear_error();
|
||||||
|
if((r=SSL_read(c->ssl, (void*)ldns_buffer_at(c->buffer,
|
||||||
|
c->tcp_byte_count), (int)(sizeof(uint16_t) -
|
||||||
|
c->tcp_byte_count))) <= 0) {
|
||||||
|
int want = SSL_get_error(c->ssl, r);
|
||||||
|
if(want == SSL_ERROR_ZERO_RETURN) {
|
||||||
|
return 0; /* shutdown, closed */
|
||||||
|
} else if(want == SSL_ERROR_WANT_READ) {
|
||||||
|
return 1; /* read more later */
|
||||||
|
} else if(want == SSL_ERROR_WANT_WRITE) {
|
||||||
|
c->ssl_shake_state = comm_ssl_shake_hs_write;
|
||||||
|
comm_point_listen_for_rw(c, 0, 1);
|
||||||
|
return 1;
|
||||||
|
} else if(want == SSL_ERROR_SYSCALL) {
|
||||||
|
if(errno != 0)
|
||||||
|
log_err("SSL_read syscall: %s",
|
||||||
|
strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
log_crypto_err("could not SSL_read");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
c->tcp_byte_count += r;
|
||||||
|
if(c->tcp_byte_count != sizeof(uint16_t))
|
||||||
|
return 1;
|
||||||
|
if(ldns_buffer_read_u16_at(c->buffer, 0) >
|
||||||
|
ldns_buffer_capacity(c->buffer)) {
|
||||||
|
verbose(VERB_QUERY, "ssl: dropped larger than buffer");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ldns_buffer_set_limit(c->buffer,
|
||||||
|
ldns_buffer_read_u16_at(c->buffer, 0));
|
||||||
|
if(ldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
|
||||||
|
verbose(VERB_QUERY, "ssl: dropped bogus too short.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
verbose(VERB_ALGO, "Reading ssl tcp query of length %d",
|
||||||
|
(int)ldns_buffer_limit(c->buffer));
|
||||||
|
}
|
||||||
|
log_assert(ldns_buffer_remaining(c->buffer) > 0);
|
||||||
|
ERR_clear_error();
|
||||||
|
r = SSL_read(c->ssl, (void*)ldns_buffer_current(c->buffer),
|
||||||
|
(int)ldns_buffer_remaining(c->buffer));
|
||||||
|
if(r <= 0) {
|
||||||
|
int want = SSL_get_error(c->ssl, r);
|
||||||
|
if(want == SSL_ERROR_ZERO_RETURN) {
|
||||||
|
return 0; /* shutdown, closed */
|
||||||
|
} else if(want == SSL_ERROR_WANT_READ) {
|
||||||
|
return 1; /* read more later */
|
||||||
|
} else if(want == SSL_ERROR_WANT_WRITE) {
|
||||||
|
c->ssl_shake_state = comm_ssl_shake_hs_write;
|
||||||
|
comm_point_listen_for_rw(c, 0, 1);
|
||||||
|
return 1;
|
||||||
|
} else if(want == SSL_ERROR_SYSCALL) {
|
||||||
|
if(errno != 0)
|
||||||
|
log_err("SSL_read syscall: %s",
|
||||||
|
strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
log_crypto_err("could not SSL_read");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ldns_buffer_skip(c->buffer, (ssize_t)r);
|
||||||
|
if(ldns_buffer_remaining(c->buffer) <= 0) {
|
||||||
|
tcp_callback_reader(c);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ssl write callback on TCP */
|
||||||
|
static int
|
||||||
|
ssl_handle_write(struct comm_point* c)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
if(c->ssl_shake_state != comm_ssl_shake_none) {
|
||||||
|
if(!ssl_handshake(c))
|
||||||
|
return 0;
|
||||||
|
if(c->ssl_shake_state != comm_ssl_shake_none)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* ignore return, if fails we may simply block */
|
||||||
|
(void)SSL_set_mode(c->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||||
|
if(c->tcp_byte_count < sizeof(uint16_t)) {
|
||||||
|
uint16_t len = htons(ldns_buffer_limit(c->buffer));
|
||||||
|
ERR_clear_error();
|
||||||
|
r = SSL_write(c->ssl,
|
||||||
|
(void*)(((uint8_t*)&len)+c->tcp_byte_count),
|
||||||
|
(int)(sizeof(uint16_t)-c->tcp_byte_count));
|
||||||
|
if(r <= 0) {
|
||||||
|
int want = SSL_get_error(c->ssl, r);
|
||||||
|
if(want == SSL_ERROR_ZERO_RETURN) {
|
||||||
|
return 0; /* closed */
|
||||||
|
} else if(want == SSL_ERROR_WANT_READ) {
|
||||||
|
c->ssl_shake_state = comm_ssl_shake_read;
|
||||||
|
comm_point_listen_for_rw(c, 1, 0);
|
||||||
|
return 1; /* wait for read condition */
|
||||||
|
} else if(want == SSL_ERROR_WANT_WRITE) {
|
||||||
|
return 1; /* write more later */
|
||||||
|
} else if(want == SSL_ERROR_SYSCALL) {
|
||||||
|
if(errno != 0)
|
||||||
|
log_err("SSL_write syscall: %s",
|
||||||
|
strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
log_crypto_err("could not SSL_write");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
c->tcp_byte_count += r;
|
||||||
|
if(c->tcp_byte_count < sizeof(uint16_t))
|
||||||
|
return 1;
|
||||||
|
ldns_buffer_set_position(c->buffer, c->tcp_byte_count -
|
||||||
|
sizeof(uint16_t));
|
||||||
|
if(ldns_buffer_remaining(c->buffer) == 0) {
|
||||||
|
tcp_callback_writer(c);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_assert(ldns_buffer_remaining(c->buffer) > 0);
|
||||||
|
ERR_clear_error();
|
||||||
|
r = SSL_write(c->ssl, (void*)ldns_buffer_current(c->buffer),
|
||||||
|
(int)ldns_buffer_remaining(c->buffer));
|
||||||
|
if(r <= 0) {
|
||||||
|
int want = SSL_get_error(c->ssl, r);
|
||||||
|
if(want == SSL_ERROR_ZERO_RETURN) {
|
||||||
|
return 0; /* closed */
|
||||||
|
} else if(want == SSL_ERROR_WANT_READ) {
|
||||||
|
c->ssl_shake_state = comm_ssl_shake_read;
|
||||||
|
comm_point_listen_for_rw(c, 1, 0);
|
||||||
|
return 1; /* wait for read condition */
|
||||||
|
} else if(want == SSL_ERROR_WANT_WRITE) {
|
||||||
|
return 1; /* write more later */
|
||||||
|
} else if(want == SSL_ERROR_SYSCALL) {
|
||||||
|
if(errno != 0)
|
||||||
|
log_err("SSL_write syscall: %s",
|
||||||
|
strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
log_crypto_err("could not SSL_write");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ldns_buffer_skip(c->buffer, (ssize_t)r);
|
||||||
|
|
||||||
|
if(ldns_buffer_remaining(c->buffer) == 0) {
|
||||||
|
tcp_callback_writer(c);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/** Handle tcp reading callback.
|
/** Handle tcp reading callback.
|
||||||
* @param fd: file descriptor of socket.
|
* @param fd: file descriptor of socket.
|
||||||
* @param c: comm point to read from into buffer.
|
* @param c: comm point to read from into buffer.
|
||||||
|
|
@ -777,6 +1050,8 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
|
||||||
log_assert(c->type == comm_tcp || c->type == comm_local);
|
log_assert(c->type == comm_tcp || c->type == comm_local);
|
||||||
if(!c->tcp_is_reading)
|
if(!c->tcp_is_reading)
|
||||||
return 0;
|
return 0;
|
||||||
|
if(c->ssl)
|
||||||
|
return ssl_handle_read(c);
|
||||||
|
|
||||||
log_assert(fd != -1);
|
log_assert(fd != -1);
|
||||||
if(c->tcp_byte_count < sizeof(uint16_t)) {
|
if(c->tcp_byte_count < sizeof(uint16_t)) {
|
||||||
|
|
@ -915,6 +1190,8 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(c->ssl)
|
||||||
|
return ssl_handle_write(c);
|
||||||
|
|
||||||
if(c->tcp_byte_count < sizeof(uint16_t)) {
|
if(c->tcp_byte_count < sizeof(uint16_t)) {
|
||||||
uint16_t len = htons(ldns_buffer_limit(c->buffer));
|
uint16_t len = htons(ldns_buffer_limit(c->buffer));
|
||||||
|
|
@ -1476,6 +1753,10 @@ comm_point_delete(struct comm_point* c)
|
||||||
{
|
{
|
||||||
if(!c)
|
if(!c)
|
||||||
return;
|
return;
|
||||||
|
if(c->type == comm_tcp && c->ssl) {
|
||||||
|
SSL_shutdown(c->ssl);
|
||||||
|
SSL_free(c->ssl);
|
||||||
|
}
|
||||||
comm_point_close(c);
|
comm_point_close(c);
|
||||||
if(c->tcp_handlers) {
|
if(c->tcp_handlers) {
|
||||||
int i;
|
int i;
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,23 @@ struct comm_point {
|
||||||
For tcp_accept the first entry, for tcp_handlers the next one. */
|
For tcp_accept the first entry, for tcp_handlers the next one. */
|
||||||
struct comm_point* tcp_free;
|
struct comm_point* tcp_free;
|
||||||
|
|
||||||
|
/* -------- SSL TCP DNS ------- */
|
||||||
|
/** the SSL object with rw bio (owned) or for commaccept ctx ref */
|
||||||
|
void* ssl;
|
||||||
|
/** handshake state for init and renegotiate */
|
||||||
|
enum {
|
||||||
|
/** no handshake, it has been done */
|
||||||
|
comm_ssl_shake_none = 0,
|
||||||
|
/** ssl initial handshake wants to read */
|
||||||
|
comm_ssl_shake_read,
|
||||||
|
/** ssl initial handshake wants to write */
|
||||||
|
comm_ssl_shake_write,
|
||||||
|
/** ssl_write wants to read */
|
||||||
|
comm_ssl_shake_hs_read,
|
||||||
|
/** ssl_read wants to write */
|
||||||
|
comm_ssl_shake_hs_write
|
||||||
|
} ssl_shake_state;
|
||||||
|
|
||||||
/** is this a UDP, TCP-accept or TCP socket. */
|
/** is this a UDP, TCP-accept or TCP socket. */
|
||||||
enum comm_point_type {
|
enum comm_point_type {
|
||||||
/** UDP socket - handle datagrams. */
|
/** UDP socket - handle datagrams. */
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue