summaryrefslogtreecommitdiff
path: root/contrib/unbound/util
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2018-05-12 15:04:05 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2018-05-12 15:04:05 +0000
commit57bddd215c419a01611bca0d1b1d545a64a7e731 (patch)
tree6c6ef88c9bb07275d652d9c1b6d0604268894bd7 /contrib/unbound/util
parent838e13ceea400eedd6865d8103874a12bc34fd7f (diff)
parent197f1a0fe3e81cde0cd25a3a1f37ebedf9a99488 (diff)
downloadsrc-test2-57bddd215c419a01611bca0d1b1d545a64a7e731.tar.gz
src-test2-57bddd215c419a01611bca0d1b1d545a64a7e731.zip
Notes
Diffstat (limited to 'contrib/unbound/util')
-rw-r--r--contrib/unbound/util/config_file.c60
-rw-r--r--contrib/unbound/util/config_file.h55
-rw-r--r--contrib/unbound/util/configlexer.lex18
-rw-r--r--contrib/unbound/util/configparser.y137
-rw-r--r--contrib/unbound/util/data/msgreply.c30
-rw-r--r--contrib/unbound/util/data/msgreply.h4
-rw-r--r--contrib/unbound/util/fptr_wlist.c9
-rw-r--r--contrib/unbound/util/iana_ports.inc6
-rw-r--r--contrib/unbound/util/log.c11
-rw-r--r--contrib/unbound/util/log.h9
-rw-r--r--contrib/unbound/util/module.h9
-rw-r--r--contrib/unbound/util/net_help.c15
-rw-r--r--contrib/unbound/util/net_help.h9
-rw-r--r--contrib/unbound/util/netevent.c796
-rw-r--r--contrib/unbound/util/netevent.h41
-rw-r--r--contrib/unbound/util/ub_event.c2
16 files changed, 1185 insertions, 26 deletions
diff --git a/contrib/unbound/util/config_file.c b/contrib/unbound/util/config_file.c
index 05b3d000183a..465fa35dbb28 100644
--- a/contrib/unbound/util/config_file.c
+++ b/contrib/unbound/util/config_file.c
@@ -108,6 +108,7 @@ config_create(void)
cfg->ssl_service_pem = NULL;
cfg->ssl_port = 853;
cfg->ssl_upstream = 0;
+ cfg->tls_cert_bundle = NULL;
cfg->use_syslog = 1;
cfg->log_identity = NULL; /* changed later with argv[0] */
cfg->log_time_ascii = 0;
@@ -177,6 +178,7 @@ config_create(void)
cfg->out_ifs = NULL;
cfg->stubs = NULL;
cfg->forwards = NULL;
+ cfg->auths = NULL;
#ifdef CLIENT_SUBNET
cfg->client_subnet = NULL;
cfg->client_subnet_zone = NULL;
@@ -219,6 +221,7 @@ config_create(void)
cfg->val_log_level = 0;
cfg->val_log_squelch = 0;
cfg->val_permissive_mode = 0;
+ cfg->aggressive_nsec = 0;
cfg->ignore_cd = 0;
cfg->serve_expired = 0;
cfg->add_holddown = 30*24*3600;
@@ -282,6 +285,7 @@ config_create(void)
cfg->dnscrypt_port = 0;
cfg->dnscrypt_provider = NULL;
cfg->dnscrypt_provider_cert = NULL;
+ cfg->dnscrypt_provider_cert_rotated = NULL;
cfg->dnscrypt_secret_key = NULL;
cfg->dnscrypt_shared_secret_cache_size = 4*1024*1024;
cfg->dnscrypt_shared_secret_cache_slabs = 4;
@@ -374,6 +378,10 @@ struct config_file* config_create_forlib(void)
/** put string into strlist */
#define S_STRLIST(str, var) if(strcmp(opt, str)==0) \
{ return cfg_strlist_insert(&cfg->var, strdup(val)); }
+/** put string into strlist if not present yet*/
+#define S_STRLIST_UNIQ(str, var) if(strcmp(opt, str)==0) \
+ { if(cfg_strlist_find(cfg->var, val)) { return 0;} \
+ return cfg_strlist_insert(&cfg->var, strdup(val)); }
int config_set_option(struct config_file* cfg, const char* opt,
const char* val)
@@ -437,6 +445,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_STR("ssl-service-key:", ssl_service_key)
else S_STR("ssl-service-pem:", ssl_service_pem)
else S_NUMBER_NONZERO("ssl-port:", ssl_port)
+ else S_STR("tls-cert-bundle:", tls_cert_bundle)
else S_YNO("interface-automatic:", if_automatic)
else S_YNO("use-systemd:", use_systemd)
else S_YNO("do-daemonize:", do_daemonize)
@@ -513,6 +522,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_YNO("log-queries:", log_queries)
else S_YNO("log-replies:", log_replies)
else S_YNO("val-permissive-mode:", val_permissive_mode)
+ else S_YNO("aggressive-nsec:", aggressive_nsec)
else S_YNO("ignore-cd-flag:", ignore_cd)
else S_YNO("serve-expired:", serve_expired)
else S_STR("val-nsec3-keysize-iterations:", val_nsec3_key_iterations)
@@ -570,8 +580,9 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_YNO("dnscrypt-enable:", dnscrypt)
else S_NUMBER_NONZERO("dnscrypt-port:", dnscrypt_port)
else S_STR("dnscrypt-provider:", dnscrypt_provider)
- else S_STRLIST("dnscrypt-provider-cert:", dnscrypt_provider_cert)
- else S_STRLIST("dnscrypt-secret-key:", dnscrypt_secret_key)
+ else S_STRLIST_UNIQ("dnscrypt-provider-cert:", dnscrypt_provider_cert)
+ else S_STRLIST("dnscrypt-provider-cert-rotated:", dnscrypt_provider_cert_rotated)
+ else S_STRLIST_UNIQ("dnscrypt-secret-key:", dnscrypt_secret_key)
else S_MEMSIZE("dnscrypt-shared-secret-cache-size:",
dnscrypt_shared_secret_cache_size)
else S_POW2("dnscrypt-shared-secret-cache-slabs:",
@@ -628,7 +639,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
* interface, outgoing-interface, access-control,
* stub-zone, name, stub-addr, stub-host, stub-prime
* forward-first, stub-first, forward-ssl-upstream,
- * stub-ssl-upstream, forward-zone,
+ * stub-ssl-upstream, forward-zone, auth-zone
* name, forward-addr, forward-host,
* ratelimit-for-domain, ratelimit-below-domain,
* local-zone-tag, access-control-view,
@@ -844,6 +855,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_STR(opt, "ssl-service-key", ssl_service_key)
else O_STR(opt, "ssl-service-pem", ssl_service_pem)
else O_DEC(opt, "ssl-port", ssl_port)
+ else O_STR(opt, "tls-cert-bundle", tls_cert_bundle)
else O_YNO(opt, "use-systemd", use_systemd)
else O_YNO(opt, "do-daemonize", do_daemonize)
else O_STR(opt, "chroot", chrootdir)
@@ -876,6 +888,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_YNO(opt, "val-clean-additional", val_clean_additional)
else O_DEC(opt, "val-log-level", val_log_level)
else O_YNO(opt, "val-permissive-mode", val_permissive_mode)
+ else O_YNO(opt, "aggressive-nsec:", aggressive_nsec)
else O_YNO(opt, "ignore-cd-flag", ignore_cd)
else O_YNO(opt, "serve-expired", serve_expired)
else O_STR(opt, "val-nsec3-keysize-iterations",val_nsec3_key_iterations)
@@ -941,6 +954,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_DEC(opt, "dnscrypt-port", dnscrypt_port)
else O_STR(opt, "dnscrypt-provider", dnscrypt_provider)
else O_LST(opt, "dnscrypt-provider-cert", dnscrypt_provider_cert)
+ else O_LST(opt, "dnscrypt-provider-cert-rotated", dnscrypt_provider_cert_rotated)
else O_LST(opt, "dnscrypt-secret-key", dnscrypt_secret_key)
else O_MEM(opt, "dnscrypt-shared-secret-cache-size",
dnscrypt_shared_secret_cache_size)
@@ -1158,6 +1172,28 @@ config_deltrplstrlist(struct config_str3list* p)
}
void
+config_delauth(struct config_auth* p)
+{
+ if(!p) return;
+ free(p->name);
+ config_delstrlist(p->masters);
+ config_delstrlist(p->urls);
+ free(p->zonefile);
+ free(p);
+}
+
+void
+config_delauths(struct config_auth* p)
+{
+ struct config_auth* np;
+ while(p) {
+ np = p->next;
+ config_delauth(p);
+ p = np;
+ }
+}
+
+void
config_delstub(struct config_stub* p)
{
if(!p) return;
@@ -1237,11 +1273,13 @@ config_delete(struct config_file* cfg)
free(cfg->target_fetch_policy);
free(cfg->ssl_service_key);
free(cfg->ssl_service_pem);
+ free(cfg->tls_cert_bundle);
free(cfg->log_identity);
config_del_strarray(cfg->ifs, cfg->num_ifs);
config_del_strarray(cfg->out_ifs, cfg->num_out_ifs);
config_delstubs(cfg->stubs);
config_delstubs(cfg->forwards);
+ config_delauths(cfg->auths);
config_delviews(cfg->views);
config_delstrlist(cfg->donotqueryaddrs);
config_delstrlist(cfg->root_hints);
@@ -1458,6 +1496,22 @@ cfg_region_strlist_insert(struct regional* region,
return 1;
}
+struct config_strlist*
+cfg_strlist_find(struct config_strlist* head, const char *item)
+{
+ struct config_strlist *s = head;
+ if(!head){
+ return NULL;
+ }
+ while(s) {
+ if(strcmp(s->str, item) == 0) {
+ return s;
+ }
+ s = s->next;
+ }
+ return NULL;
+}
+
int
cfg_strlist_insert(struct config_strlist** head, char* item)
{
diff --git a/contrib/unbound/util/config_file.h b/contrib/unbound/util/config_file.h
index 5d9b2d0be15e..2e1c53ee0733 100644
--- a/contrib/unbound/util/config_file.h
+++ b/contrib/unbound/util/config_file.h
@@ -42,6 +42,7 @@
#ifndef UTIL_CONFIG_FILE_H
#define UTIL_CONFIG_FILE_H
struct config_stub;
+struct config_auth;
struct config_view;
struct config_strlist;
struct config_str2list;
@@ -99,6 +100,8 @@ struct config_file {
int ssl_port;
/** if outgoing tcp connections use SSL */
int ssl_upstream;
+ /** cert bundle for outgoing connections */
+ char* tls_cert_bundle;
/** outgoing port range number of ports (per thread) */
int outgoing_num_ports;
@@ -170,6 +173,8 @@ struct config_file {
struct config_stub* stubs;
/** the forward zone definitions, linked list */
struct config_stub* forwards;
+ /** the auth zone definitions, linked list */
+ struct config_auth* auths;
/** the views definitions, linked list */
struct config_view* views;
/** list of donotquery addresses, linked list */
@@ -297,6 +302,8 @@ struct config_file {
int val_log_squelch;
/** should validator allow bogus messages to go through */
int val_permissive_mode;
+ /** use cached NSEC records to synthesise (negative) answers */
+ int aggressive_nsec;
/** ignore the CD flag in incoming queries and refuse them bogus data */
int ignore_cd;
/** serve expired entries and prefetch them */
@@ -466,6 +473,10 @@ struct config_file {
struct config_strlist* dnscrypt_secret_key;
/** dnscrypt provider certs 1.cert */
struct config_strlist* dnscrypt_provider_cert;
+ /** dnscrypt provider certs 1.cert which have been rotated and should not be
+ * advertised through DNS's providername TXT record but are required to be
+ * able to handle existing traffic using the old cert. */
+ struct config_strlist* dnscrypt_provider_cert_rotated;
/** memory size in bytes for dnscrypt shared secrets cache */
size_t dnscrypt_shared_secret_cache_size;
/** number of slabs for dnscrypt shared secrets cache */
@@ -527,6 +538,29 @@ struct config_stub {
};
/**
+ * Auth config options
+ */
+struct config_auth {
+ /** next in list */
+ struct config_auth* next;
+ /** domain name (in text) of the auth apex domain */
+ char* name;
+ /** list of masters */
+ struct config_strlist* masters;
+ /** list of urls */
+ struct config_strlist* urls;
+ /** zonefile (or NULL) */
+ char* zonefile;
+ /** provide downstream answers */
+ int for_downstream;
+ /** provide upstream answers */
+ int for_upstream;
+ /** fallback to recursion to authorities if zone expired and other
+ * reasons perhaps (like, query bogus) */
+ int fallback_enabled;
+};
+
+/**
* View config options
*/
struct config_view {
@@ -721,6 +755,15 @@ char* config_collate_cat(struct config_strlist* list);
int cfg_strlist_append(struct config_strlist_head* list, char* item);
/**
+ * Find string in strlist.
+ * @param head: pointer to strlist head variable.
+ * @param item: the item to search for.
+ * @return: the element in the list when found, NULL otherwise.
+ */
+struct config_strlist* cfg_strlist_find(struct config_strlist* head,
+ const char* item);
+
+/**
* Insert string into strlist.
* @param head: pointer to strlist head variable.
* @param item: new item. malloced by caller. If NULL the insertion fails.
@@ -808,6 +851,18 @@ void config_delstub(struct config_stub* p);
void config_delstubs(struct config_stub* list);
/**
+ * Delete an auth item
+ * @param p: auth item
+ */
+void config_delauth(struct config_auth* p);
+
+/**
+ * Delete items in config auth list.
+ * @param list: list.
+ */
+void config_delauths(struct config_auth* list);
+
+/**
* Delete a view item
* @param p: view item
*/
diff --git a/contrib/unbound/util/configlexer.lex b/contrib/unbound/util/configlexer.lex
index e397e8da5b53..d7f46aafe7b2 100644
--- a/contrib/unbound/util/configlexer.lex
+++ b/contrib/unbound/util/configlexer.lex
@@ -15,7 +15,6 @@
#endif
#include <ctype.h>
-#include <string.h>
#include <strings.h>
#ifdef HAVE_GLOB_H
# include <glob.h>
@@ -231,9 +230,15 @@ tcp-upstream{COLON} { YDVAR(1, VAR_TCP_UPSTREAM) }
tcp-mss{COLON} { YDVAR(1, VAR_TCP_MSS) }
outgoing-tcp-mss{COLON} { YDVAR(1, VAR_OUTGOING_TCP_MSS) }
ssl-upstream{COLON} { YDVAR(1, VAR_SSL_UPSTREAM) }
+tls-upstream{COLON} { YDVAR(1, VAR_SSL_UPSTREAM) }
ssl-service-key{COLON} { YDVAR(1, VAR_SSL_SERVICE_KEY) }
+tls-service-key{COLON} { YDVAR(1, VAR_SSL_SERVICE_KEY) }
ssl-service-pem{COLON} { YDVAR(1, VAR_SSL_SERVICE_PEM) }
+tls-service-pem{COLON} { YDVAR(1, VAR_SSL_SERVICE_PEM) }
ssl-port{COLON} { YDVAR(1, VAR_SSL_PORT) }
+tls-port{COLON} { YDVAR(1, VAR_SSL_PORT) }
+ssl-cert-bundle{COLON} { YDVAR(1, VAR_TLS_CERT_BUNDLE) }
+tls-cert-bundle{COLON} { YDVAR(1, VAR_TLS_CERT_BUNDLE) }
use-systemd{COLON} { YDVAR(1, VAR_USE_SYSTEMD) }
do-daemonize{COLON} { YDVAR(1, VAR_DO_DAEMONIZE) }
interface{COLON} { YDVAR(1, VAR_INTERFACE) }
@@ -291,11 +296,20 @@ stub-host{COLON} { YDVAR(1, VAR_STUB_HOST) }
stub-prime{COLON} { YDVAR(1, VAR_STUB_PRIME) }
stub-first{COLON} { YDVAR(1, VAR_STUB_FIRST) }
stub-ssl-upstream{COLON} { YDVAR(1, VAR_STUB_SSL_UPSTREAM) }
+stub-tls-upstream{COLON} { YDVAR(1, VAR_STUB_SSL_UPSTREAM) }
forward-zone{COLON} { YDVAR(0, VAR_FORWARD_ZONE) }
forward-addr{COLON} { YDVAR(1, VAR_FORWARD_ADDR) }
forward-host{COLON} { YDVAR(1, VAR_FORWARD_HOST) }
forward-first{COLON} { YDVAR(1, VAR_FORWARD_FIRST) }
forward-ssl-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
+forward-tls-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
+auth-zone{COLON} { YDVAR(0, VAR_AUTH_ZONE) }
+zonefile{COLON} { YDVAR(1, VAR_ZONEFILE) }
+master{COLON} { YDVAR(1, VAR_MASTER) }
+url{COLON} { YDVAR(1, VAR_URL) }
+for-downstream{COLON} { YDVAR(1, VAR_FOR_DOWNSTREAM) }
+for-upstream{COLON} { YDVAR(1, VAR_FOR_UPSTREAM) }
+fallback-enabled{COLON} { YDVAR(1, VAR_FALLBACK_ENABLED) }
view{COLON} { YDVAR(0, VAR_VIEW) }
view-first{COLON} { YDVAR(1, VAR_VIEW_FIRST) }
do-not-query-address{COLON} { YDVAR(1, VAR_DO_NOT_QUERY_ADDRESS) }
@@ -326,6 +340,7 @@ val-sig-skew-max{COLON} { YDVAR(1, VAR_VAL_SIG_SKEW_MAX) }
val-bogus-ttl{COLON} { YDVAR(1, VAR_BOGUS_TTL) }
val-clean-additional{COLON} { YDVAR(1, VAR_VAL_CLEAN_ADDITIONAL) }
val-permissive-mode{COLON} { YDVAR(1, VAR_VAL_PERMISSIVE_MODE) }
+aggressive-nsec{COLON} { YDVAR(1, VAR_AGGRESSIVE_NSEC) }
ignore-cd-flag{COLON} { YDVAR(1, VAR_IGNORE_CD_FLAG) }
serve-expired{COLON} { YDVAR(1, VAR_SERVE_EXPIRED) }
fake-dsa{COLON} { YDVAR(1, VAR_FAKE_DSA) }
@@ -418,6 +433,7 @@ dnscrypt-port{COLON} { YDVAR(1, VAR_DNSCRYPT_PORT) }
dnscrypt-provider{COLON} { YDVAR(1, VAR_DNSCRYPT_PROVIDER) }
dnscrypt-secret-key{COLON} { YDVAR(1, VAR_DNSCRYPT_SECRET_KEY) }
dnscrypt-provider-cert{COLON} { YDVAR(1, VAR_DNSCRYPT_PROVIDER_CERT) }
+dnscrypt-provider-cert-rotated{COLON} { YDVAR(1, VAR_DNSCRYPT_PROVIDER_CERT_ROTATED) }
dnscrypt-shared-secret-cache-size{COLON} {
YDVAR(1, VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE) }
dnscrypt-shared-secret-cache-slabs{COLON} {
diff --git a/contrib/unbound/util/configparser.y b/contrib/unbound/util/configparser.y
index 1f72c73b08d8..7e23fca16823 100644
--- a/contrib/unbound/util/configparser.y
+++ b/contrib/unbound/util/configparser.y
@@ -109,7 +109,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_LOG_REPLIES
%token VAR_TCP_UPSTREAM VAR_SSL_UPSTREAM
%token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST
-%token VAR_STUB_SSL_UPSTREAM VAR_FORWARD_SSL_UPSTREAM
+%token VAR_STUB_SSL_UPSTREAM VAR_FORWARD_SSL_UPSTREAM VAR_TLS_CERT_BUNDLE
%token VAR_STUB_FIRST VAR_MINIMAL_RESPONSES VAR_RRSET_ROUNDROBIN
%token VAR_MAX_UDP_SIZE VAR_DELAY_CLOSE
%token VAR_UNBLOCK_LAN_ZONES VAR_INSECURE_LAN_ZONES
@@ -141,9 +141,10 @@ extern struct config_parser_state* cfg_parser;
%token VAR_ACCESS_CONTROL_TAG_DATA VAR_VIEW VAR_ACCESS_CONTROL_VIEW
%token VAR_VIEW_FIRST VAR_SERVE_EXPIRED VAR_FAKE_DSA VAR_FAKE_SHA1
%token VAR_LOG_IDENTITY VAR_HIDE_TRUSTANCHOR VAR_TRUST_ANCHOR_SIGNALING
-%token VAR_USE_SYSTEMD VAR_SHM_ENABLE VAR_SHM_KEY
+%token VAR_AGGRESSIVE_NSEC VAR_USE_SYSTEMD VAR_SHM_ENABLE VAR_SHM_KEY
%token VAR_DNSCRYPT VAR_DNSCRYPT_ENABLE VAR_DNSCRYPT_PORT VAR_DNSCRYPT_PROVIDER
%token VAR_DNSCRYPT_SECRET_KEY VAR_DNSCRYPT_PROVIDER_CERT
+%token VAR_DNSCRYPT_PROVIDER_CERT_ROTATED
%token VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE
%token VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS
%token VAR_DNSCRYPT_NONCE_CACHE_SIZE
@@ -151,16 +152,17 @@ extern struct config_parser_state* cfg_parser;
%token VAR_IPSECMOD_ENABLED VAR_IPSECMOD_HOOK VAR_IPSECMOD_IGNORE_BOGUS
%token VAR_IPSECMOD_MAX_TTL VAR_IPSECMOD_WHITELIST VAR_IPSECMOD_STRICT
%token VAR_CACHEDB VAR_CACHEDB_BACKEND VAR_CACHEDB_SECRETSEED
-%token VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM
+%token VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM VAR_FOR_UPSTREAM
+%token VAR_AUTH_ZONE VAR_ZONEFILE VAR_MASTER VAR_URL VAR_FOR_DOWNSTREAM
+%token VAR_FALLBACK_ENABLED
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
toplevelvar: serverstart contents_server | stubstart contents_stub |
forwardstart contents_forward | pythonstart contents_py |
- rcstart contents_rc | dtstart contents_dt | viewstart
- contents_view |
- dnscstart contents_dnsc |
- cachedbstart contents_cachedb
+ rcstart contents_rc | dtstart contents_dt | viewstart contents_view |
+ dnscstart contents_dnsc | cachedbstart contents_cachedb |
+ authstart contents_auth
;
/* server: declaration */
@@ -241,7 +243,8 @@ content_server: server_num_threads | server_verbosity | server_port |
server_ipsecmod_enabled | server_ipsecmod_hook |
server_ipsecmod_ignore_bogus | server_ipsecmod_max_ttl |
server_ipsecmod_whitelist | server_ipsecmod_strict |
- server_udp_upstream_without_downstream
+ server_udp_upstream_without_downstream | server_aggressive_nsec |
+ server_tls_cert_bundle
;
stubstart: VAR_STUB_ZONE
{
@@ -296,6 +299,27 @@ contents_view: contents_view content_view
content_view: view_name | view_local_zone | view_local_data | view_first |
view_response_ip | view_response_ip_data | view_local_data_ptr
;
+authstart: VAR_AUTH_ZONE
+ {
+ struct config_auth* s;
+ OUTYY(("\nP(auth_zone:)\n"));
+ s = (struct config_auth*)calloc(1, sizeof(struct config_auth));
+ if(s) {
+ s->next = cfg_parser->cfg->auths;
+ cfg_parser->cfg->auths = s;
+ /* defaults for auth zone */
+ s->for_downstream = 1;
+ s->for_upstream = 1;
+ s->fallback_enabled = 0;
+ } else
+ yyerror("out of memory");
+ }
+ ;
+contents_auth: contents_auth content_auth
+ | ;
+content_auth: auth_name | auth_zonefile | auth_master | auth_url |
+ auth_for_downstream | auth_for_upstream | auth_fallback_enabled
+ ;
server_num_threads: VAR_NUM_THREADS STRING_ARG
{
OUTYY(("P(server_num_threads:%s)\n", $2));
@@ -651,6 +675,13 @@ server_ssl_port: VAR_SSL_PORT STRING_ARG
free($2);
}
;
+server_tls_cert_bundle: VAR_TLS_CERT_BUNDLE STRING_ARG
+ {
+ OUTYY(("P(server_tls_cert_bundle:%s)\n", $2));
+ free(cfg_parser->cfg->tls_cert_bundle);
+ cfg_parser->cfg->tls_cert_bundle = $2;
+ }
+ ;
server_use_systemd: VAR_USE_SYSTEMD STRING_ARG
{
OUTYY(("P(server_use_systemd:%s)\n", $2));
@@ -1367,6 +1398,17 @@ server_val_permissive_mode: VAR_VAL_PERMISSIVE_MODE STRING_ARG
free($2);
}
;
+server_aggressive_nsec: VAR_AGGRESSIVE_NSEC STRING_ARG
+ {
+ OUTYY(("P(server_aggressive_nsec:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else
+ cfg_parser->cfg->aggressive_nsec =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_ignore_cd_flag: VAR_IGNORE_CD_FLAG STRING_ARG
{
OUTYY(("P(server_ignore_cd_flag:%s)\n", $2));
@@ -1502,12 +1544,13 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
&& strcmp($3, "always_transparent")!=0
&& strcmp($3, "always_refuse")!=0
&& strcmp($3, "always_nxdomain")!=0
+ && strcmp($3, "noview")!=0
&& strcmp($3, "inform")!=0 && strcmp($3, "inform_deny")!=0)
yyerror("local-zone type: expected static, deny, "
"refuse, redirect, transparent, "
"typetransparent, inform, inform_deny, "
"always_transparent, always_refuse, "
- "always_nxdomain or nodefault");
+ "always_nxdomain, noview or nodefault");
else if(strcmp($3, "nodefault")==0) {
if(!cfg_strlist_insert(&cfg_parser->cfg->
local_zones_nodefault, $2))
@@ -1998,6 +2041,67 @@ forward_ssl_upstream: VAR_FORWARD_SSL_UPSTREAM STRING_ARG
free($2);
}
;
+auth_name: VAR_NAME STRING_ARG
+ {
+ OUTYY(("P(name:%s)\n", $2));
+ if(cfg_parser->cfg->auths->name)
+ yyerror("auth name override, there must be one name "
+ "for one auth-zone");
+ free(cfg_parser->cfg->auths->name);
+ cfg_parser->cfg->auths->name = $2;
+ }
+ ;
+auth_zonefile: VAR_ZONEFILE STRING_ARG
+ {
+ OUTYY(("P(zonefile:%s)\n", $2));
+ free(cfg_parser->cfg->auths->zonefile);
+ cfg_parser->cfg->auths->zonefile = $2;
+ }
+ ;
+auth_master: VAR_MASTER STRING_ARG
+ {
+ OUTYY(("P(master:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->auths->masters, $2))
+ yyerror("out of memory");
+ }
+ ;
+auth_url: VAR_URL STRING_ARG
+ {
+ OUTYY(("P(url:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->auths->urls, $2))
+ yyerror("out of memory");
+ }
+ ;
+auth_for_downstream: VAR_FOR_DOWNSTREAM STRING_ARG
+ {
+ OUTYY(("P(for-downstream:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->auths->for_downstream =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+auth_for_upstream: VAR_FOR_UPSTREAM STRING_ARG
+ {
+ OUTYY(("P(for-upstream:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->auths->for_upstream =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+auth_fallback_enabled: VAR_FALLBACK_ENABLED STRING_ARG
+ {
+ OUTYY(("P(fallback-enabled:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->auths->fallback_enabled =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
view_name: VAR_NAME STRING_ARG
{
OUTYY(("P(name:%s)\n", $2));
@@ -2018,12 +2122,13 @@ view_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
&& strcmp($3, "always_transparent")!=0
&& strcmp($3, "always_refuse")!=0
&& strcmp($3, "always_nxdomain")!=0
+ && strcmp($3, "noview")!=0
&& strcmp($3, "inform")!=0 && strcmp($3, "inform_deny")!=0)
yyerror("local-zone type: expected static, deny, "
"refuse, redirect, transparent, "
"typetransparent, inform, inform_deny, "
"always_transparent, always_refuse, "
- "always_nxdomain or nodefault");
+ "always_nxdomain, noview or nodefault");
else if(strcmp($3, "nodefault")==0) {
if(!cfg_strlist_insert(&cfg_parser->cfg->views->
local_zones_nodefault, $2))
@@ -2339,6 +2444,7 @@ contents_dnsc: contents_dnsc content_dnsc
content_dnsc:
dnsc_dnscrypt_enable | dnsc_dnscrypt_port | dnsc_dnscrypt_provider |
dnsc_dnscrypt_secret_key | dnsc_dnscrypt_provider_cert |
+ dnsc_dnscrypt_provider_cert_rotated |
dnsc_dnscrypt_shared_secret_cache_size |
dnsc_dnscrypt_shared_secret_cache_slabs |
dnsc_dnscrypt_nonce_cache_size |
@@ -2374,13 +2480,24 @@ dnsc_dnscrypt_provider: VAR_DNSCRYPT_PROVIDER STRING_ARG
dnsc_dnscrypt_provider_cert: VAR_DNSCRYPT_PROVIDER_CERT STRING_ARG
{
OUTYY(("P(dnsc_dnscrypt_provider_cert:%s)\n", $2));
+ if(cfg_strlist_find(cfg_parser->cfg->dnscrypt_provider_cert, $2))
+ log_warn("dnscrypt-provider-cert %s is a duplicate", $2);
if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_provider_cert, $2))
fatal_exit("out of memory adding dnscrypt-provider-cert");
}
;
+dnsc_dnscrypt_provider_cert_rotated: VAR_DNSCRYPT_PROVIDER_CERT_ROTATED STRING_ARG
+ {
+ OUTYY(("P(dnsc_dnscrypt_provider_cert_rotated:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_provider_cert_rotated, $2))
+ fatal_exit("out of memory adding dnscrypt-provider-cert-rotated");
+ }
+ ;
dnsc_dnscrypt_secret_key: VAR_DNSCRYPT_SECRET_KEY STRING_ARG
{
OUTYY(("P(dnsc_dnscrypt_secret_key:%s)\n", $2));
+ if(cfg_strlist_find(cfg_parser->cfg->dnscrypt_secret_key, $2))
+ log_warn("dnscrypt-secret-key: %s is a duplicate", $2);
if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_secret_key, $2))
fatal_exit("out of memory adding dnscrypt-secret-key");
}
diff --git a/contrib/unbound/util/data/msgreply.c b/contrib/unbound/util/data/msgreply.c
index ae2fe02b6d7c..e25b42cc257a 100644
--- a/contrib/unbound/util/data/msgreply.c
+++ b/contrib/unbound/util/data/msgreply.c
@@ -631,9 +631,14 @@ query_info_entrysetup(struct query_info* q, struct reply_info* r,
e->entry.key = e;
e->entry.data = r;
lock_rw_init(&e->entry.lock);
- lock_protect(&e->entry.lock, &e->key, sizeof(e->key));
- lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash) +
- sizeof(e->entry.key) + sizeof(e->entry.data));
+ lock_protect(&e->entry.lock, &e->key.qname, sizeof(e->key.qname));
+ lock_protect(&e->entry.lock, &e->key.qname_len, sizeof(e->key.qname_len));
+ lock_protect(&e->entry.lock, &e->key.qtype, sizeof(e->key.qtype));
+ lock_protect(&e->entry.lock, &e->key.qclass, sizeof(e->key.qclass));
+ lock_protect(&e->entry.lock, &e->key.local_alias, sizeof(e->key.local_alias));
+ lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash));
+ lock_protect(&e->entry.lock, &e->entry.key, sizeof(e->entry.key));
+ lock_protect(&e->entry.lock, &e->entry.data, sizeof(e->entry.data));
lock_protect(&e->entry.lock, e->key.qname, e->key.qname_len);
q->qname = NULL;
return e;
@@ -896,6 +901,25 @@ reply_all_rrsets_secure(struct reply_info* rep)
return 1;
}
+struct reply_info*
+parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region,
+ struct query_info* qi)
+{
+ struct reply_info* rep;
+ struct msg_parse* msg;
+ if(!(msg = regional_alloc(region, sizeof(*msg)))) {
+ return NULL;
+ }
+ memset(msg, 0, sizeof(*msg));
+ sldns_buffer_set_position(pkt, 0);
+ if(parse_packet(pkt, msg, region) != 0)
+ return 0;
+ if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) {
+ return 0;
+ }
+ return rep;
+}
+
int edns_opt_append(struct edns_data* edns, struct regional* region,
uint16_t code, size_t len, uint8_t* data)
{
diff --git a/contrib/unbound/util/data/msgreply.h b/contrib/unbound/util/data/msgreply.h
index b66f344e1521..60e6438a84ab 100644
--- a/contrib/unbound/util/data/msgreply.h
+++ b/contrib/unbound/util/data/msgreply.h
@@ -285,6 +285,10 @@ int parse_create_msg(struct sldns_buffer* pkt, struct msg_parse* msg,
struct alloc_cache* alloc, struct query_info* qinf,
struct reply_info** rep, struct regional* region);
+/** get msg reply struct (in temp region) */
+struct reply_info* parse_reply_in_temp_region(struct sldns_buffer* pkt,
+ struct regional* region, struct query_info* qi);
+
/**
* Sorts the ref array.
* @param rep: reply info. rrsets must be filled in.
diff --git a/contrib/unbound/util/fptr_wlist.c b/contrib/unbound/util/fptr_wlist.c
index d3c1a0c06b24..400a15de2ebb 100644
--- a/contrib/unbound/util/fptr_wlist.c
+++ b/contrib/unbound/util/fptr_wlist.c
@@ -98,6 +98,9 @@ fptr_whitelist_comm_point(comm_point_callback_type *fptr)
else if(fptr == &outnet_udp_cb) return 1;
else if(fptr == &outnet_tcp_cb) return 1;
else if(fptr == &tube_handle_listen) return 1;
+ else if(fptr == &auth_xfer_probe_udp_callback) return 1;
+ else if(fptr == &auth_xfer_transfer_tcp_callback) return 1;
+ else if(fptr == &auth_xfer_transfer_http_callback) return 1;
return 0;
}
@@ -122,6 +125,8 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
#ifdef UB_ON_WINDOWS
else if(fptr == &wsvc_cron_cb) return 1;
#endif
+ else if(fptr == &auth_xfer_timer) return 1;
+ else if(fptr == &auth_xfer_probe_timer_callback) return 1;
return 0;
}
@@ -157,6 +162,7 @@ fptr_whitelist_event(void (*fptr)(int, short, void *))
else if(fptr == &comm_point_raw_handle_callback) return 1;
else if(fptr == &tube_handle_signal) return 1;
else if(fptr == &comm_base_handle_slow_accept) return 1;
+ else if(fptr == &comm_point_http_handle_callback) return 1;
#ifdef UB_ON_WINDOWS
else if(fptr == &worker_win_stop_cb) return 1;
#endif
@@ -215,6 +221,7 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *))
else if(fptr == &view_cmp) return 1;
else if(fptr == &auth_zone_cmp) return 1;
else if(fptr == &auth_data_cmp) return 1;
+ else if(fptr == &auth_xfer_cmp) return 1;
return 0;
}
@@ -509,6 +516,8 @@ int fptr_whitelist_mesh_cb(mesh_cb_func_type fptr)
else if(fptr == &libworker_bg_done_cb) return 1;
else if(fptr == &libworker_event_done_cb) return 1;
else if(fptr == &probe_answer_cb) return 1;
+ else if(fptr == &auth_xfer_probe_lookup_callback) return 1;
+ else if(fptr == &auth_xfer_transfer_lookup_callback) return 1;
return 0;
}
diff --git a/contrib/unbound/util/iana_ports.inc b/contrib/unbound/util/iana_ports.inc
index 58c69fd1c1a7..e44a796dc4ad 100644
--- a/contrib/unbound/util/iana_ports.inc
+++ b/contrib/unbound/util/iana_ports.inc
@@ -4584,6 +4584,7 @@
7040,
7070,
7071,
+7072,
7080,
7088,
7095,
@@ -4634,6 +4635,7 @@
7402,
7410,
7411,
+7420,
7421,
7426,
7427,
@@ -4670,6 +4672,7 @@
7629,
7633,
7648,
+7663,
7674,
7675,
7676,
@@ -4896,6 +4899,7 @@
9026,
9060,
9080,
+9081,
9084,
9085,
9086,
@@ -5390,6 +5394,7 @@
33331,
33334,
33434,
+33435,
33656,
34249,
34378,
@@ -5431,6 +5436,7 @@
43189,
43190,
43210,
+43438,
43439,
43440,
43441,
diff --git a/contrib/unbound/util/log.c b/contrib/unbound/util/log.c
index c14b45834add..75a58f9de3db 100644
--- a/contrib/unbound/util/log.c
+++ b/contrib/unbound/util/log.c
@@ -191,6 +191,17 @@ void log_set_time_asc(int use_asc)
log_time_asc = use_asc;
}
+void* log_get_lock(void)
+{
+ if(!key_created)
+ return NULL;
+#ifndef THREADS_DISABLED
+ return (void*)&log_lock;
+#else
+ return NULL;
+#endif
+}
+
void
log_vmsg(int pri, const char* type,
const char *format, va_list args)
diff --git a/contrib/unbound/util/log.h b/contrib/unbound/util/log.h
index 8e85ee620b18..7bc3d9e76152 100644
--- a/contrib/unbound/util/log.h
+++ b/contrib/unbound/util/log.h
@@ -127,6 +127,9 @@ void log_set_time(time_t* t);
*/
void log_set_time_asc(int use_asc);
+/** get log lock */
+void* log_get_lock(void);
+
/**
* Log informational message.
* Pass printf formatted arguments. No trailing newline is needed.
@@ -186,11 +189,17 @@ void log_vmsg(int pri, const char* type, const char* format, va_list args);
* an assertion that is thrown to the logfile.
*/
#ifdef UNBOUND_DEBUG
+#ifdef __clang_analyzer__
+/* clang analyzer needs to know that log_assert is an assertion, otherwise
+ * it could complain about the nullptr the assert is guarding against. */
+#define log_assert(x) assert(x)
+#else
# define log_assert(x) \
do { if(!(x)) \
fatal_exit("%s:%d: %s: assertion %s failed", \
__FILE__, __LINE__, __func__, #x); \
} while(0);
+#endif
#else
# define log_assert(x) /*nothing*/
#endif
diff --git a/contrib/unbound/util/module.h b/contrib/unbound/util/module.h
index 415865c3d8b6..73db994bd7a3 100644
--- a/contrib/unbound/util/module.h
+++ b/contrib/unbound/util/module.h
@@ -166,6 +166,9 @@ struct query_info;
struct edns_data;
struct regional;
struct worker;
+struct comm_base;
+struct auth_zones;
+struct outside_network;
struct module_qstate;
struct ub_randstate;
struct mesh_area;
@@ -445,6 +448,10 @@ struct module_env {
struct sldns_buffer* scratch_buffer;
/** internal data for daemon - worker thread. */
struct worker* worker;
+ /** the worker event base */
+ struct comm_base* worker_base;
+ /** the outside network */
+ struct outside_network* outnet;
/** mesh area with query state dependencies */
struct mesh_area* mesh;
/** allocation service */
@@ -468,6 +475,8 @@ struct module_env {
struct val_neg_cache* neg_cache;
/** the 5011-probe timer (if any) */
struct comm_timer* probe_timer;
+ /** auth zones */
+ struct auth_zones* auth_zones;
/** Mapping of forwarding zones to targets.
* iterator forwarder information. per-thread, created by worker */
struct iter_forwards* fwds;
diff --git a/contrib/unbound/util/net_help.c b/contrib/unbound/util/net_help.c
index ce136a337cff..fdc8b0558af0 100644
--- a/contrib/unbound/util/net_help.c
+++ b/contrib/unbound/util/net_help.c
@@ -271,6 +271,19 @@ int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr,
return 1;
}
+/** store port number into sockaddr structure */
+void
+sockaddr_store_port(struct sockaddr_storage* addr, socklen_t addrlen, int port)
+{
+ if(addr_is_ip6(addr, addrlen)) {
+ struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
+ sa->sin6_port = (in_port_t)htons((uint16_t)port);
+ } else {
+ struct sockaddr_in* sa = (struct sockaddr_in*)addr;
+ sa->sin_port = (in_port_t)htons((uint16_t)port);
+ }
+}
+
void
log_nametypeclass(enum verbosity_value v, const char* str, uint8_t* name,
uint16_t type, uint16_t dclass)
@@ -645,7 +658,7 @@ listen_sslctx_setup(void* ctxt)
#endif
#if defined(SHA256_DIGEST_LENGTH) && defined(USE_ECDSA)
/* if we have sha256, set the cipher list to have no known vulns */
- if(!SSL_CTX_set_cipher_list(ctx, "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"))
+ if(!SSL_CTX_set_cipher_list(ctx, "TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"))
log_crypto_err("could not set cipher list with SSL_CTX_set_cipher_list");
#endif
diff --git a/contrib/unbound/util/net_help.h b/contrib/unbound/util/net_help.h
index f0236e5335df..2d6fce91db6e 100644
--- a/contrib/unbound/util/net_help.h
+++ b/contrib/unbound/util/net_help.h
@@ -202,6 +202,15 @@ int netblockstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr,
socklen_t* addrlen, int* net);
/**
+ * Store port number into sockaddr structure
+ * @param addr: sockaddr structure, ip4 or ip6.
+ * @param addrlen: length of addr.
+ * @param port: port number to put into the addr.
+ */
+void sockaddr_store_port(struct sockaddr_storage* addr, socklen_t addrlen,
+ int port);
+
+/**
* Print string with neat domain name, type and class.
* @param v: at what verbosity level to print this.
* @param str: string of message.
diff --git a/contrib/unbound/util/netevent.c b/contrib/unbound/util/netevent.c
index 5965a2d9aba6..fc6f6a9ea8b5 100644
--- a/contrib/unbound/util/netevent.c
+++ b/contrib/unbound/util/netevent.c
@@ -299,6 +299,12 @@ udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
# endif
) && verbosity < VERB_DETAIL)
return 0;
+# ifdef EADDRINUSE
+ /* If SO_REUSEADDR is set, we could try to connect to the same server
+ * from the same source port twice. */
+ if(errno == EADDRINUSE && verbosity < VERB_DETAIL)
+ return 0;
+# endif
/* squelch errors where people deploy AAAA ::ffff:bla for
* authority servers, which we try for intranets. */
if(errno == EINVAL && addr_is_ip4mapped(
@@ -648,7 +654,7 @@ comm_point_udp_ancil_callback(int fd, short event, void* arg)
(void)comm_point_send_udp_msg_if(rep.c, rep.c->buffer,
(struct sockaddr*)&rep.addr, rep.addrlen, &rep);
}
- if(rep.c->fd == -1) /* commpoint closed */
+ if(!rep.c || rep.c->fd == -1) /* commpoint closed */
break;
}
#else
@@ -711,7 +717,7 @@ comm_point_udp_callback(int fd, short event, void* arg)
(void)comm_point_send_udp_msg(rep.c, buffer,
(struct sockaddr*)&rep.addr, rep.addrlen);
}
- if(rep.c->fd != fd) /* commpoint closed to -1 or reused for
+ if(!rep.c || rep.c->fd != fd) /* commpoint closed to -1 or reused for
another UDP port. Note rep.c cannot be reused with TCP fd. */
break;
}
@@ -964,6 +970,32 @@ tcp_callback_reader(struct comm_point* c)
}
}
+#ifdef HAVE_SSL
+/** log certificate details */
+static void
+log_cert(unsigned level, const char* str, X509* cert)
+{
+ BIO* bio;
+ char nul = 0;
+ char* pp = NULL;
+ long len;
+ if(verbosity < level) return;
+ bio = BIO_new(BIO_s_mem());
+ if(!bio) return;
+ X509_print_ex(bio, cert, 0, (unsigned long)-1
+ ^(X509_FLAG_NO_SUBJECT
+ |X509_FLAG_NO_ISSUER|X509_FLAG_NO_VALIDITY
+ |X509_FLAG_NO_EXTENSIONS|X509_FLAG_NO_AUX
+ |X509_FLAG_NO_ATTRIBUTES));
+ BIO_write(bio, &nul, (int)sizeof(nul));
+ len = BIO_get_mem_data(bio, &pp);
+ if(len != 0 && pp) {
+ verbose(level, "%s: \n%s", str, pp);
+ }
+ BIO_free(bio);
+}
+#endif /* HAVE_SSL */
+
/** continue ssl handshake */
#ifdef HAVE_SSL
static int
@@ -1015,8 +1047,51 @@ ssl_handshake(struct comm_point* c)
}
}
/* this is where peer verification could take place */
- log_addr(VERB_ALGO, "SSL DNS connection", &c->repinfo.addr,
- c->repinfo.addrlen);
+ if((SSL_get_verify_mode(c->ssl)&SSL_VERIFY_PEER)) {
+ /* verification */
+ if(SSL_get_verify_result(c->ssl) == X509_V_OK) {
+ X509* x = SSL_get_peer_certificate(c->ssl);
+ if(!x) {
+ log_addr(VERB_ALGO, "SSL connection failed: "
+ "no certificate",
+ &c->repinfo.addr, c->repinfo.addrlen);
+ return 0;
+ }
+ log_cert(VERB_ALGO, "peer certificate", x);
+#ifdef HAVE_SSL_GET0_PEERNAME
+ if(SSL_get0_peername(c->ssl)) {
+ char buf[255];
+ snprintf(buf, sizeof(buf), "SSL connection "
+ "to %s authenticated",
+ SSL_get0_peername(c->ssl));
+ log_addr(VERB_ALGO, buf, &c->repinfo.addr,
+ c->repinfo.addrlen);
+ } else {
+#endif
+ log_addr(VERB_ALGO, "SSL connection "
+ "authenticated", &c->repinfo.addr,
+ c->repinfo.addrlen);
+#ifdef HAVE_SSL_GET0_PEERNAME
+ }
+#endif
+ X509_free(x);
+ } else {
+ X509* x = SSL_get_peer_certificate(c->ssl);
+ if(x) {
+ log_cert(VERB_ALGO, "peer certificate", x);
+ X509_free(x);
+ }
+ log_addr(VERB_ALGO, "SSL connection failed: "
+ "failed to authenticate",
+ &c->repinfo.addr, c->repinfo.addrlen);
+ return 0;
+ }
+ } else {
+ /* unauthenticated, the verify peer flag was not set
+ * in c->ssl when the ssl object was created from ssl_ctx */
+ log_addr(VERB_ALGO, "SSL connection", &c->repinfo.addr,
+ c->repinfo.addrlen);
+ }
/* setup listen rw correctly */
if(c->tcp_is_reading) {
@@ -1600,6 +1675,644 @@ comm_point_tcp_handle_callback(int fd, short event, void* arg)
log_err("Ignored event %d for tcphdl.", event);
}
+/** Make http handler free for next assignment */
+static void
+reclaim_http_handler(struct comm_point* c)
+{
+ log_assert(c->type == comm_http);
+ if(c->ssl) {
+#ifdef HAVE_SSL
+ SSL_shutdown(c->ssl);
+ SSL_free(c->ssl);
+ c->ssl = NULL;
+#endif
+ }
+ comm_point_close(c);
+ if(c->tcp_parent) {
+ c->tcp_parent->cur_tcp_count--;
+ c->tcp_free = c->tcp_parent->tcp_free;
+ c->tcp_parent->tcp_free = c;
+ if(!c->tcp_free) {
+ /* re-enable listening on accept socket */
+ comm_point_start_listening(c->tcp_parent, -1, -1);
+ }
+ }
+}
+
+/** read more data for http (with ssl) */
+static int
+ssl_http_read_more(struct comm_point* c)
+{
+#ifdef HAVE_SSL
+ int r;
+ log_assert(sldns_buffer_remaining(c->buffer) > 0);
+ ERR_clear_error();
+ r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer),
+ (int)sldns_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;
+ }
+ sldns_buffer_skip(c->buffer, (ssize_t)r);
+ return 1;
+#else
+ (void)c;
+ return 0;
+#endif /* HAVE_SSL */
+}
+
+/** read more data for http */
+static int
+http_read_more(int fd, struct comm_point* c)
+{
+ ssize_t r;
+ log_assert(sldns_buffer_remaining(c->buffer) > 0);
+ r = recv(fd, (void*)sldns_buffer_current(c->buffer),
+ sldns_buffer_remaining(c->buffer), 0);
+ if(r == 0) {
+ return 0;
+ } else if(r == -1) {
+#ifndef USE_WINSOCK
+ if(errno == EINTR || errno == EAGAIN)
+ return 1;
+ log_err_addr("read (in http r)", strerror(errno),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#else /* USE_WINSOCK */
+ if(WSAGetLastError() == WSAECONNRESET)
+ return 0;
+ if(WSAGetLastError() == WSAEINPROGRESS)
+ return 1;
+ if(WSAGetLastError() == WSAEWOULDBLOCK) {
+ ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
+ return 1;
+ }
+ log_err_addr("read (in http r)",
+ wsa_strerror(WSAGetLastError()),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#endif
+ return 0;
+ }
+ sldns_buffer_skip(c->buffer, r);
+ return 1;
+}
+
+/** return true if http header has been read (one line complete) */
+static int
+http_header_done(sldns_buffer* buf)
+{
+ size_t i;
+ for(i=sldns_buffer_position(buf); i<sldns_buffer_limit(buf); i++) {
+ /* there was a \r before the \n, but we ignore that */
+ if((char)sldns_buffer_read_u8_at(buf, i) == '\n')
+ return 1;
+ }
+ return 0;
+}
+
+/** return character string into buffer for header line, moves buffer
+ * past that line and puts zero terminator into linefeed-newline */
+static char*
+http_header_line(sldns_buffer* buf)
+{
+ char* result = (char*)sldns_buffer_current(buf);
+ size_t i;
+ for(i=sldns_buffer_position(buf); i<sldns_buffer_limit(buf); i++) {
+ /* terminate the string on the \r */
+ if((char)sldns_buffer_read_u8_at(buf, i) == '\r')
+ sldns_buffer_write_u8_at(buf, i, 0);
+ /* terminate on the \n and skip past the it and done */
+ if((char)sldns_buffer_read_u8_at(buf, i) == '\n') {
+ sldns_buffer_write_u8_at(buf, i, 0);
+ sldns_buffer_set_position(buf, i+1);
+ return result;
+ }
+ }
+ return NULL;
+}
+
+/** move unread buffer to start and clear rest for putting the rest into it */
+static void
+http_moveover_buffer(sldns_buffer* buf)
+{
+ size_t pos = sldns_buffer_position(buf);
+ size_t len = sldns_buffer_remaining(buf);
+ sldns_buffer_clear(buf);
+ memmove(sldns_buffer_begin(buf), sldns_buffer_at(buf, pos), len);
+ sldns_buffer_set_position(buf, len);
+}
+
+/** a http header is complete, process it */
+static int
+http_process_initial_header(struct comm_point* c)
+{
+ char* line = http_header_line(c->buffer);
+ if(!line) return 1;
+ verbose(VERB_ALGO, "http header: %s", line);
+ if(strncasecmp(line, "HTTP/1.1 ", 9) == 0) {
+ /* check returncode */
+ if(line[9] != '2') {
+ verbose(VERB_ALGO, "http bad status %s", line+9);
+ return 0;
+ }
+ } else if(strncasecmp(line, "Content-Length: ", 16) == 0) {
+ if(!c->http_is_chunked)
+ c->tcp_byte_count = (size_t)atoi(line+16);
+ } else if(strncasecmp(line, "Transfer-Encoding: chunked", 19+7) == 0) {
+ c->tcp_byte_count = 0;
+ c->http_is_chunked = 1;
+ } else if(line[0] == 0) {
+ /* end of initial headers */
+ c->http_in_headers = 0;
+ if(c->http_is_chunked)
+ c->http_in_chunk_headers = 1;
+ /* remove header text from front of buffer
+ * the buffer is going to be used to return the data segment
+ * itself and we don't want the header to get returned
+ * prepended with it */
+ http_moveover_buffer(c->buffer);
+ sldns_buffer_flip(c->buffer);
+ return 1;
+ }
+ /* ignore other headers */
+ return 1;
+}
+
+/** a chunk header is complete, process it, return 0=fail, 1=continue next
+ * header line, 2=done with chunked transfer*/
+static int
+http_process_chunk_header(struct comm_point* c)
+{
+ char* line = http_header_line(c->buffer);
+ if(!line) return 1;
+ if(c->http_in_chunk_headers == 3) {
+ verbose(VERB_ALGO, "http chunk trailer: %s", line);
+ /* are we done ? */
+ if(line[0] == 0 && c->tcp_byte_count == 0) {
+ /* callback of http reader when NETEVENT_DONE,
+ * end of data, with no data in buffer */
+ sldns_buffer_set_position(c->buffer, 0);
+ sldns_buffer_set_limit(c->buffer, 0);
+ fptr_ok(fptr_whitelist_comm_point(c->callback));
+ (void)(*c->callback)(c, c->cb_arg, NETEVENT_DONE, NULL);
+ /* return that we are done */
+ return 2;
+ }
+ if(line[0] == 0) {
+ /* continue with header of the next chunk */
+ c->http_in_chunk_headers = 1;
+ /* remove header text from front of buffer */
+ http_moveover_buffer(c->buffer);
+ sldns_buffer_flip(c->buffer);
+ return 1;
+ }
+ /* ignore further trail headers */
+ return 1;
+ }
+ verbose(VERB_ALGO, "http chunk header: %s", line);
+ if(c->http_in_chunk_headers == 1) {
+ /* read chunked start line */
+ char* end = NULL;
+ c->tcp_byte_count = (size_t)strtol(line, &end, 16);
+ if(end == line)
+ return 0;
+ c->http_in_chunk_headers = 0;
+ /* remove header text from front of buffer */
+ http_moveover_buffer(c->buffer);
+ sldns_buffer_flip(c->buffer);
+ if(c->tcp_byte_count == 0) {
+ /* done with chunks, process chunk_trailer lines */
+ c->http_in_chunk_headers = 3;
+ }
+ return 1;
+ }
+ /* ignore other headers */
+ return 1;
+}
+
+/** handle nonchunked data segment */
+static int
+http_nonchunk_segment(struct comm_point* c)
+{
+ /* c->buffer at position..limit has new data we read in.
+ * the buffer itself is full of nonchunked data.
+ * we are looking to read tcp_byte_count more data
+ * and then the transfer is done. */
+ size_t remainbufferlen;
+ size_t got_now = sldns_buffer_limit(c->buffer) - c->http_stored;
+ if(c->tcp_byte_count <= got_now) {
+ /* done, this is the last data fragment */
+ c->http_stored = 0;
+ sldns_buffer_set_position(c->buffer, 0);
+ fptr_ok(fptr_whitelist_comm_point(c->callback));
+ (void)(*c->callback)(c, c->cb_arg, NETEVENT_DONE, NULL);
+ return 1;
+ }
+ c->tcp_byte_count -= got_now;
+ /* if we have the buffer space,
+ * read more data collected into the buffer */
+ remainbufferlen = sldns_buffer_capacity(c->buffer) -
+ sldns_buffer_limit(c->buffer);
+ if(remainbufferlen >= c->tcp_byte_count ||
+ remainbufferlen >= 2048) {
+ size_t total = sldns_buffer_limit(c->buffer);
+ sldns_buffer_clear(c->buffer);
+ sldns_buffer_set_position(c->buffer, total);
+ c->http_stored = total;
+ /* return and wait to read more */
+ return 1;
+ }
+ /* call callback with this data amount, then
+ * wait for more */
+ c->http_stored = 0;
+ sldns_buffer_set_position(c->buffer, 0);
+ fptr_ok(fptr_whitelist_comm_point(c->callback));
+ (void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, NULL);
+ /* c->callback has to buffer_clear(c->buffer). */
+ /* return and wait to read more */
+ return 1;
+}
+
+/** handle nonchunked data segment, return 0=fail, 1=wait, 2=process more */
+static int
+http_chunked_segment(struct comm_point* c)
+{
+ /* the c->buffer has from position..limit new data we read. */
+ /* the current chunk has length tcp_byte_count.
+ * once we read that read more chunk headers.
+ */
+ size_t remainbufferlen;
+ size_t got_now = sldns_buffer_limit(c->buffer) - c->http_stored;
+ if(c->tcp_byte_count <= got_now) {
+ /* the chunk has completed (with perhaps some extra data
+ * from next chunk header and next chunk) */
+ /* save too much info into temp buffer */
+ size_t fraglen;
+ struct comm_reply repinfo;
+ c->http_stored = 0;
+ sldns_buffer_skip(c->buffer, (ssize_t)c->tcp_byte_count);
+ sldns_buffer_clear(c->http_temp);
+ sldns_buffer_write(c->http_temp,
+ sldns_buffer_current(c->buffer),
+ sldns_buffer_remaining(c->buffer));
+ sldns_buffer_flip(c->http_temp);
+
+ /* callback with this fragment */
+ fraglen = sldns_buffer_position(c->buffer);
+ sldns_buffer_set_position(c->buffer, 0);
+ sldns_buffer_set_limit(c->buffer, fraglen);
+ repinfo = c->repinfo;
+ fptr_ok(fptr_whitelist_comm_point(c->callback));
+ (void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &repinfo);
+ /* c->callback has to buffer_clear(). */
+
+ /* is commpoint deleted? */
+ if(!repinfo.c) {
+ return 1;
+ }
+ /* copy waiting info */
+ sldns_buffer_clear(c->buffer);
+ sldns_buffer_write(c->buffer,
+ sldns_buffer_begin(c->http_temp),
+ sldns_buffer_remaining(c->http_temp));
+ sldns_buffer_flip(c->buffer);
+ /* process end of chunk trailer header lines, until
+ * an empty line */
+ c->http_in_chunk_headers = 3;
+ /* process more data in buffer (if any) */
+ return 2;
+ }
+ c->tcp_byte_count -= got_now;
+
+ /* if we have the buffer space,
+ * read more data collected into the buffer */
+ remainbufferlen = sldns_buffer_capacity(c->buffer) -
+ sldns_buffer_limit(c->buffer);
+ if(remainbufferlen >= c->tcp_byte_count ||
+ remainbufferlen >= 2048) {
+ size_t total = sldns_buffer_limit(c->buffer);
+ sldns_buffer_clear(c->buffer);
+ sldns_buffer_set_position(c->buffer, total);
+ c->http_stored = total;
+ /* return and wait to read more */
+ return 1;
+ }
+
+ /* callback of http reader for a new part of the data */
+ c->http_stored = 0;
+ sldns_buffer_set_position(c->buffer, 0);
+ fptr_ok(fptr_whitelist_comm_point(c->callback));
+ (void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, NULL);
+ /* c->callback has to buffer_clear(c->buffer). */
+ /* return and wait to read more */
+ return 1;
+}
+
+/**
+ * Handle http reading callback.
+ * @param fd: file descriptor of socket.
+ * @param c: comm point to read from into buffer.
+ * @return: 0 on error
+ */
+static int
+comm_point_http_handle_read(int fd, struct comm_point* c)
+{
+ log_assert(c->type == comm_http);
+ log_assert(fd != -1);
+
+ /* if we are in ssl handshake, handle SSL handshake */
+#ifdef HAVE_SSL
+ if(c->ssl && 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;
+ }
+#endif /* HAVE_SSL */
+
+ if(!c->tcp_is_reading)
+ return 1;
+ /* read more data */
+ if(c->ssl) {
+ if(!ssl_http_read_more(c))
+ return 0;
+ } else {
+ if(!http_read_more(fd, c))
+ return 0;
+ }
+
+ sldns_buffer_flip(c->buffer);
+ while(sldns_buffer_remaining(c->buffer) > 0) {
+ /* if we are reading headers, read more headers */
+ if(c->http_in_headers || c->http_in_chunk_headers) {
+ /* if header is done, process the header */
+ if(!http_header_done(c->buffer)) {
+ /* copy remaining data to front of buffer
+ * and set rest for writing into it */
+ http_moveover_buffer(c->buffer);
+ /* return and wait to read more */
+ return 1;
+ }
+ if(!c->http_in_chunk_headers) {
+ /* process initial headers */
+ if(!http_process_initial_header(c))
+ return 0;
+ } else {
+ /* process chunk headers */
+ int r = http_process_chunk_header(c);
+ if(r == 0) return 0;
+ if(r == 2) return 1; /* done */
+ /* r == 1, continue */
+ }
+ /* see if we have more to process */
+ continue;
+ }
+
+ if(!c->http_is_chunked) {
+ /* if we are reading nonchunks, process that*/
+ return http_nonchunk_segment(c);
+ } else {
+ /* if we are reading chunks, read the chunk */
+ int r = http_chunked_segment(c);
+ if(r == 0) return 0;
+ if(r == 1) return 1;
+ continue;
+ }
+ }
+ /* broke out of the loop; could not process header instead need
+ * to read more */
+ /* moveover any remaining data and read more data */
+ http_moveover_buffer(c->buffer);
+ /* return and wait to read more */
+ return 1;
+}
+
+/** check pending connect for http */
+static int
+http_check_connect(int fd, struct comm_point* c)
+{
+ /* check for pending error from nonblocking connect */
+ /* from Stevens, unix network programming, vol1, 3rd ed, p450*/
+ int error = 0;
+ socklen_t len = (socklen_t)sizeof(error);
+ if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
+ &len) < 0){
+#ifndef USE_WINSOCK
+ error = errno; /* on solaris errno is error */
+#else /* USE_WINSOCK */
+ error = WSAGetLastError();
+#endif
+ }
+#ifndef USE_WINSOCK
+#if defined(EINPROGRESS) && defined(EWOULDBLOCK)
+ if(error == EINPROGRESS || error == EWOULDBLOCK)
+ return 1; /* try again later */
+ else
+#endif
+ if(error != 0 && verbosity < 2)
+ return 0; /* silence lots of chatter in the logs */
+ else if(error != 0) {
+ log_err_addr("http connect", strerror(error),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#else /* USE_WINSOCK */
+ /* examine error */
+ if(error == WSAEINPROGRESS)
+ return 1;
+ else if(error == WSAEWOULDBLOCK) {
+ ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
+ return 1;
+ } else if(error != 0 && verbosity < 2)
+ return 0;
+ else if(error != 0) {
+ log_err_addr("http connect", wsa_strerror(error),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#endif /* USE_WINSOCK */
+ return 0;
+ }
+ /* keep on processing this socket */
+ return 2;
+}
+
+/** write more data for http (with ssl) */
+static int
+ssl_http_write_more(struct comm_point* c)
+{
+#ifdef HAVE_SSL
+ int r;
+ log_assert(sldns_buffer_remaining(c->buffer) > 0);
+ ERR_clear_error();
+ r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer),
+ (int)sldns_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;
+ }
+ sldns_buffer_skip(c->buffer, (ssize_t)r);
+ return 1;
+#else
+ (void)c;
+ return 0;
+#endif /* HAVE_SSL */
+}
+
+/** write more data for http */
+static int
+http_write_more(int fd, struct comm_point* c)
+{
+ ssize_t r;
+ log_assert(sldns_buffer_remaining(c->buffer) > 0);
+ r = send(fd, (void*)sldns_buffer_current(c->buffer),
+ sldns_buffer_remaining(c->buffer), 0);
+ if(r == -1) {
+#ifndef USE_WINSOCK
+ if(errno == EINTR || errno == EAGAIN)
+ return 1;
+ log_err_addr("http send r", strerror(errno),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#else
+ if(WSAGetLastError() == WSAEINPROGRESS)
+ return 1;
+ if(WSAGetLastError() == WSAEWOULDBLOCK) {
+ ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
+ return 1;
+ }
+ log_err_addr("http send r", wsa_strerror(WSAGetLastError()),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#endif
+ return 0;
+ }
+ sldns_buffer_skip(c->buffer, r);
+ return 1;
+}
+
+/**
+ * Handle http writing callback.
+ * @param fd: file descriptor of socket.
+ * @param c: comm point to write buffer out of.
+ * @return: 0 on error
+ */
+static int
+comm_point_http_handle_write(int fd, struct comm_point* c)
+{
+ log_assert(c->type == comm_http);
+ log_assert(fd != -1);
+
+ /* check pending connect errors, if that fails, we wait for more,
+ * or we can continue to write contents */
+ if(c->tcp_check_nb_connect) {
+ int r = http_check_connect(fd, c);
+ if(r == 0) return 0;
+ if(r == 1) return 1;
+ c->tcp_check_nb_connect = 0;
+ }
+ /* if we are in ssl handshake, handle SSL handshake */
+#ifdef HAVE_SSL
+ if(c->ssl && 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;
+ }
+#endif /* HAVE_SSL */
+ if(c->tcp_is_reading)
+ return 1;
+ /* if we are writing, write more */
+ if(c->ssl) {
+ if(!ssl_http_write_more(c))
+ return 0;
+ } else {
+ if(!http_write_more(fd, c))
+ return 0;
+ }
+
+ /* we write a single buffer contents, that can contain
+ * the http request, and then flip to read the results */
+ /* see if write is done */
+ if(sldns_buffer_remaining(c->buffer) == 0) {
+ sldns_buffer_clear(c->buffer);
+ if(c->tcp_do_toggle_rw)
+ c->tcp_is_reading = 1;
+ c->tcp_byte_count = 0;
+ /* switch from listening(write) to listening(read) */
+ comm_point_stop_listening(c);
+ comm_point_start_listening(c, -1, -1);
+ }
+ return 1;
+}
+
+void
+comm_point_http_handle_callback(int fd, short event, void* arg)
+{
+ struct comm_point* c = (struct comm_point*)arg;
+ log_assert(c->type == comm_http);
+ ub_comm_base_now(c->ev->base);
+
+ if(event&UB_EV_READ) {
+ if(!comm_point_http_handle_read(fd, c)) {
+ reclaim_http_handler(c);
+ if(!c->tcp_do_close) {
+ fptr_ok(fptr_whitelist_comm_point(
+ c->callback));
+ (void)(*c->callback)(c, c->cb_arg,
+ NETEVENT_CLOSED, NULL);
+ }
+ }
+ return;
+ }
+ if(event&UB_EV_WRITE) {
+ if(!comm_point_http_handle_write(fd, c)) {
+ reclaim_http_handler(c);
+ if(!c->tcp_do_close) {
+ fptr_ok(fptr_whitelist_comm_point(
+ c->callback));
+ (void)(*c->callback)(c, c->cb_arg,
+ NETEVENT_CLOSED, NULL);
+ }
+ }
+ return;
+ }
+ if(event&UB_EV_TIMEOUT) {
+ verbose(VERB_QUERY, "http took too long, dropped");
+ reclaim_http_handler(c);
+ if(!c->tcp_do_close) {
+ fptr_ok(fptr_whitelist_comm_point(c->callback));
+ (void)(*c->callback)(c, c->cb_arg,
+ NETEVENT_TIMEOUT, NULL);
+ }
+ return;
+ }
+ log_err("Ignored event %d for httphdl.", event);
+}
+
void comm_point_local_handle_callback(int fd, short event, void* arg)
{
struct comm_point* c = (struct comm_point*)arg;
@@ -1958,6 +2671,75 @@ comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
}
struct comm_point*
+comm_point_create_http_out(struct comm_base *base, size_t bufsize,
+ comm_point_callback_type* callback, void* callback_arg,
+ sldns_buffer* temp)
+{
+ struct comm_point* c = (struct comm_point*)calloc(1,
+ sizeof(struct comm_point));
+ short evbits;
+ if(!c)
+ return NULL;
+ c->ev = (struct internal_event*)calloc(1,
+ sizeof(struct internal_event));
+ if(!c->ev) {
+ free(c);
+ return NULL;
+ }
+ c->ev->base = base;
+ c->fd = -1;
+ c->buffer = sldns_buffer_new(bufsize);
+ if(!c->buffer) {
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+ c->timeout = NULL;
+ c->tcp_is_reading = 0;
+ c->tcp_byte_count = 0;
+ c->tcp_parent = NULL;
+ c->max_tcp_count = 0;
+ c->cur_tcp_count = 0;
+ c->tcp_handlers = NULL;
+ c->tcp_free = NULL;
+ c->type = comm_http;
+ c->tcp_do_close = 0;
+ c->do_not_close = 0;
+ c->tcp_do_toggle_rw = 1;
+ c->tcp_check_nb_connect = 1;
+ c->http_in_headers = 1;
+ c->http_in_chunk_headers = 0;
+ c->http_is_chunked = 0;
+ c->http_temp = temp;
+#ifdef USE_MSG_FASTOPEN
+ c->tcp_do_fastopen = 1;
+#endif
+#ifdef USE_DNSCRYPT
+ c->dnscrypt = 0;
+ c->dnscrypt_buffer = c->buffer;
+#endif
+ c->repinfo.c = c;
+ c->callback = callback;
+ c->cb_arg = callback_arg;
+ evbits = UB_EV_PERSIST | UB_EV_WRITE;
+ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
+ comm_point_http_handle_callback, c);
+ if(c->ev->ev == NULL)
+ {
+ log_err("could not baseset tcpout event");
+#ifdef HAVE_SSL
+ SSL_free(c->ssl);
+#endif
+ sldns_buffer_free(c->buffer);
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+
+ return c;
+}
+
+struct comm_point*
comm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
comm_point_callback_type* callback, void* callback_arg)
{
@@ -2110,7 +2892,7 @@ comm_point_delete(struct comm_point* c)
{
if(!c)
return;
- if(c->type == comm_tcp && c->ssl) {
+ if((c->type == comm_tcp || c->type == comm_http) && c->ssl) {
#ifdef HAVE_SSL
SSL_shutdown(c->ssl);
SSL_free(c->ssl);
@@ -2124,7 +2906,7 @@ comm_point_delete(struct comm_point* c)
free(c->tcp_handlers);
}
free(c->timeout);
- if(c->type == comm_tcp || c->type == comm_local) {
+ if(c->type == comm_tcp || c->type == comm_local || c->type == comm_http) {
sldns_buffer_free(c->buffer);
#ifdef USE_DNSCRYPT
if(c->dnscrypt && c->dnscrypt_buffer != c->buffer) {
@@ -2221,7 +3003,7 @@ comm_point_start_listening(struct comm_point* c, int newfd, int msec)
c->timeout->tv_usec = (msec%1000)*1000;
#endif /* S_SPLINT_S */
}
- if(c->type == comm_tcp) {
+ if(c->type == comm_tcp || c->type == comm_http) {
ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
if(c->tcp_is_reading)
ub_event_add_bits(c->ev->ev, UB_EV_READ);
diff --git a/contrib/unbound/util/netevent.h b/contrib/unbound/util/netevent.h
index 54740266d0a4..6819f57f8d9e 100644
--- a/contrib/unbound/util/netevent.h
+++ b/contrib/unbound/util/netevent.h
@@ -84,6 +84,8 @@ typedef int comm_point_callback_type(struct comm_point*, void*, int,
#define NETEVENT_TIMEOUT -2
/** to pass fallback from capsforID to callback function; 0x20 failed */
#define NETEVENT_CAPSFAIL -3
+/** to pass done transfer to callback function; http file is complete */
+#define NETEVENT_DONE -4
/** timeout to slow accept calls when not possible, in msec. */
#define NETEVENT_SLOW_ACCEPT_TIME 2000
@@ -201,6 +203,19 @@ struct comm_point {
comm_ssl_shake_hs_write
} ssl_shake_state;
+ /* -------- HTTP ------- */
+ /** Currently reading in http headers */
+ int http_in_headers;
+ /** Currently reading in chunk headers, 0=not, 1=firstline, 2=unused
+ * (more lines), 3=trailer headers after chunk */
+ int http_in_chunk_headers;
+ /** chunked transfer */
+ int http_is_chunked;
+ /** http temp buffer (shared buffer for temporary work) */
+ struct sldns_buffer* http_temp;
+ /** http stored content in buffer */
+ size_t http_stored;
+
/* -------- dnstap ------- */
/** the dnstap environment */
struct dt_env* dtenv;
@@ -213,6 +228,8 @@ struct comm_point {
comm_tcp_accept,
/** TCP handler socket - handle byteperbyte readwrite. */
comm_tcp,
+ /** HTTP handler socket */
+ comm_http,
/** AF_UNIX socket - for internal commands. */
comm_local,
/** raw - not DNS format - for pipe readers and writers */
@@ -450,6 +467,20 @@ struct comm_point* comm_point_create_tcp_out(struct comm_base* base,
size_t bufsize, comm_point_callback_type* callback, void* callback_arg);
/**
+ * Create an outgoing HTTP commpoint. No file descriptor is opened, left at -1.
+ * @param base: in which base to alloc the commpoint.
+ * @param bufsize: size of buffer to create for handlers.
+ * @param callback: callback function pointer for the handler.
+ * @param callback_arg: will be passed to your callback function.
+ * @param temp: sldns buffer, shared between other http_out commpoints, for
+ * temporary data when performing callbacks.
+ * @return: the commpoint or NULL on error.
+ */
+struct comm_point* comm_point_create_http_out(struct comm_base* base,
+ size_t bufsize, comm_point_callback_type* callback,
+ void* callback_arg, struct sldns_buffer* temp);
+
+/**
* Create commpoint to listen to a local domain file descriptor.
* @param base: in which base to alloc the commpoint.
* @param fd: file descriptor of open AF_UNIX socket set to listen nonblocking.
@@ -667,6 +698,16 @@ void comm_point_tcp_handle_callback(int fd, short event, void* arg);
/**
* This routine is published for checks and tests, and is only used internally.
+ * handle libevent callback for tcp data comm point
+ * @param fd: file descriptor.
+ * @param event: event bits from libevent:
+ * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
+ * @param arg: the comm_point structure.
+ */
+void comm_point_http_handle_callback(int fd, short event, void* arg);
+
+/**
+ * This routine is published for checks and tests, and is only used internally.
* handle libevent callback for timer comm.
* @param fd: file descriptor (always -1).
* @param event: event bits from libevent:
diff --git a/contrib/unbound/util/ub_event.c b/contrib/unbound/util/ub_event.c
index 3b92be1a3025..fba2f2488296 100644
--- a/contrib/unbound/util/ub_event.c
+++ b/contrib/unbound/util/ub_event.c
@@ -427,7 +427,7 @@ ub_winsock_tcp_wouldblock(struct ub_event* ev, int eventbits)
void ub_comm_base_now(struct comm_base* cb)
{
- #ifdef USE_MINI_EVENT
+#ifdef USE_MINI_EVENT
/** minievent updates the time when it blocks. */
(void)cb; /* nothing to do */
#else /* !USE_MINI_EVENT */