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)
|
||||
$(INFO) Link $@
|
||||
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
|
||||
cp $(srcdir)/libunbound/ubsyms.def $(BUILD)clubsyms.def
|
||||
echo lock_protect >> $(BUILD)clubsyms.def
|
||||
|
|
@ -252,7 +252,7 @@ else
|
|||
echo checklock_init >> $(BUILD)clubsyms.def
|
||||
echo checklock_thrcreate >> $(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
|
||||
|
||||
unbound$(EXEEXT): $(DAEMON_OBJ) libunbound.la
|
||||
|
|
@ -289,7 +289,7 @@ anchor-update$(EXEEXT): $(ANCHORUPD_OBJ) libunbound.la
|
|||
|
||||
unittest$(EXEEXT): $(UNITTEST_OBJ)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(UNITTEST_OBJ)) $(LIBS)
|
||||
$Q$(LINK) -o $@ $(sort $(UNITTEST_OBJ)) -lssl $(LIBS)
|
||||
|
||||
testbound$(EXEEXT): $(TESTBOUND_OBJ)
|
||||
$(INFO) Link $@
|
||||
|
|
@ -297,7 +297,7 @@ testbound$(EXEEXT): $(TESTBOUND_OBJ)
|
|||
|
||||
lock-verify$(EXEEXT): $(LOCKVERIFY_OBJ)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(LOCKVERIFY_OBJ)) $(LIBS)
|
||||
$Q$(LINK) -o $@ $(sort $(LOCKVERIFY_OBJ)) -lssl $(LIBS)
|
||||
|
||||
petal$(EXEEXT): $(PETAL_OBJ)
|
||||
$(INFO) Link $@
|
||||
|
|
@ -305,15 +305,15 @@ petal$(EXEEXT): $(PETAL_OBJ)
|
|||
|
||||
pktview$(EXEEXT): $(PKTVIEW_OBJ)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(PKTVIEW_OBJ)) $(LIBS)
|
||||
$Q$(LINK) -o $@ $(sort $(PKTVIEW_OBJ)) -lssl $(LIBS)
|
||||
|
||||
signit$(EXEEXT): $(SIGNIT_OBJ)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(SIGNIT_OBJ)) $(LIBS)
|
||||
$Q$(LINK) -o $@ $(sort $(SIGNIT_OBJ)) -lssl $(LIBS)
|
||||
|
||||
memstats$(EXEEXT): $(MEMSTATS_OBJ)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(MEMSTATS_OBJ)) $(LIBS)
|
||||
$Q$(LINK) -o $@ $(sort $(MEMSTATS_OBJ)) -lssl $(LIBS)
|
||||
|
||||
asynclook$(EXEEXT): $(ASYNCLOOK_OBJ) libunbound.la
|
||||
$(INFO) Link $@
|
||||
|
|
@ -321,15 +321,15 @@ asynclook$(EXEEXT): $(ASYNCLOOK_OBJ) libunbound.la
|
|||
|
||||
streamtcp$(EXEEXT): $(STREAMTCP_OBJ)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(STREAMTCP_OBJ)) $(LIBS)
|
||||
$Q$(LINK) -o $@ $(sort $(STREAMTCP_OBJ)) -lssl $(LIBS)
|
||||
|
||||
perf$(EXEEXT): $(PERF_OBJ)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(PERF_OBJ)) $(LIBS)
|
||||
$Q$(LINK) -o $@ $(sort $(PERF_OBJ)) -lssl $(LIBS)
|
||||
|
||||
delayer$(EXEEXT): $(DELAYER_OBJ)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(DELAYER_OBJ)) $(LIBS)
|
||||
$Q$(LINK) -o $@ $(sort $(DELAYER_OBJ)) -lssl $(LIBS)
|
||||
|
||||
harvest$(EXEEXT): $(HARVEST_OBJ) libunbound.la
|
||||
$(INFO) Link $@
|
||||
|
|
|
|||
|
|
@ -528,6 +528,8 @@ daemon_delete(struct daemon* daemon)
|
|||
free(daemon->chroot);
|
||||
free(daemon->pidfile);
|
||||
free(daemon->env);
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_sslctx);
|
||||
SSL_CTX_free((SSL_CTX*)daemon->connect_sslctx);
|
||||
free(daemon);
|
||||
#ifdef LEX_HAS_YYLEX_DESTROY
|
||||
/* lex cleanup */
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ struct daemon {
|
|||
struct listen_port* rc_ports;
|
||||
/** remote control connections management (for first worker) */
|
||||
struct daemon_remote* rc;
|
||||
/** ssl context for listening to dnstcp over ssl, and connecting ssl */
|
||||
void* listen_sslctx, *connect_sslctx;
|
||||
/** num threads allocated */
|
||||
int num;
|
||||
/** the worker entries */
|
||||
|
|
|
|||
|
|
@ -92,21 +92,6 @@
|
|||
/** if true, inhibits a lot of =0 lines from the stats output */
|
||||
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 */
|
||||
static void
|
||||
timeval_subtract(struct timeval* d, const struct timeval* end,
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
#include "services/cache/infra.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/module.h"
|
||||
#include "util/net_help.h"
|
||||
#include <signal.h>
|
||||
#include <fcntl.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 */
|
||||
if(!(daemon->rc = daemon_remote_create(cfg)))
|
||||
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
|
||||
/* 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,
|
||||
cfg->msg_buffer_size, (int)cfg->incoming_num_tcp,
|
||||
worker_handle_request, worker);
|
||||
worker->daemon->listen_sslctx, worker_handle_request, worker);
|
||||
if(!worker->front) {
|
||||
log_err("could not create listening sockets");
|
||||
worker_delete(worker);
|
||||
|
|
@ -1105,7 +1105,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
|||
worker->daemon->env->infra_cache, worker->rndstate,
|
||||
cfg->use_caps_bits_for_id, worker->ports, worker->numports,
|
||||
cfg->unwanted_threshold, &worker_alloc_cleanup, worker,
|
||||
cfg->do_udp);
|
||||
cfg->do_udp, worker->daemon->connect_sslctx);
|
||||
if(!worker->back) {
|
||||
log_err("could not create outgoing sockets");
|
||||
worker_delete(worker);
|
||||
|
|
@ -1255,9 +1255,9 @@ worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
|||
e->qstate = q;
|
||||
e->qsent = outnet_serviced_query(worker->back, qname,
|
||||
qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
|
||||
q->env->cfg->tcp_upstream, addr, addrlen, zone, zonelen,
|
||||
worker_handle_service_reply, e, worker->back->udp_buff,
|
||||
&outbound_entry_compare);
|
||||
q->env->cfg->tcp_upstream || q->env->cfg->ssl_upstream, addr,
|
||||
addrlen, zone, zonelen, worker_handle_service_reply, e,
|
||||
worker->back->udp_buff, &outbound_entry_compare);
|
||||
if(!e->qsent) {
|
||||
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
|
||||
- lame-ttl and lame-size options no longer exist, it is integrated
|
||||
with the host info. They are ignored (with verbose warning) if
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include "config.h"
|
||||
#include <ldns/dname.h>
|
||||
#include <ldns/wire2host.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include "libunbound/libworker.h"
|
||||
#include "libunbound/context.h"
|
||||
#include "libunbound/unbound.h"
|
||||
|
|
@ -84,6 +85,7 @@ libworker_delete(struct libworker* w)
|
|||
ub_randfree(w->env->rnd);
|
||||
free(w->env);
|
||||
}
|
||||
SSL_CTX_free(w->sslctx);
|
||||
outside_network_delete(w->back);
|
||||
comm_base_delete(w->base);
|
||||
free(w);
|
||||
|
|
@ -124,6 +126,13 @@ libworker_setup(struct ub_ctx* ctx, int is_bg)
|
|||
forwards_delete(w->env->fwds);
|
||||
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) {
|
||||
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,
|
||||
w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
|
||||
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) {
|
||||
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->qsent = outnet_serviced_query(w->back, qname,
|
||||
qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
|
||||
q->env->cfg->tcp_upstream, addr, addrlen, zone, zonelen,
|
||||
libworker_handle_service_reply, e, w->back->udp_buff,
|
||||
&outbound_entry_compare);
|
||||
q->env->cfg->tcp_upstream || q->env->cfg->ssl_upstream, addr,
|
||||
addrlen, zone, zonelen, libworker_handle_service_reply, e,
|
||||
w->back->udp_buff, &outbound_entry_compare);
|
||||
if(!e->qsent) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ struct libworker {
|
|||
struct outside_network* back;
|
||||
/** random() table for this worker. */
|
||||
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*
|
||||
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)
|
||||
{
|
||||
struct listen_dnsport* front = (struct listen_dnsport*)
|
||||
|
|
@ -736,6 +736,9 @@ listen_create(struct comm_base* base, struct listen_port* ports,
|
|||
free(front);
|
||||
return NULL;
|
||||
}
|
||||
if(sslctx) {
|
||||
verbose(VERB_ALGO, "setup for SSL-wrapped TCP service");
|
||||
}
|
||||
|
||||
/* create comm points as needed */
|
||||
while(ports) {
|
||||
|
|
@ -743,10 +746,11 @@ listen_create(struct comm_base* base, struct listen_port* ports,
|
|||
if(ports->ftype == listen_type_udp)
|
||||
cp = comm_point_create_udp(base, ports->fd,
|
||||
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,
|
||||
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,
|
||||
front->udp_buff, cb, cb_arg);
|
||||
if(!cp) {
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ void listening_ports_free(struct listen_port* list);
|
|||
* @param bufsize: size of datagram buffer.
|
||||
* @param tcp_accept_count: max number of simultaneous TCP connections
|
||||
* from clients.
|
||||
* @param sslctx: nonNULL if ssl context.
|
||||
* @param cb: callback function when a request arrives. It is passed
|
||||
* the packet and user argument. Return true to send a reply.
|
||||
* @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_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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
|
||||
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*)
|
||||
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->infra = infra;
|
||||
outnet->rnd = rnd;
|
||||
outnet->sslctx = sslctx;
|
||||
outnet->svcd_overhead = 0;
|
||||
outnet->want_to_quit = 0;
|
||||
outnet->unwanted_threshold = unwanted_threshold;
|
||||
|
|
|
|||
|
|
@ -118,6 +118,8 @@ struct outside_network {
|
|||
struct infra_cache* infra;
|
||||
/** where to get random numbers */
|
||||
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.
|
||||
|
|
@ -369,6 +371,7 @@ struct serviced_query {
|
|||
* @param unwanted_action: the action to take.
|
||||
* @param unwanted_param: user parameter to action.
|
||||
* @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.
|
||||
*/
|
||||
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,
|
||||
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -708,7 +708,7 @@ run_scenario(struct replay_runtime* runtime)
|
|||
struct listen_dnsport*
|
||||
listen_create(struct comm_base* base, struct listen_port* ATTR_UNUSED(ports),
|
||||
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 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(numavailports), size_t ATTR_UNUSED(unwanted_threshold),
|
||||
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 outside_network* outnet = calloc(1,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/msgreply.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("-u use UDP. No retries are attempted.\n");
|
||||
printf("-n do not wait for an answer.\n");
|
||||
printf("-s use ssl\n");
|
||||
printf("-h this help text\n");
|
||||
exit(1);
|
||||
}
|
||||
|
|
@ -105,7 +107,7 @@ open_svr(const char* svr, int udp)
|
|||
|
||||
/** write a query over the TCP fd */
|
||||
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)
|
||||
{
|
||||
struct query_info qinfo;
|
||||
|
|
@ -128,65 +130,111 @@ write_q(int fd, int udp, ldns_buffer* buf, int id,
|
|||
|
||||
/* make query */
|
||||
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);
|
||||
|
||||
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 */
|
||||
if(!udp) {
|
||||
len = (uint16_t)ldns_buffer_limit(buf);
|
||||
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
|
||||
perror("send() len failed");
|
||||
perror("send() len failed");
|
||||
#else
|
||||
printf("send len: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
printf("send len: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
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)) {
|
||||
#ifndef USE_WINSOCK
|
||||
perror("send() data failed");
|
||||
#else
|
||||
printf("send data: %s\n", wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if(send(fd, (void*)ldns_buffer_begin(buf), ldns_buffer_limit(buf), 0) <
|
||||
(ssize_t)ldns_buffer_limit(buf)) {
|
||||
#ifndef USE_WINSOCK
|
||||
perror("send() data failed");
|
||||
#else
|
||||
printf("send data: %s\n", wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
||||
free(qinfo.qname);
|
||||
}
|
||||
|
||||
/** receive DNS datagram over TCP and print it */
|
||||
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;
|
||||
ldns_pkt* pkt;
|
||||
ldns_status status;
|
||||
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
|
||||
perror("read() len failed");
|
||||
perror("read() len failed");
|
||||
#else
|
||||
printf("read len: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
printf("read len: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
len = ntohs(len);
|
||||
ldns_buffer_clear(buf);
|
||||
ldns_buffer_set_limit(buf, len);
|
||||
if(recv(fd, (void*)ldns_buffer_begin(buf), len, 0) <
|
||||
(ssize_t)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) <
|
||||
(ssize_t)len) {
|
||||
#ifndef USE_WINSOCK
|
||||
perror("read() data failed");
|
||||
perror("read() data failed");
|
||||
#else
|
||||
printf("read data: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
printf("read data: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ssize_t l;
|
||||
|
|
@ -220,20 +268,34 @@ recv_one(int fd, int udp, ldns_buffer* buf)
|
|||
|
||||
/** send the TCP queries and print answers */
|
||||
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);
|
||||
int fd = open_svr(svr, udp);
|
||||
int i;
|
||||
SSL_CTX* ctx;
|
||||
SSL* ssl;
|
||||
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) {
|
||||
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 */
|
||||
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
|
||||
close(fd);
|
||||
#else
|
||||
|
|
@ -268,6 +330,7 @@ int main(int argc, char** argv)
|
|||
const char* svr = "127.0.0.1";
|
||||
int udp = 0;
|
||||
int noanswer = 0;
|
||||
int usessl = 0;
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
WSADATA wsa_data;
|
||||
|
|
@ -292,7 +355,7 @@ int main(int argc, char** argv)
|
|||
if(argc == 1) {
|
||||
usage(argv);
|
||||
}
|
||||
while( (c=getopt(argc, argv, "f:hnu")) != -1) {
|
||||
while( (c=getopt(argc, argv, "f:hnsu")) != -1) {
|
||||
switch(c) {
|
||||
case 'f':
|
||||
svr = optarg;
|
||||
|
|
@ -303,6 +366,9 @@ int main(int argc, char** argv)
|
|||
case 'u':
|
||||
udp = 1;
|
||||
break;
|
||||
case 's':
|
||||
usessl = 1;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
|
|
@ -316,7 +382,12 @@ int main(int argc, char** argv)
|
|||
printf("queries must be multiples of name,type,class\n");
|
||||
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();
|
||||
#ifdef USE_WINSOCK
|
||||
WSACleanup();
|
||||
|
|
|
|||
|
|
@ -88,6 +88,9 @@ config_create(void)
|
|||
cfg->do_udp = 1;
|
||||
cfg->do_tcp = 1;
|
||||
cfg->tcp_upstream = 0;
|
||||
cfg->ssl_service_key = NULL;
|
||||
cfg->ssl_service_pem = NULL;
|
||||
cfg->ssl_upstream = 0;
|
||||
cfg->use_syslog = 1;
|
||||
cfg->log_time_ascii = 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-tcp:", do_tcp)
|
||||
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("do-daemonize:", do_daemonize)
|
||||
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-tcp", do_tcp)
|
||||
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_STR(opt, "chroot", chrootdir)
|
||||
else O_STR(opt, "username", username)
|
||||
|
|
@ -728,6 +737,8 @@ config_delete(struct config_file* cfg)
|
|||
free(cfg->logfile);
|
||||
free(cfg->pidfile);
|
||||
free(cfg->target_fetch_policy);
|
||||
free(cfg->ssl_service_key);
|
||||
free(cfg->ssl_service_pem);
|
||||
if(cfg->ifs) {
|
||||
int i;
|
||||
for(i=0; i<cfg->num_ifs; i++)
|
||||
|
|
|
|||
|
|
@ -79,6 +79,13 @@ struct config_file {
|
|||
/** tcp upstream queries (no UDP upstream queries) */
|
||||
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) */
|
||||
int outgoing_num_ports;
|
||||
/** 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-tcp{COLON} { YDVAR(1, VAR_DO_TCP) }
|
||||
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) }
|
||||
interface{COLON} { YDVAR(1, VAR_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_IGNORE_CD_FLAG = 374,
|
||||
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
|
||||
/* Tokens. */
|
||||
|
|
@ -279,6 +282,9 @@
|
|||
#define VAR_IGNORE_CD_FLAG 374
|
||||
#define VAR_LOG_QUERIES 375
|
||||
#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 299 "util/configparser.h"
|
||||
#line 305 "util/configparser.h"
|
||||
} YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# 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_DEL_HOLDDOWN VAR_SO_RCVBUF VAR_EDNS_BUFFER_SIZE VAR_PREFETCH
|
||||
%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 ;
|
||||
|
|
@ -157,7 +158,8 @@ content_server: server_num_threads | server_verbosity | server_port |
|
|||
server_del_holddown | server_keep_missing | server_so_rcvbuf |
|
||||
server_edns_buffer_size | server_prefetch | server_prefetch_key |
|
||||
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
|
||||
{
|
||||
|
|
@ -374,6 +376,29 @@ server_tcp_upstream: VAR_TCP_UPSTREAM STRING_ARG
|
|||
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
|
||||
{
|
||||
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/regional.h"
|
||||
#include <fcntl.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
/** max length of an IP address (the address portion) that we allow */
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
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 */
|
||||
|
|
|
|||
281
util/netevent.c
281
util/netevent.c
|
|
@ -44,6 +44,8 @@
|
|||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
/* -------- Start of local definitions -------- */
|
||||
/** 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;
|
||||
}
|
||||
|
||||
#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
|
||||
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);
|
||||
if(new_fd == -1)
|
||||
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 */
|
||||
c->tcp_free = c_hdl->tcp_free;
|
||||
|
|
@ -722,6 +765,11 @@ static void
|
|||
reclaim_tcp_handler(struct comm_point* c)
|
||||
{
|
||||
log_assert(c->type == comm_tcp);
|
||||
if(c->ssl) {
|
||||
SSL_shutdown(c->ssl);
|
||||
SSL_free(c->ssl);
|
||||
c->ssl = NULL;
|
||||
}
|
||||
comm_point_close(c);
|
||||
if(c->tcp_parent) {
|
||||
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.
|
||||
* @param fd: file descriptor of socket.
|
||||
* @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);
|
||||
if(!c->tcp_is_reading)
|
||||
return 0;
|
||||
if(c->ssl)
|
||||
return ssl_handle_read(c);
|
||||
|
||||
log_assert(fd != -1);
|
||||
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;
|
||||
}
|
||||
}
|
||||
if(c->ssl)
|
||||
return ssl_handle_write(c);
|
||||
|
||||
if(c->tcp_byte_count < sizeof(uint16_t)) {
|
||||
uint16_t len = htons(ldns_buffer_limit(c->buffer));
|
||||
|
|
@ -1476,6 +1753,10 @@ comm_point_delete(struct comm_point* c)
|
|||
{
|
||||
if(!c)
|
||||
return;
|
||||
if(c->type == comm_tcp && c->ssl) {
|
||||
SSL_shutdown(c->ssl);
|
||||
SSL_free(c->ssl);
|
||||
}
|
||||
comm_point_close(c);
|
||||
if(c->tcp_handlers) {
|
||||
int i;
|
||||
|
|
|
|||
|
|
@ -160,6 +160,23 @@ struct comm_point {
|
|||
For tcp_accept the first entry, for tcp_handlers the next one. */
|
||||
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. */
|
||||
enum comm_point_type {
|
||||
/** UDP socket - handle datagrams. */
|
||||
|
|
|
|||
Loading…
Reference in a new issue