free(daemon->env);
#ifdef HAVE_SSL
listen_sslctx_delete_ticket_keys();
- SSL_CTX_free((SSL_CTX*)daemon->listen_sslctx);
- SSL_CTX_free((SSL_CTX*)daemon->connect_sslctx);
+ SSL_CTX_free((SSL_CTX*)daemon->listen_dot_sslctx);
+ SSL_CTX_free((SSL_CTX*)daemon->listen_doh_sslctx);
+ SSL_CTX_free((SSL_CTX*)daemon->connect_dot_sslctx);
#endif
#ifdef HAVE_NGTCP2
- SSL_CTX_free((SSL_CTX*)daemon->quic_sslctx);
+ SSL_CTX_free((SSL_CTX*)daemon->listen_quic_sslctx);
#endif
free(daemon);
/* lex cleanup */
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;
+ /** ssl context for listening to dnstcp over ssl */
+ void* listen_dot_sslctx;
+ /** ssl context for connecting to dnstcp over ssl */
+ void* connect_dot_sslctx;
+ /** ssl context for listening to DoH */
+ void* listen_doh_sslctx;
/** ssl context for listening to quic */
- void* quic_sslctx;
+ void* listen_quic_sslctx;
/** num threads allocated */
int num;
/** num threads allocated in the previous config or 0 at first */
#endif /* HAVE_DAEMON */
}
+/* setup a listening ssl context, fatal_exit() on any failure */
+static void
+setup_listen_sslctx(void** ctx, int is_dot, int is_doh, struct config_file* cfg)
+{
+#ifdef HAVE_SSL
+ if(!(*ctx = listen_sslctx_create(
+ cfg->ssl_service_key, cfg->ssl_service_pem, NULL,
+ cfg->tls_ciphers, cfg->tls_ciphersuites,
+ (cfg->tls_session_ticket_keys.first &&
+ cfg->tls_session_ticket_keys.first->str[0] != 0),
+ is_dot, is_doh))) {
+ fatal_exit("could not set up listen SSL_CTX");
+ }
+#else /* HAVE_SSL */
+ (void)ctx;(void)is_dot;(void)is_doh;(void)cfg;
+#endif /* HAVE_SSL */
+}
+
+/* setups the needed ssl contexts, fatal_exit() on any failure */
+static void
+setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
+{
+#ifdef HAVE_SSL
+ 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]) {
+ /* setup the session keys; the callback to use them will be
+ * attached to each sslctx separately */
+ if(cfg->tls_session_ticket_keys.first &&
+ cfg->tls_session_ticket_keys.first->str[0] != 0) {
+ if(!listen_sslctx_setup_ticket_keys(
+ cfg->tls_session_ticket_keys.first)) {
+ fatal_exit("could not set session ticket SSL_CTX");
+ }
+ }
+ (void)setup_listen_sslctx(&daemon->listen_dot_sslctx, 1, 0, cfg);
+#ifdef HAVE_NGHTTP2_NGHTTP2_H
+ if(cfg_has_https(cfg)) {
+ (void)setup_listen_sslctx(&daemon->listen_doh_sslctx, 0, 1, cfg);
+ }
+#endif
+#ifdef HAVE_NGTCP2
+ if(!(daemon->listen_quic_sslctx = quic_sslctx_create(
+ cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) {
+ fatal_exit("could not set up quic SSL_CTX");
+ }
+#endif /* HAVE_NGTCP2 */
+ }
+ if(!(daemon->connect_dot_sslctx = connect_sslctx_create(NULL, NULL,
+ cfg->tls_cert_bundle, cfg->tls_win_cert)))
+ fatal_exit("could not set up connect SSL_CTX");
+#else /* HAVE_SSL */
+ (void)daemon;(void)cfg;
+#endif /* HAVE_SSL */
+}
+
/** daemonize, drop user privileges and chroot if needed */
static void
perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
#endif
/* read ssl keys while superuser and outside chroot */
-#ifdef HAVE_SSL
- 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(cfg->tls_ciphers && cfg->tls_ciphers[0]) {
- if (!SSL_CTX_set_cipher_list(daemon->listen_sslctx, cfg->tls_ciphers)) {
- fatal_exit("failed to set tls-cipher %s", cfg->tls_ciphers);
- }
- }
-#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
- if(cfg->tls_ciphersuites && cfg->tls_ciphersuites[0]) {
- if (!SSL_CTX_set_ciphersuites(daemon->listen_sslctx, cfg->tls_ciphersuites)) {
- fatal_exit("failed to set tls-ciphersuites %s", cfg->tls_ciphersuites);
- }
- }
-#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */
- if(cfg->tls_session_ticket_keys.first &&
- cfg->tls_session_ticket_keys.first->str[0] != 0) {
- if(!listen_sslctx_setup_ticket_keys(daemon->listen_sslctx, cfg->tls_session_ticket_keys.first)) {
- fatal_exit("could not set session ticket SSL_CTX");
- }
- }
-#ifdef HAVE_NGTCP2
- if(!(daemon->quic_sslctx = quic_sslctx_create(
- cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) {
- fatal_exit("could not set up quic SSL_CTX");
- }
-#endif /* HAVE_NGTCP2 */
- }
- if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL,
- cfg->tls_cert_bundle, cfg->tls_win_cert)))
- fatal_exit("could not set up connect SSL_CTX");
-#endif /* HAVE_SSL */
+ (void)setup_sslctxs(daemon, cfg);
/* init syslog (as root) if needed, before daemonize, otherwise
* a fork error could not be printed since daemonize closed stderr.*/
: cfg->tcp_idle_timeout,
cfg->harden_large_queries, cfg->http_max_streams,
cfg->http_endpoint, cfg->http_notls_downstream,
- worker->daemon->tcl, worker->daemon->listen_sslctx,
- worker->daemon->quic_sslctx,
+ worker->daemon->tcl, worker->daemon->listen_dot_sslctx,
+ worker->daemon->listen_doh_sslctx,
+ worker->daemon->listen_quic_sslctx,
dtenv, worker->daemon->doq_table, worker->env.rnd,
cfg, worker_handle_request, worker);
if(!worker->front) {
cfg->unwanted_threshold, cfg->outgoing_tcp_mss,
&worker_alloc_cleanup, worker,
cfg->do_udp || cfg->udp_upstream_without_downstream,
- worker->daemon->connect_sslctx, cfg->delay_close,
+ worker->daemon->connect_dot_sslctx, cfg->delay_close,
cfg->tls_use_sni, dtenv, cfg->udp_connect,
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
cfg->tcp_auth_query_timeout);
s->fd = -1;
s->ev_cb = ev_cb;
s->data = data;
- s->sslctx = listen_sslctx_create(server_key, server_cert, verifypem);
+ s->sslctx = listen_sslctx_create(server_key, server_cert, verifypem,
+ NULL, NULL, 0, 0, 0);
if(!s->sslctx) {
log_err("could not create ssl context");
free(s->ip);
size_t bufsize, int tcp_accept_count, int tcp_idle_timeout,
int harden_large_queries, uint32_t http_max_streams,
char* http_endpoint, int http_notls, struct tcl_list* tcp_conn_limit,
- void* sslctx, void* quic_sslctx, struct dt_env* dtenv,
+ void* dot_sslctx, void* doh_sslctx, void* quic_sslctx,
+ struct dt_env* dtenv,
struct doq_table* doq_table,
struct ub_randstate* rnd,struct config_file* cfg,
comm_point_callback_type* cb, void *cb_arg)
ports->ftype, ports->pp2_enabled, cb, cb_arg,
ports->socket);
if(ports->ftype == listen_type_http) {
- if(!sslctx && !http_notls) {
+ if(!doh_sslctx && !http_notls) {
log_warn("HTTPS port configured, but "
"no TLS tls-service-key or "
"tls-service-pem set");
cp->ssl = NULL;
} else if(ports->ftype == listen_type_doq) {
cp->ssl = quic_sslctx;
+ } else if(ports->ftype == listen_type_http) {
+ cp->ssl = doh_sslctx;
} else {
- cp->ssl = sslctx;
+ cp->ssl = dot_sslctx;
}
cp->dtenv = dtenv;
cp->do_not_close = 1;
* @param http_endpoint: HTTP endpoint to service queries on
* @param http_notls: no TLS for http downstream
* @param tcp_conn_limit: TCP connection limit info.
- * @param sslctx: nonNULL if ssl context.
+ * @param dot_sslctx: nonNULL if dot ssl context.
+ * @param doh_sslctx: nonNULL if doh ssl context.
* @param quic_sslctx: nonNULL if quic ssl context.
* @param dtenv: nonNULL if dnstap enabled.
* @param doq_table: the doq connection table, with shared information.
size_t bufsize, int tcp_accept_count, int tcp_idle_timeout,
int harden_large_queries, uint32_t http_max_streams,
char* http_endpoint, int http_notls, struct tcl_list* tcp_conn_limit,
- void* sslctx, void* quic_sslctx, struct dt_env* dtenv,
+ void* dot_sslctx, void* doh_sslctx, void* quic_sslctx,
+ struct dt_env* dtenv,
struct doq_table* doq_table,
struct ub_randstate* rnd,struct config_file* cfg,
comm_point_callback_type* cb, void *cb_arg);
char* ATTR_UNUSED(http_endpoint),
int ATTR_UNUSED(http_notls),
struct tcl_list* ATTR_UNUSED(tcp_conn_limit),
- void* ATTR_UNUSED(sslctx), void* ATTR_UNUSED(quic_ssl),
+ void* ATTR_UNUSED(dot_sslctx), void* ATTR_UNUSED(doh_sslctx),
+ void* ATTR_UNUSED(quic_ssl),
struct dt_env* ATTR_UNUSED(dtenv),
struct doq_table* ATTR_UNUSED(table),
struct ub_randstate* ATTR_UNUSED(rnd),
}
#endif /* HAVE_SSL */
+#if defined(HAVE_SSL) && defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB)
+static int
+dot_alpn_select_cb(SSL* ATTR_UNUSED(ssl), const unsigned char** out,
+ unsigned char* outlen, const unsigned char* in, unsigned int inlen,
+ void* ATTR_UNUSED(arg))
+{
+ static const unsigned char alpns[] = { 3, 'd', 'o', 't' };
+ unsigned char* tmp_out;
+ int ret;
+ ret = SSL_select_next_proto(&tmp_out, outlen, alpns, sizeof(alpns), in, inlen);
+ if(ret == OPENSSL_NPN_NO_OVERLAP) {
+ /* Client sent ALPN but no overlap. Should have been error,
+ * but for privacy we continue without ALPN (e.g., if certain
+ * ALPNs are blocked) */
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+ *out = tmp_out;
+ return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
#if defined(HAVE_SSL) && defined(HAVE_NGHTTP2) && defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB)
-static int alpn_select_cb(SSL* ATTR_UNUSED(ssl), const unsigned char** out,
+static int doh_alpn_select_cb(SSL* ATTR_UNUSED(ssl), const unsigned char** out,
unsigned char* outlen, const unsigned char* in, unsigned int inlen,
void* ATTR_UNUSED(arg))
{
}
#endif
+/* setup the callback for ticket keys */
+static int
+setup_ticket_keys_cb(void* sslctx)
+{
+# ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
+ if(SSL_CTX_set_tlsext_ticket_key_evp_cb(sslctx, tls_session_ticket_key_cb) == 0) {
+ return 0;
+ }
+# else
+ if(SSL_CTX_set_tlsext_ticket_key_cb(sslctx, tls_session_ticket_key_cb) == 0) {
+ return 0;
+ }
+# endif
+ return 1;
+}
+
+
int
listen_sslctx_setup(void* ctxt)
{
#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL
SSL_CTX_set_security_level(ctx, 0);
#endif
-#if defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB) && defined(HAVE_NGHTTP2)
- SSL_CTX_set_alpn_select_cb(ctx, alpn_select_cb, NULL);
-#endif
#else
(void)ctxt;
#endif /* HAVE_SSL */
#endif /* HAVE_SSL */
}
-void* listen_sslctx_create(char* key, char* pem, char* verifypem)
+void* listen_sslctx_create(const char* key, const char* pem,
+ const char* verifypem, const char* tls_ciphers,
+ const char* tls_ciphersuites, int set_ticket_keys_cb,
+ int is_dot, int is_doh)
{
#ifdef HAVE_SSL
SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
verifypem));
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
}
+ if(tls_ciphers && tls_ciphers[0]) {
+ if (!SSL_CTX_set_cipher_list(ctx, tls_ciphers)) {
+ log_err("failed to set tls-cipher %s",
+ tls_ciphers);
+ log_crypto_err("Error in SSL_CTX_set_cipher_list");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ }
+#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
+ if(tls_ciphersuites && tls_ciphersuites[0]) {
+ if (!SSL_CTX_set_ciphersuites(ctx, tls_ciphersuites)) {
+ log_err("failed to set tls-ciphersuites %s",
+ tls_ciphersuites);
+ log_crypto_err("Error in SSL_CTX_set_ciphersuites");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ }
+#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */
+ if(set_ticket_keys_cb) {
+ if(!setup_ticket_keys_cb(ctx)) {
+ log_crypto_err("no support for TLS session ticket");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ }
+ /* setup ALPN */
+#if defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB)
+ if(is_dot) {
+ SSL_CTX_set_alpn_select_cb(ctx, dot_alpn_select_cb, NULL);
+ } else if(is_doh) {
+#if defined(HAVE_NGHTTP2)
+ SSL_CTX_set_alpn_select_cb(ctx, doh_alpn_select_cb, NULL);
+#endif
+ }
+#endif /* HAVE_SSL_CTX_SET_ALPN_SELECT_CB */
return ctx;
#else
(void)key; (void)pem; (void)verifypem;
+ (void)tls_ciphers; (void)tls_ciphersuites;
+ (void)tls_session_ticket_keys;
return NULL;
-#endif
+#endif /* HAVE_SSL */
}
#ifdef USE_WINSOCK
#endif /* OPENSSL_THREADS */
}
-int listen_sslctx_setup_ticket_keys(void* sslctx, struct config_strlist* tls_session_ticket_keys) {
+int listen_sslctx_setup_ticket_keys(struct config_strlist* tls_session_ticket_keys) {
#ifdef HAVE_SSL
size_t s = 1;
struct config_strlist* p;
}
/* terminate array with NULL key name entry */
keys->key_name = NULL;
-# ifdef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
- if(SSL_CTX_set_tlsext_ticket_key_evp_cb(sslctx, tls_session_ticket_key_cb) == 0) {
- log_err("no support for TLS session ticket");
- return 0;
- }
-# else
- if(SSL_CTX_set_tlsext_ticket_key_cb(sslctx, tls_session_ticket_key_cb) == 0) {
- log_err("no support for TLS session ticket");
- return 0;
- }
-# endif
return 1;
#else
- (void)sslctx;
(void)tls_session_ticket_keys;
return 0;
#endif
-
}
#ifdef HAVE_SSL
* @param key: private key file.
* @param pem: public key cert.
* @param verifypem: if nonNULL, verifylocation file.
+ * @param tls_ciphers: if non empty string, tls ciphers to use.
+ * @param tls_ciphersuites: if non empty string, tls ciphersuites to use.
+ * @param set_ticket_keys_cb: if the callback for configured ticket keys needs
+ * to be set.
+ * @param is_dot: if the TLS connection is for DoT to set the appropriate ALPN.
+ * @param is_doh: if the TLS connection is for DoH to set the appropriate ALPN.
* return SSL_CTX* or NULL on failure (logged).
*/
-void* listen_sslctx_create(char* key, char* pem, char* verifypem);
+void* listen_sslctx_create(const char* key, const char* pem,
+ const char* verifypem, const char* tls_ciphers,
+ const char* tls_ciphersuites, int set_ticket_keys_cb,
+ int is_dot, int is_doh);
/**
* create SSL connect context
/**
* setup TLS session ticket
- * @param sslctx: the SSL_CTX to use (from connect_sslctx_create())
* @param tls_session_ticket_keys: TLS ticket secret filenames
* @return false on failure (alloc failure).
*/
-int listen_sslctx_setup_ticket_keys(void* sslctx,
- struct config_strlist* tls_session_ticket_keys);
+int listen_sslctx_setup_ticket_keys(struct config_strlist* tls_session_ticket_keys);
/** Free memory used for TLS session ticket keys */
void listen_sslctx_delete_ticket_keys(void);