summaryrefslogtreecommitdiff
path: root/usr.sbin/unbound/util
diff options
context:
space:
mode:
authorStuart Henderson <sthen@cvs.openbsd.org>2017-08-12 11:22:47 +0000
committerStuart Henderson <sthen@cvs.openbsd.org>2017-08-12 11:22:47 +0000
commit72a92e1acfb2c25b147862010c351f1c669d159f (patch)
treed1d5054f9a4e7919b56c9fcb4bf8173967a9a31f /usr.sbin/unbound/util
parenta02d7aa0c1d30c13f6b9b9736d6a9462d8ac2c31 (diff)
update to unbound 1.6.4, ok florian@
Diffstat (limited to 'usr.sbin/unbound/util')
-rw-r--r--usr.sbin/unbound/util/config_file.c144
-rw-r--r--usr.sbin/unbound/util/config_file.h66
-rw-r--r--usr.sbin/unbound/util/configlexer.lex26
-rw-r--r--usr.sbin/unbound/util/configparser.y384
-rw-r--r--usr.sbin/unbound/util/data/msgencode.c16
-rw-r--r--usr.sbin/unbound/util/data/msgparse.c2
-rw-r--r--usr.sbin/unbound/util/data/msgreply.c58
-rw-r--r--usr.sbin/unbound/util/data/msgreply.h42
-rw-r--r--usr.sbin/unbound/util/data/packed_rrset.h5
-rw-r--r--usr.sbin/unbound/util/fptr_wlist.c100
-rw-r--r--usr.sbin/unbound/util/fptr_wlist.h25
-rw-r--r--usr.sbin/unbound/util/iana_ports.inc10
-rw-r--r--usr.sbin/unbound/util/log.c8
-rw-r--r--usr.sbin/unbound/util/module.c155
-rw-r--r--usr.sbin/unbound/util/module.h215
-rw-r--r--usr.sbin/unbound/util/netevent.c151
-rw-r--r--usr.sbin/unbound/util/netevent.h19
-rw-r--r--usr.sbin/unbound/util/shm_side/shm_main.c285
-rw-r--r--usr.sbin/unbound/util/shm_side/shm_main.h68
-rw-r--r--usr.sbin/unbound/util/storage/lruhash.c86
-rw-r--r--usr.sbin/unbound/util/storage/lruhash.h32
-rw-r--r--usr.sbin/unbound/util/timehist.c29
-rw-r--r--usr.sbin/unbound/util/timehist.h24
23 files changed, 1637 insertions, 313 deletions
diff --git a/usr.sbin/unbound/util/config_file.c b/usr.sbin/unbound/util/config_file.c
index 1eba4af860c..d0fdb2daaa2 100644
--- a/usr.sbin/unbound/util/config_file.c
+++ b/usr.sbin/unbound/util/config_file.c
@@ -62,6 +62,9 @@
#ifdef HAVE_GLOB_H
# include <glob.h>
#endif
+#ifdef CLIENT_SUBNET
+#include "edns-subnet/edns-subnet.h"
+#endif
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
@@ -173,6 +176,14 @@ config_create(void)
cfg->out_ifs = NULL;
cfg->stubs = NULL;
cfg->forwards = NULL;
+#ifdef CLIENT_SUBNET
+ cfg->client_subnet = NULL;
+ cfg->client_subnet_zone = NULL;
+ cfg->client_subnet_opcode = LDNS_EDNS_CLIENT_SUBNET;
+ cfg->client_subnet_always_forward = 0;
+ cfg->max_client_subnet_ipv4 = 24;
+ cfg->max_client_subnet_ipv6 = 56;
+#endif
cfg->views = NULL;
cfg->acls = NULL;
cfg->harden_short_bufsize = 0;
@@ -189,12 +200,14 @@ config_create(void)
cfg->unwanted_threshold = 0;
cfg->hide_identity = 0;
cfg->hide_version = 0;
+ cfg->hide_trustanchor = 0;
cfg->identity = NULL;
cfg->version = NULL;
cfg->auto_trust_anchor_file_list = NULL;
cfg->trust_anchor_file_list = NULL;
cfg->trust_anchor_list = NULL;
cfg->trusted_keys_file_list = NULL;
+ cfg->trust_anchor_signaling = 0;
cfg->dlv_anchor_file = NULL;
cfg->dlv_anchor_list = NULL;
cfg->domain_insecure = NULL;
@@ -216,6 +229,7 @@ config_create(void)
cfg->neg_cache_size = 1 * 1024 * 1024;
cfg->local_zones = NULL;
cfg->local_zones_nodefault = NULL;
+ cfg->local_zones_disable_default = 0;
cfg->local_data = NULL;
cfg->local_zone_overrides = NULL;
cfg->unblock_lan_zones = 0;
@@ -237,7 +251,11 @@ config_create(void)
if(!(cfg->control_cert_file = strdup(RUN_DIR"/unbound_control.pem")))
goto error_exit;
+#ifdef CLIENT_SUBNET
+ if(!(cfg->module_conf = strdup("subnetcache validator iterator"))) goto error_exit;
+#else
if(!(cfg->module_conf = strdup("validator iterator"))) goto error_exit;
+#endif
if(!(cfg->val_nsec3_key_iterations =
strdup("1024 150 2048 500 4096 2500"))) goto error_exit;
#if defined(DNSTAP_SOCKET_PATH)
@@ -257,6 +275,21 @@ config_create(void)
cfg->ratelimit_factor = 10;
cfg->qname_minimisation = 0;
cfg->qname_minimisation_strict = 0;
+ cfg->shm_enable = 0;
+ cfg->shm_key = 11777;
+ cfg->dnscrypt = 0;
+ cfg->dnscrypt_port = 0;
+ cfg->dnscrypt_provider = NULL;
+ cfg->dnscrypt_provider_cert = NULL;
+ cfg->dnscrypt_secret_key = NULL;
+#ifdef USE_IPSECMOD
+ cfg->ipsecmod_enabled = 1;
+ cfg->ipsecmod_ignore_bogus = 0;
+ cfg->ipsecmod_hook = NULL;
+ cfg->ipsecmod_max_ttl = 3600;
+ cfg->ipsecmod_whitelist = NULL;
+ cfg->ipsecmod_strict = 0;
+#endif
return cfg;
error_exit:
config_delete(cfg);
@@ -380,6 +413,8 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_STR("log-identity:", log_identity)
else S_YNO("extended-statistics:", stat_extended)
else S_YNO("statistics-cumulative:", stat_cumulative)
+ else S_YNO("shm-enable:", shm_enable)
+ else S_NUMBER_OR_ZERO("shm-key:", shm_key)
else S_YNO("do-ip4:", do_ip4)
else S_YNO("do-ip6:", do_ip6)
else S_YNO("do-udp:", do_udp)
@@ -433,6 +468,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_STR("pidfile:", pidfile)
else S_YNO("hide-identity:", hide_identity)
else S_YNO("hide-version:", hide_version)
+ else S_YNO("hide-trustanchor:", hide_trustanchor)
else S_STR("identity:", identity)
else S_STR("version:", version)
else S_STRLIST("root-hints:", root_hints)
@@ -455,6 +491,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_STRLIST("trust-anchor-file:", trust_anchor_file_list)
else S_STRLIST("trust-anchor:", trust_anchor_list)
else S_STRLIST("trusted-keys-file:", trusted_keys_file_list)
+ else S_YNO("trust-anchor-signaling:", trust_anchor_signaling)
else S_STR("dlv-anchor-file:", dlv_anchor_file)
else S_STRLIST("dlv-anchor:", dlv_anchor_list)
else S_STRLIST("domain-insecure:", domain_insecure)
@@ -492,6 +529,39 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_STR("module-config:", module_conf)
else S_STR("python-script:", python_script)
else S_YNO("disable-dnssec-lame-check:", disable_dnssec_lame_check)
+#ifdef CLIENT_SUBNET
+ /* Can't set max subnet prefix here, since that value is used when
+ * generating the address tree. */
+ /* No client-subnet-always-forward here, module registration depends on
+ * this option. */
+#endif
+#ifdef USE_DNSTAP
+ else S_YNO("dnstap-enable:", dnstap)
+ else S_STR("dnstap-socket-path:", dnstap_socket_path)
+ else S_YNO("dnstap-send-identity:", dnstap_send_identity)
+ else S_YNO("dnstap-send-version:", dnstap_send_version)
+ else S_STR("dnstap-identity:", dnstap_identity)
+ else S_STR("dnstap-version:", dnstap_version)
+ else S_YNO("dnstap-log-resolver-query-messages:",
+ dnstap_log_resolver_query_messages)
+ else S_YNO("dnstap-log-resolver-response-messages:",
+ dnstap_log_resolver_response_messages)
+ else S_YNO("dnstap-log-client-query-messages:",
+ dnstap_log_client_query_messages)
+ else S_YNO("dnstap-log-client-response-messages:",
+ dnstap_log_client_response_messages)
+ else S_YNO("dnstap-log-forwarder-query-messages:",
+ dnstap_log_forwarder_query_messages)
+ else S_YNO("dnstap-log-forwarder-response-messages:",
+ dnstap_log_forwarder_response_messages)
+#endif
+#ifdef USE_DNSCRYPT
+ 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)
+#endif
else if(strcmp(opt, "ip-ratelimit:") == 0) {
IS_NUMBER_OR_ZERO; cfg->ip_ratelimit = atoi(val);
infra_ip_ratelimit=cfg->ip_ratelimit;
@@ -508,6 +578,13 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_NUMBER_OR_ZERO("ratelimit-factor:", ratelimit_factor)
else S_YNO("qname-minimisation:", qname_minimisation)
else S_YNO("qname-minimisation-strict:", qname_minimisation_strict)
+#ifdef USE_IPSECMOD
+ else S_YNO("ipsecmod-enabled:", ipsecmod_enabled)
+ else S_YNO("ipsecmod-ignore-bogus:", ipsecmod_ignore_bogus)
+ else if(strcmp(opt, "ipsecmod-max-ttl:") == 0)
+ { IS_NUMBER_OR_ZERO; cfg->ipsecmod_max_ttl = atoi(val); }
+ else S_YNO("ipsecmod-strict:", ipsecmod_strict)
+#endif
else if(strcmp(opt, "define-tag:") ==0) {
return config_add_tag(cfg, val);
/* val_sig_skew_min and max are copied into val_env during init,
@@ -529,13 +606,16 @@ int config_set_option(struct config_file* cfg, const char* opt,
cfg->out_ifs = oi;
} else {
/* unknown or unsupported (from the set_option interface):
- * interface, outgoing-interface, access-control,
+ * 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,
* name, forward-addr, forward-host,
* ratelimit-for-domain, ratelimit-below-domain,
- * local-zone-tag, access-control-view */
+ * local-zone-tag, access-control-view,
+ * send-client-subnet, client-subnet-always-forward,
+ * max-client-subnet-ipv4, max-client-subnet-ipv6, ipsecmod_hook,
+ * ipsecmod_whitelist. */
return 0;
}
return 1;
@@ -697,6 +777,8 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_DEC(opt, "statistics-interval", stat_interval)
else O_YNO(opt, "statistics-cumulative", stat_cumulative)
else O_YNO(opt, "extended-statistics", stat_extended)
+ else O_YNO(opt, "shm-enable", shm_enable)
+ else O_DEC(opt, "shm-key", shm_key)
else O_YNO(opt, "use-syslog", use_syslog)
else O_STR(opt, "log-identity", log_identity)
else O_YNO(opt, "log-time-ascii", log_time_ascii)
@@ -753,6 +835,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_STR(opt, "pidfile", pidfile)
else O_YNO(opt, "hide-identity", hide_identity)
else O_YNO(opt, "hide-version", hide_version)
+ else O_YNO(opt, "hide-trustanchor", hide_trustanchor)
else O_STR(opt, "identity", identity)
else O_STR(opt, "version", version)
else O_STR(opt, "target-fetch-policy", target_fetch_policy)
@@ -798,12 +881,48 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_LST(opt, "trust-anchor-file", trust_anchor_file_list)
else O_LST(opt, "trust-anchor", trust_anchor_list)
else O_LST(opt, "trusted-keys-file", trusted_keys_file_list)
+ else O_YNO(opt, "trust-anchor-signaling", trust_anchor_signaling)
else O_LST(opt, "dlv-anchor", dlv_anchor_list)
else O_LST(opt, "control-interface", control_ifs)
else O_LST(opt, "domain-insecure", domain_insecure)
else O_UNS(opt, "val-override-date", val_date_override)
else O_YNO(opt, "minimal-responses", minimal_responses)
else O_YNO(opt, "rrset-roundrobin", rrset_roundrobin)
+#ifdef CLIENT_SUBNET
+ else O_LST(opt, "send-client-subnet", client_subnet)
+ else O_LST(opt, "client-subnet-zone", client_subnet_zone)
+ else O_DEC(opt, "max-client-subnet-ipv4", max_client_subnet_ipv4)
+ else O_DEC(opt, "max-client-subnet-ipv6", max_client_subnet_ipv6)
+ else O_YNO(opt, "client-subnet-always-forward:",
+ client_subnet_always_forward)
+#endif
+#ifdef USE_DNSTAP
+ else O_YNO(opt, "dnstap-enable", dnstap)
+ else O_STR(opt, "dnstap-socket-path", dnstap_socket_path)
+ else O_YNO(opt, "dnstap-send-identity", dnstap_send_identity)
+ else O_YNO(opt, "dnstap-send-version", dnstap_send_version)
+ else O_STR(opt, "dnstap-identity", dnstap_identity)
+ else O_STR(opt, "dnstap-version", dnstap_version)
+ else O_YNO(opt, "dnstap-log-resolver-query-messages",
+ dnstap_log_resolver_query_messages)
+ else O_YNO(opt, "dnstap-log-resolver-response-messages",
+ dnstap_log_resolver_response_messages)
+ else O_YNO(opt, "dnstap-log-client-query-messages",
+ dnstap_log_client_query_messages)
+ else O_YNO(opt, "dnstap-log-client-response-messages",
+ dnstap_log_client_response_messages)
+ else O_YNO(opt, "dnstap-log-forwarder-query-messages",
+ dnstap_log_forwarder_query_messages)
+ else O_YNO(opt, "dnstap-log-forwarder-response-messages",
+ dnstap_log_forwarder_response_messages)
+#endif
+#ifdef USE_DNSCRYPT
+ else O_YNO(opt, "dnscrypt-enable", dnscrypt)
+ 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-secret-key", dnscrypt_secret_key)
+#endif
else O_YNO(opt, "unblock-lan-zones", unblock_lan_zones)
else O_YNO(opt, "insecure-lan-zones", insecure_lan_zones)
else O_DEC(opt, "max-udp-size", max_udp_size)
@@ -826,10 +945,19 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_IFC(opt, "define-tag", num_tags, tagname)
else O_LTG(opt, "local-zone-tag", local_zone_tags)
else O_LTG(opt, "access-control-tag", acl_tags)
+ else O_LTG(opt, "response-ip-tag", respip_tags)
else O_LS3(opt, "local-zone-override", local_zone_overrides)
else O_LS3(opt, "access-control-tag-action", acl_tag_actions)
else O_LS3(opt, "access-control-tag-data", acl_tag_datas)
else O_LS2(opt, "access-control-view", acl_view)
+#ifdef USE_IPSECMOD
+ else O_YNO(opt, "ipsecmod-enabled", ipsecmod_enabled)
+ else O_YNO(opt, "ipsecmod-ignore-bogus", ipsecmod_ignore_bogus)
+ else O_STR(opt, "ipsecmod-hook", ipsecmod_hook)
+ else O_DEC(opt, "ipsecmod-max-ttl", ipsecmod_max_ttl)
+ else O_LST(opt, "ipsecmod-whitelist", ipsecmod_whitelist)
+ else O_YNO(opt, "ipsecmod-strict", ipsecmod_strict)
+#endif
/* not here:
* outgoing-permit, outgoing-avoid - have list of ports
* local-zone - zones and nodefault variables
@@ -934,6 +1062,8 @@ config_read(struct config_file* cfg, const char* filename, const char* chroot)
ub_c_parse();
fclose(in);
+ if(!cfg->dnscrypt) cfg->dnscrypt_port = 0;
+
if(cfg_parser->errors != 0) {
fprintf(stderr, "read %s failed: %d errors in configuration file\n",
fname, cfg_parser->errors);
@@ -1083,10 +1213,15 @@ config_delete(struct config_file* cfg)
config_delviews(cfg->views);
config_delstrlist(cfg->donotqueryaddrs);
config_delstrlist(cfg->root_hints);
+#ifdef CLIENT_SUBNET
+ config_delstrlist(cfg->client_subnet);
+ config_delstrlist(cfg->client_subnet_zone);
+#endif
free(cfg->identity);
free(cfg->version);
free(cfg->module_conf);
free(cfg->outgoing_avail_ports);
+ free(cfg->python_script);
config_delstrlist(cfg->caps_whitelist);
config_delstrlist(cfg->private_address);
config_delstrlist(cfg->private_domain);
@@ -1106,6 +1241,7 @@ config_delete(struct config_file* cfg)
config_del_strarray(cfg->tagname, cfg->num_tags);
config_del_strbytelist(cfg->local_zone_tags);
config_del_strbytelist(cfg->acl_tags);
+ config_del_strbytelist(cfg->respip_tags);
config_deltrplstrlist(cfg->acl_tag_actions);
config_deltrplstrlist(cfg->acl_tag_datas);
config_delstrlist(cfg->control_ifs);
@@ -1119,6 +1255,10 @@ config_delete(struct config_file* cfg)
free(cfg->dnstap_version);
config_deldblstrlist(cfg->ratelimit_for_domain);
config_deldblstrlist(cfg->ratelimit_below_domain);
+#ifdef USE_IPSECMOD
+ free(cfg->ipsecmod_hook);
+ config_delstrlist(cfg->ipsecmod_whitelist);
+#endif
free(cfg);
}
diff --git a/usr.sbin/unbound/util/config_file.h b/usr.sbin/unbound/util/config_file.h
index d52c2f48104..bb7a292050b 100644
--- a/usr.sbin/unbound/util/config_file.h
+++ b/usr.sbin/unbound/util/config_file.h
@@ -172,6 +172,20 @@ struct config_file {
struct config_view* views;
/** list of donotquery addresses, linked list */
struct config_strlist* donotqueryaddrs;
+#ifdef CLIENT_SUBNET
+ /** list of servers we send edns-client-subnet option to and
+ * accept option from, linked list */
+ struct config_strlist* client_subnet;
+ /** list of zones we send edns-client-subnet option for */
+ struct config_strlist* client_subnet_zone;
+ /** opcode assigned by IANA for edns0-client-subnet option */
+ uint16_t client_subnet_opcode;
+ /** Do not check whitelist if incoming query contains an ECS record */
+ int client_subnet_always_forward;
+ /** Subnet length we are willing to give up privacy for */
+ uint8_t max_client_subnet_ipv4;
+ uint8_t max_client_subnet_ipv6;
+#endif
/** list of access control entries, linked list */
struct config_str2list* acls;
/** use default localhost donotqueryaddr entries */
@@ -238,6 +252,8 @@ struct config_file {
int hide_identity;
/** do not report version (version.server, version.bind) */
int hide_version;
+ /** do not report trustanchor (trustanchor.unbound) */
+ int hide_trustanchor;
/** identity, hostname is returned if "". */
char* identity;
/** version, package version returned if "". */
@@ -260,6 +276,8 @@ struct config_file {
struct config_strlist* dlv_anchor_list;
/** insecure domain list */
struct config_strlist* domain_insecure;
+ /** send key tag query */
+ int trust_anchor_signaling;
/** if not 0, this value is the validation date for RRSIGs */
int32_t val_date_override;
@@ -303,6 +321,8 @@ struct config_file {
struct config_str2list* local_zones;
/** local zones nodefault list */
struct config_strlist* local_zones_nodefault;
+ /** do not add any default local zone */
+ int local_zones_disable_default;
/** local data RRs configured */
struct config_strlist* local_data;
/** local zone override types per netblock */
@@ -321,6 +341,12 @@ struct config_file {
struct config_str3list* acl_tag_datas;
/** list of aclname, view*/
struct config_str2list* acl_view;
+ /** list of IP-netblock, tagbitlist */
+ struct config_strbytelist* respip_tags;
+ /** list of response-driven access control entries, linked list */
+ struct config_str2list* respip_actions;
+ /** RRs configured for response-driven access controls */
+ struct config_str2list* respip_data;
/** tag list, array with tagname[i] is malloced string */
char** tagname;
/** number of items in the taglist */
@@ -422,6 +448,38 @@ struct config_file {
/** minimise QNAME in strict mode, minimise according to RFC.
* Do not apply fallback */
int qname_minimisation_strict;
+ /** SHM data - true if shm is enabled */
+ int shm_enable;
+ /** SHM data - key for the shm */
+ int shm_key;
+
+ /** DNSCrypt */
+ /** true to enable dnscrypt */
+ int dnscrypt;
+ /** port on which to provide dnscrypt service */
+ int dnscrypt_port;
+ /** provider name 2.dnscrypt-cert.example.com */
+ char* dnscrypt_provider;
+ /** dnscrypt secret keys 1.key */
+ struct config_strlist* dnscrypt_secret_key;
+ /** dnscrypt provider certs 1.cert */
+ struct config_strlist* dnscrypt_provider_cert;
+
+ /** IPsec module */
+#ifdef USE_IPSECMOD
+ /** false to bypass the IPsec module */
+ int ipsecmod_enabled;
+ /** whitelisted domains for ipsecmod */
+ struct config_strlist* ipsecmod_whitelist;
+ /** path to external hook */
+ char* ipsecmod_hook;
+ /** true to proceed even with a bogus IPSECKEY */
+ int ipsecmod_ignore_bogus;
+ /** max TTL for the A/AAAA records that call the hook */
+ int ipsecmod_max_ttl;
+ /** false to proceed even when ipsecmod_hook fails */
+ int ipsecmod_strict;
+#endif
};
/** from cfg username, after daemonise setup performed */
@@ -447,7 +505,7 @@ struct config_stub {
int isprime;
/** if forward-first is set (failover to without if fails) */
int isfirst;
- /* use SSL for queries to this stub */
+ /** use SSL for queries to this stub */
int ssl_upstream;
};
@@ -468,6 +526,10 @@ struct config_view {
/** Fallback to global local_zones when there is no match in the view
* view specific tree. 1 for yes, 0 for no */
int isfirst;
+ /** predefined actions for particular IP address responses */
+ struct config_str2list* respip_actions;
+ /** data complementing the 'redirect' response IP actions */
+ struct config_str2list* respip_data;
};
/**
@@ -964,6 +1026,6 @@ void w_config_adjust_directory(struct config_file* cfg);
#endif /* UB_ON_WINDOWS */
/** debug option for unit tests. */
-extern int fake_dsa;
+extern int fake_dsa, fake_sha1;
#endif /* UTIL_CONFIG_FILE_H */
diff --git a/usr.sbin/unbound/util/configlexer.lex b/usr.sbin/unbound/util/configlexer.lex
index 0e6037cd1b5..d9b8e281c56 100644
--- a/usr.sbin/unbound/util/configlexer.lex
+++ b/usr.sbin/unbound/util/configlexer.lex
@@ -300,8 +300,15 @@ view-first{COLON} { YDVAR(1, VAR_VIEW_FIRST) }
do-not-query-address{COLON} { YDVAR(1, VAR_DO_NOT_QUERY_ADDRESS) }
do-not-query-localhost{COLON} { YDVAR(1, VAR_DO_NOT_QUERY_LOCALHOST) }
access-control{COLON} { YDVAR(2, VAR_ACCESS_CONTROL) }
+send-client-subnet{COLON} { YDVAR(1, VAR_SEND_CLIENT_SUBNET) }
+client-subnet-zone{COLON} { YDVAR(1, VAR_CLIENT_SUBNET_ZONE) }
+client-subnet-always-forward{COLON} { YDVAR(1, VAR_CLIENT_SUBNET_ALWAYS_FORWARD) }
+client-subnet-opcode{COLON} { YDVAR(1, VAR_CLIENT_SUBNET_OPCODE) }
+max-client-subnet-ipv4{COLON} { YDVAR(1, VAR_MAX_CLIENT_SUBNET_IPV4) }
+max-client-subnet-ipv6{COLON} { YDVAR(1, VAR_MAX_CLIENT_SUBNET_IPV6) }
hide-identity{COLON} { YDVAR(1, VAR_HIDE_IDENTITY) }
hide-version{COLON} { YDVAR(1, VAR_HIDE_VERSION) }
+hide-trustanchor{COLON} { YDVAR(1, VAR_HIDE_TRUSTANCHOR) }
identity{COLON} { YDVAR(1, VAR_IDENTITY) }
version{COLON} { YDVAR(1, VAR_VERSION) }
module-config{COLON} { YDVAR(1, VAR_MODULE_CONF) }
@@ -311,6 +318,7 @@ trust-anchor-file{COLON} { YDVAR(1, VAR_TRUST_ANCHOR_FILE) }
auto-trust-anchor-file{COLON} { YDVAR(1, VAR_AUTO_TRUST_ANCHOR_FILE) }
trusted-keys-file{COLON} { YDVAR(1, VAR_TRUSTED_KEYS_FILE) }
trust-anchor{COLON} { YDVAR(1, VAR_TRUST_ANCHOR) }
+trust-anchor-signaling{COLON} { YDVAR(1, VAR_TRUST_ANCHOR_SIGNALING) }
val-override-date{COLON} { YDVAR(1, VAR_VAL_OVERRIDE_DATE) }
val-sig-skew-min{COLON} { YDVAR(1, VAR_VAL_SIG_SKEW_MIN) }
val-sig-skew-max{COLON} { YDVAR(1, VAR_VAL_SIG_SKEW_MAX) }
@@ -320,6 +328,7 @@ val-permissive-mode{COLON} { YDVAR(1, VAR_VAL_PERMISSIVE_MODE) }
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) }
+fake-sha1{COLON} { YDVAR(1, VAR_FAKE_SHA1) }
val-log-level{COLON} { YDVAR(1, VAR_VAL_LOG_LEVEL) }
key-cache-size{COLON} { YDVAR(1, VAR_KEY_CACHE_SIZE) }
key-cache-slabs{COLON} { YDVAR(1, VAR_KEY_CACHE_SLABS) }
@@ -343,6 +352,8 @@ insecure-lan-zones{COLON} { YDVAR(1, VAR_INSECURE_LAN_ZONES) }
statistics-interval{COLON} { YDVAR(1, VAR_STATISTICS_INTERVAL) }
statistics-cumulative{COLON} { YDVAR(1, VAR_STATISTICS_CUMULATIVE) }
extended-statistics{COLON} { YDVAR(1, VAR_EXTENDED_STATISTICS) }
+shm-enable{COLON} { YDVAR(1, VAR_SHM_ENABLE) }
+shm-key{COLON} { YDVAR(1, VAR_SHM_KEY) }
remote-control{COLON} { YDVAR(0, VAR_REMOTE_CONTROL) }
control-enable{COLON} { YDVAR(1, VAR_CONTROL_ENABLE) }
control-interface{COLON} { YDVAR(1, VAR_CONTROL_INTERFACE) }
@@ -397,6 +408,21 @@ ratelimit-for-domain{COLON} { YDVAR(2, VAR_RATELIMIT_FOR_DOMAIN) }
ratelimit-below-domain{COLON} { YDVAR(2, VAR_RATELIMIT_BELOW_DOMAIN) }
ip-ratelimit-factor{COLON} { YDVAR(1, VAR_IP_RATELIMIT_FACTOR) }
ratelimit-factor{COLON} { YDVAR(1, VAR_RATELIMIT_FACTOR) }
+response-ip-tag{COLON} { YDVAR(2, VAR_RESPONSE_IP_TAG) }
+response-ip{COLON} { YDVAR(2, VAR_RESPONSE_IP) }
+response-ip-data{COLON} { YDVAR(2, VAR_RESPONSE_IP_DATA) }
+dnscrypt{COLON} { YDVAR(0, VAR_DNSCRYPT) }
+dnscrypt-enable{COLON} { YDVAR(1, VAR_DNSCRYPT_ENABLE) }
+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) }
+ipsecmod-enabled{COLON} { YDVAR(1, VAR_IPSECMOD_ENABLED) }
+ipsecmod-ignore-bogus{COLON} { YDVAR(1, VAR_IPSECMOD_IGNORE_BOGUS) }
+ipsecmod-hook{COLON} { YDVAR(1, VAR_IPSECMOD_HOOK) }
+ipsecmod-max-ttl{COLON} { YDVAR(1, VAR_IPSECMOD_MAX_TTL) }
+ipsecmod-whitelist{COLON} { YDVAR(1, VAR_IPSECMOD_WHITELIST) }
+ipsecmod-strict{COLON} { YDVAR(1, VAR_IPSECMOD_STRICT) }
<INITIAL,val>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; }
/* Quoted strings. Strip leading and ending quotes */
diff --git a/usr.sbin/unbound/util/configparser.y b/usr.sbin/unbound/util/configparser.y
index e6e3fb4744f..7c8161442cc 100644
--- a/usr.sbin/unbound/util/configparser.y
+++ b/usr.sbin/unbound/util/configparser.y
@@ -51,6 +51,8 @@
int ub_c_lex(void);
void ub_c_error(const char *message);
+static void validate_respip_action(const char* action);
+
/* these need to be global, otherwise they cannot be used inside yacc */
extern struct config_parser_state* cfg_parser;
@@ -122,27 +124,36 @@ extern struct config_parser_state* cfg_parser;
%token VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES
%token VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES
%token VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES
+%token VAR_RESPONSE_IP_TAG VAR_RESPONSE_IP VAR_RESPONSE_IP_DATA
%token VAR_HARDEN_ALGO_DOWNGRADE VAR_IP_TRANSPARENT
%token VAR_DISABLE_DNSSEC_LAME_CHECK
%token VAR_IP_RATELIMIT VAR_IP_RATELIMIT_SLABS VAR_IP_RATELIMIT_SIZE
%token VAR_RATELIMIT VAR_RATELIMIT_SLABS VAR_RATELIMIT_SIZE
%token VAR_RATELIMIT_FOR_DOMAIN VAR_RATELIMIT_BELOW_DOMAIN
%token VAR_IP_RATELIMIT_FACTOR VAR_RATELIMIT_FACTOR
+%token VAR_SEND_CLIENT_SUBNET VAR_CLIENT_SUBNET_ZONE
+%token VAR_CLIENT_SUBNET_ALWAYS_FORWARD VAR_CLIENT_SUBNET_OPCODE
+%token VAR_MAX_CLIENT_SUBNET_IPV4 VAR_MAX_CLIENT_SUBNET_IPV6
%token VAR_CAPS_WHITELIST VAR_CACHE_MAX_NEGATIVE_TTL VAR_PERMIT_SMALL_HOLDDOWN
%token VAR_QNAME_MINIMISATION VAR_QNAME_MINIMISATION_STRICT VAR_IP_FREEBIND
%token VAR_DEFINE_TAG VAR_LOCAL_ZONE_TAG VAR_ACCESS_CONTROL_TAG
%token VAR_LOCAL_ZONE_OVERRIDE VAR_ACCESS_CONTROL_TAG_ACTION
%token VAR_ACCESS_CONTROL_TAG_DATA VAR_VIEW VAR_ACCESS_CONTROL_VIEW
-%token VAR_VIEW_FIRST VAR_SERVE_EXPIRED VAR_FAKE_DSA
-%token VAR_LOG_IDENTITY
-%token VAR_USE_SYSTEMD
+%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_DNSCRYPT VAR_DNSCRYPT_ENABLE VAR_DNSCRYPT_PORT VAR_DNSCRYPT_PROVIDER
+%token VAR_DNSCRYPT_SECRET_KEY VAR_DNSCRYPT_PROVIDER_CERT
+%token VAR_IPSECMOD_ENABLED VAR_IPSECMOD_HOOK VAR_IPSECMOD_IGNORE_BOGUS
+%token VAR_IPSECMOD_MAX_TTL VAR_IPSECMOD_WHITELIST VAR_IPSECMOD_STRICT
%%
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
+ contents_view |
+ dnscstart contents_dnsc
;
/* server: declaration */
@@ -205,7 +216,10 @@ content_server: server_num_threads | server_verbosity | server_port |
server_ip_ratelimit_size | server_ratelimit_size |
server_ratelimit_for_domain |
server_ratelimit_below_domain | server_ratelimit_factor |
- server_ip_ratelimit_factor |
+ server_ip_ratelimit_factor | server_send_client_subnet |
+ server_client_subnet_zone | server_client_subnet_always_forward |
+ server_client_subnet_opcode |
+ server_max_client_subnet_ipv4 | server_max_client_subnet_ipv6 |
server_caps_whitelist | server_cache_max_negative_ttl |
server_permit_small_holddown | server_qname_minimisation |
server_ip_freebind | server_define_tag | server_local_zone_tag |
@@ -213,7 +227,13 @@ content_server: server_num_threads | server_verbosity | server_port |
server_local_zone_override | server_access_control_tag_action |
server_access_control_tag_data | server_access_control_view |
server_qname_minimisation_strict | server_serve_expired |
- server_fake_dsa | server_log_identity | server_use_systemd
+ server_fake_dsa | server_log_identity | server_use_systemd |
+ server_response_ip_tag | server_response_ip | server_response_ip_data |
+ server_shm_enable | server_shm_key | server_fake_sha1 |
+ server_hide_trustanchor | server_trust_anchor_signaling |
+ server_ipsecmod_enabled | server_ipsecmod_hook |
+ server_ipsecmod_ignore_bogus | server_ipsecmod_max_ttl |
+ server_ipsecmod_whitelist | server_ipsecmod_strict
;
stubstart: VAR_STUB_ZONE
{
@@ -265,7 +285,8 @@ viewstart: VAR_VIEW
;
contents_view: contents_view content_view
| ;
-content_view: view_name | view_local_zone | view_local_data | view_first
+content_view: view_name | view_local_zone | view_local_data | view_first |
+ view_response_ip | view_response_ip_data | view_local_data_ptr
;
server_num_threads: VAR_NUM_THREADS STRING_ARG
{
@@ -314,6 +335,26 @@ server_extended_statistics: VAR_EXTENDED_STATISTICS STRING_ARG
free($2);
}
;
+server_shm_enable: VAR_SHM_ENABLE STRING_ARG
+ {
+ OUTYY(("P(server_shm_enable:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->shm_enable = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_shm_key: VAR_SHM_KEY STRING_ARG
+ {
+ OUTYY(("P(server_shm_key:%s)\n", $2));
+ if(strcmp($2, "") == 0 || strcmp($2, "0") == 0)
+ cfg_parser->cfg->shm_key = 0;
+ else if(atoi($2) == 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->shm_key = atoi($2);
+ free($2);
+ }
+ ;
server_port: VAR_PORT STRING_ARG
{
OUTYY(("P(server_port:%s)\n", $2));
@@ -323,6 +364,90 @@ server_port: VAR_PORT STRING_ARG
free($2);
}
;
+server_send_client_subnet: VAR_SEND_CLIENT_SUBNET STRING_ARG
+ {
+ #ifdef CLIENT_SUBNET
+ OUTYY(("P(server_send_client_subnet:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->client_subnet, $2))
+ fatal_exit("out of memory adding client-subnet");
+ #else
+ OUTYY(("P(Compiled without edns subnet option, ignoring)\n"));
+ #endif
+ }
+ ;
+server_client_subnet_zone: VAR_CLIENT_SUBNET_ZONE STRING_ARG
+ {
+ #ifdef CLIENT_SUBNET
+ OUTYY(("P(server_client_subnet_zone:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->client_subnet_zone,
+ $2))
+ fatal_exit("out of memory adding client-subnet-zone");
+ #else
+ OUTYY(("P(Compiled without edns subnet option, ignoring)\n"));
+ #endif
+ }
+ ;
+server_client_subnet_always_forward:
+ VAR_CLIENT_SUBNET_ALWAYS_FORWARD STRING_ARG
+ {
+ #ifdef CLIENT_SUBNET
+ OUTYY(("P(server_client_subnet_always_forward:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else
+ cfg_parser->cfg->client_subnet_always_forward =
+ (strcmp($2, "yes")==0);
+ #else
+ OUTYY(("P(Compiled without edns subnet option, ignoring)\n"));
+ #endif
+ free($2);
+ }
+ ;
+server_client_subnet_opcode: VAR_CLIENT_SUBNET_OPCODE STRING_ARG
+ {
+ #ifdef CLIENT_SUBNET
+ OUTYY(("P(client_subnet_opcode:%s)\n", $2));
+ OUTYY(("P(Depricated option, ignoring)\n"));
+ #else
+ OUTYY(("P(Compiled without edns subnet option, ignoring)\n"));
+ #endif
+ free($2);
+ }
+ ;
+server_max_client_subnet_ipv4: VAR_MAX_CLIENT_SUBNET_IPV4 STRING_ARG
+ {
+ #ifdef CLIENT_SUBNET
+ OUTYY(("P(max_client_subnet_ipv4:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("IPv4 subnet length expected");
+ else if (atoi($2) > 32)
+ cfg_parser->cfg->max_client_subnet_ipv4 = 32;
+ else if (atoi($2) < 0)
+ cfg_parser->cfg->max_client_subnet_ipv4 = 0;
+ else cfg_parser->cfg->max_client_subnet_ipv4 = (uint8_t)atoi($2);
+ #else
+ OUTYY(("P(Compiled without edns subnet option, ignoring)\n"));
+ #endif
+ free($2);
+ }
+ ;
+server_max_client_subnet_ipv6: VAR_MAX_CLIENT_SUBNET_IPV6 STRING_ARG
+ {
+ #ifdef CLIENT_SUBNET
+ OUTYY(("P(max_client_subnet_ipv6:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("Ipv6 subnet length expected");
+ else if (atoi($2) > 128)
+ cfg_parser->cfg->max_client_subnet_ipv6 = 128;
+ else if (atoi($2) < 0)
+ cfg_parser->cfg->max_client_subnet_ipv6 = 0;
+ else cfg_parser->cfg->max_client_subnet_ipv6 = (uint8_t)atoi($2);
+ #else
+ OUTYY(("P(Compiled without edns subnet option, ignoring)\n"));
+ #endif
+ free($2);
+ }
+ ;
server_interface: VAR_INTERFACE STRING_ARG
{
OUTYY(("P(server_interface:%s)\n", $2));
@@ -675,6 +800,17 @@ server_trust_anchor: VAR_TRUST_ANCHOR STRING_ARG
yyerror("out of memory");
}
;
+server_trust_anchor_signaling: VAR_TRUST_ANCHOR_SIGNALING STRING_ARG
+ {
+ OUTYY(("P(server_trust_anchor_signaling:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else
+ cfg_parser->cfg->trust_anchor_signaling =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_domain_insecure: VAR_DOMAIN_INSECURE STRING_ARG
{
OUTYY(("P(server_domain_insecure:%s)\n", $2));
@@ -700,6 +836,15 @@ server_hide_version: VAR_HIDE_VERSION STRING_ARG
free($2);
}
;
+server_hide_trustanchor: VAR_HIDE_TRUSTANCHOR STRING_ARG
+ {
+ OUTYY(("P(server_hide_trustanchor:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->hide_trustanchor = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_identity: VAR_IDENTITY STRING_ARG
{
OUTYY(("P(server_identity:%s)\n", $2));
@@ -1236,6 +1381,19 @@ server_fake_dsa: VAR_FAKE_DSA STRING_ARG
free($2);
}
;
+server_fake_sha1: VAR_FAKE_SHA1 STRING_ARG
+ {
+ OUTYY(("P(server_fake_sha1:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+#ifdef HAVE_SSL
+ else fake_sha1 = (strcmp($2, "yes")==0);
+ if(fake_sha1)
+ log_warn("test option fake_sha1 is enabled");
+#endif
+ free($2);
+ }
+ ;
server_val_log_level: VAR_VAL_LOG_LEVEL STRING_ARG
{
OUTYY(("P(server_val_log_level:%s)\n", $2));
@@ -1509,6 +1667,25 @@ server_access_control_view: VAR_ACCESS_CONTROL_VIEW STRING_ARG STRING_ARG
}
}
;
+server_response_ip_tag: VAR_RESPONSE_IP_TAG STRING_ARG STRING_ARG
+ {
+ size_t len = 0;
+ uint8_t* bitlist = config_parse_taglist(cfg_parser->cfg, $3,
+ &len);
+ free($3);
+ OUTYY(("P(response_ip_tag:%s)\n", $2));
+ if(!bitlist)
+ yyerror("could not parse tags, (define-tag them first)");
+ if(bitlist) {
+ if(!cfg_strbytelist_insert(
+ &cfg_parser->cfg->respip_tags,
+ $2, bitlist, len)) {
+ yyerror("out of memory");
+ free($2);
+ }
+ }
+ }
+ ;
server_ip_ratelimit: VAR_IP_RATELIMIT STRING_ARG
{
OUTYY(("P(server_ip_ratelimit:%s)\n", $2));
@@ -1634,6 +1811,80 @@ server_qname_minimisation_strict: VAR_QNAME_MINIMISATION_STRICT STRING_ARG
free($2);
}
;
+server_ipsecmod_enabled: VAR_IPSECMOD_ENABLED STRING_ARG
+ {
+ #ifdef USE_IPSECMOD
+ OUTYY(("P(server_ipsecmod_enabled:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->ipsecmod_enabled = (strcmp($2, "yes")==0);
+ free($2);
+ #else
+ OUTYY(("P(Compiled without IPsec module, ignoring)\n"));
+ #endif
+ }
+ ;
+server_ipsecmod_ignore_bogus: VAR_IPSECMOD_IGNORE_BOGUS STRING_ARG
+ {
+ #ifdef USE_IPSECMOD
+ OUTYY(("P(server_ipsecmod_ignore_bogus:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->ipsecmod_ignore_bogus = (strcmp($2, "yes")==0);
+ free($2);
+ #else
+ OUTYY(("P(Compiled without IPsec module, ignoring)\n"));
+ #endif
+ }
+ ;
+server_ipsecmod_hook: VAR_IPSECMOD_HOOK STRING_ARG
+ {
+ #ifdef USE_IPSECMOD
+ OUTYY(("P(server_ipsecmod_hook:%s)\n", $2));
+ free(cfg_parser->cfg->ipsecmod_hook);
+ cfg_parser->cfg->ipsecmod_hook = $2;
+ #else
+ OUTYY(("P(Compiled without IPsec module, ignoring)\n"));
+ #endif
+ }
+ ;
+server_ipsecmod_max_ttl: VAR_IPSECMOD_MAX_TTL STRING_ARG
+ {
+ #ifdef USE_IPSECMOD
+ OUTYY(("P(server_ipsecmod_max_ttl:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->ipsecmod_max_ttl = atoi($2);
+ free($2);
+ #else
+ OUTYY(("P(Compiled without IPsec module, ignoring)\n"));
+ #endif
+ }
+ ;
+server_ipsecmod_whitelist: VAR_IPSECMOD_WHITELIST STRING_ARG
+ {
+ #ifdef USE_IPSECMOD
+ OUTYY(("P(server_ipsecmod_whitelist:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->ipsecmod_whitelist, $2))
+ yyerror("out of memory");
+ #else
+ OUTYY(("P(Compiled without IPsec module, ignoring)\n"));
+ #endif
+ }
+ ;
+server_ipsecmod_strict: VAR_IPSECMOD_STRICT STRING_ARG
+ {
+ #ifdef USE_IPSECMOD
+ OUTYY(("P(server_ipsecmod_strict:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->ipsecmod_strict = (strcmp($2, "yes")==0);
+ free($2);
+ #else
+ OUTYY(("P(Compiled without IPsec module, ignoring)\n"));
+ #endif
+ }
+ ;
stub_name: VAR_NAME STRING_ARG
{
OUTYY(("P(name:%s)\n", $2));
@@ -1769,6 +2020,24 @@ view_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
}
}
;
+view_response_ip: VAR_RESPONSE_IP STRING_ARG STRING_ARG
+ {
+ OUTYY(("P(view_response_ip:%s %s)\n", $2, $3));
+ validate_respip_action($3);
+ if(!cfg_str2list_insert(
+ &cfg_parser->cfg->views->respip_actions, $2, $3))
+ fatal_exit("out of memory adding per-view "
+ "response-ip action");
+ }
+ ;
+view_response_ip_data: VAR_RESPONSE_IP_DATA STRING_ARG STRING_ARG
+ {
+ OUTYY(("P(view_response_ip_data:%s)\n", $2));
+ if(!cfg_str2list_insert(
+ &cfg_parser->cfg->views->respip_data, $2, $3))
+ fatal_exit("out of memory adding response-ip-data");
+ }
+ ;
view_local_data: VAR_LOCAL_DATA STRING_ARG
{
OUTYY(("P(view_local_data:%s)\n", $2));
@@ -1778,6 +2047,21 @@ view_local_data: VAR_LOCAL_DATA STRING_ARG
}
}
;
+view_local_data_ptr: VAR_LOCAL_DATA_PTR STRING_ARG
+ {
+ char* ptr;
+ OUTYY(("P(view_local_data_ptr:%s)\n", $2));
+ ptr = cfg_ptr_reverse($2);
+ free($2);
+ if(ptr) {
+ if(!cfg_strlist_insert(&cfg_parser->cfg->views->
+ local_data, ptr))
+ fatal_exit("out of memory adding local-data");
+ } else {
+ yyerror("local-data-ptr could not be reversed");
+ }
+ }
+ ;
view_first: VAR_VIEW_FIRST STRING_ARG
{
OUTYY(("P(view-first:%s)\n", $2));
@@ -2010,6 +2294,92 @@ server_log_identity: VAR_LOG_IDENTITY STRING_ARG
cfg_parser->cfg->log_identity = $2;
}
;
+server_response_ip: VAR_RESPONSE_IP STRING_ARG STRING_ARG
+ {
+ OUTYY(("P(server_response_ip:%s %s)\n", $2, $3));
+ validate_respip_action($3);
+ if(!cfg_str2list_insert(&cfg_parser->cfg->respip_actions,
+ $2, $3))
+ fatal_exit("out of memory adding response-ip");
+ }
+ ;
+server_response_ip_data: VAR_RESPONSE_IP_DATA STRING_ARG STRING_ARG
+ {
+ OUTYY(("P(server_response_ip_data:%s)\n", $2));
+ if(!cfg_str2list_insert(&cfg_parser->cfg->respip_data,
+ $2, $3))
+ fatal_exit("out of memory adding response-ip-data");
+ }
+ ;
+dnscstart: VAR_DNSCRYPT
+ {
+ OUTYY(("\nP(dnscrypt:)\n"));
+ OUTYY(("\nP(dnscrypt:)\n"));
+ }
+ ;
+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_enable: VAR_DNSCRYPT_ENABLE STRING_ARG
+ {
+ OUTYY(("P(dnsc_dnscrypt_enable:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnscrypt = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+
+dnsc_dnscrypt_port: VAR_DNSCRYPT_PORT STRING_ARG
+ {
+ OUTYY(("P(dnsc_dnscrypt_port:%s)\n", $2));
+
+ if(atoi($2) == 0)
+ yyerror("port number expected");
+ else cfg_parser->cfg->dnscrypt_port = atoi($2);
+ free($2);
+ }
+ ;
+dnsc_dnscrypt_provider: VAR_DNSCRYPT_PROVIDER STRING_ARG
+ {
+ OUTYY(("P(dnsc_dnscrypt_provider:%s)\n", $2));
+ free(cfg_parser->cfg->dnscrypt_provider);
+ cfg_parser->cfg->dnscrypt_provider = $2;
+ }
+ ;
+dnsc_dnscrypt_provider_cert: VAR_DNSCRYPT_PROVIDER_CERT STRING_ARG
+ {
+ OUTYY(("P(dnsc_dnscrypt_provider_cert:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_provider_cert, $2))
+ fatal_exit("out of memory adding dnscrypt-provider-cert");
+ }
+ ;
+dnsc_dnscrypt_secret_key: VAR_DNSCRYPT_SECRET_KEY STRING_ARG
+ {
+ OUTYY(("P(dnsc_dnscrypt_secret_key:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_secret_key, $2))
+ fatal_exit("out of memory adding dnscrypt-secret-key");
+ }
+ ;
%%
/* parse helper routines could be here */
+static void
+validate_respip_action(const char* action)
+{
+ if(strcmp(action, "deny")!=0 &&
+ strcmp(action, "redirect")!=0 &&
+ strcmp(action, "inform")!=0 &&
+ strcmp(action, "inform_deny")!=0 &&
+ strcmp(action, "always_transparent")!=0 &&
+ strcmp(action, "always_refuse")!=0 &&
+ strcmp(action, "always_nxdomain")!=0)
+ {
+ yyerror("response-ip action: expected deny, redirect, "
+ "inform, inform_deny, always_transparent, "
+ "always_refuse or always_nxdomain");
+ }
+}
diff --git a/usr.sbin/unbound/util/data/msgencode.c b/usr.sbin/unbound/util/data/msgencode.c
index 5d3a2476217..aab7f5dfecb 100644
--- a/usr.sbin/unbound/util/data/msgencode.c
+++ b/usr.sbin/unbound/util/data/msgencode.c
@@ -459,6 +459,10 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
owner_labs = dname_count_labels(key->rk.dname);
owner_pos = sldns_buffer_position(pkt);
+ /* For an rrset with a fixed TTL, use the rrset's TTL as given */
+ if((key->rk.flags & PACKED_RRSET_FIXEDTTL) != 0)
+ timenow = 0;
+
if(do_data) {
const sldns_rr_descriptor* c = type_rdata_compressable(key);
for(i=0; i<data->count; i++) {
@@ -643,6 +647,8 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
sldns_buffer_clear(buffer);
if(udpsize < sldns_buffer_limit(buffer))
sldns_buffer_set_limit(buffer, udpsize);
+ else if(sldns_buffer_limit(buffer) < udpsize)
+ udpsize = sldns_buffer_limit(buffer);
if(sldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
return 0;
@@ -806,7 +812,7 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
struct edns_data* edns, int dnssec, int secure)
{
uint16_t flags;
- int attach_edns = 1;
+ unsigned int attach_edns = 0;
if(!cached || rep->authoritative) {
/* original flags, copy RD and CD bits from query. */
@@ -829,12 +835,15 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
log_assert(flags & BIT_QR); /* QR bit must be on in our replies */
if(udpsize < LDNS_HEADER_SIZE)
return 0;
+ if(sldns_buffer_capacity(pkt) < udpsize)
+ udpsize = sldns_buffer_capacity(pkt);
if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns)) {
/* packet too small to contain edns, omit it. */
attach_edns = 0;
} else {
/* reserve space for edns record */
- udpsize -= calc_edns_field_size(edns);
+ attach_edns = (unsigned int)calc_edns_field_size(edns);
+ udpsize -= attach_edns;
}
if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
@@ -842,7 +851,8 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
log_err("reply encode: out of memory");
return 0;
}
- if(attach_edns)
+ if(attach_edns && sldns_buffer_capacity(pkt) >=
+ sldns_buffer_limit(pkt)+attach_edns)
attach_edns_record(pkt, edns);
return 1;
}
diff --git a/usr.sbin/unbound/util/data/msgparse.c b/usr.sbin/unbound/util/data/msgparse.c
index 5381500e152..288720068b1 100644
--- a/usr.sbin/unbound/util/data/msgparse.c
+++ b/usr.sbin/unbound/util/data/msgparse.c
@@ -1018,7 +1018,7 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
edns->opt_list = NULL;
/* take the options */
- rdata_len = found->rr_first->size;
+ rdata_len = found->rr_first->size-2;
rdata_ptr = found->rr_first->ttl_data+6;
if(!parse_edns_options(rdata_ptr, rdata_len, edns, region))
return 0;
diff --git a/usr.sbin/unbound/util/data/msgreply.c b/usr.sbin/unbound/util/data/msgreply.c
index 8869716b679..2ce898d7f03 100644
--- a/usr.sbin/unbound/util/data/msgreply.c
+++ b/usr.sbin/unbound/util/data/msgreply.c
@@ -133,9 +133,8 @@ parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep,
return 1;
}
-/** allocate (special) rrset keys, return 0 on error */
-static int
-repinfo_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
+int
+reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
struct regional* region)
{
size_t i;
@@ -438,7 +437,7 @@ parse_create_msg(sldns_buffer* pkt, struct msg_parse* msg,
return 0;
if(!parse_create_repinfo(msg, rep, region))
return 0;
- if(!repinfo_alloc_rrset_keys(*rep, alloc, region))
+ if(!reply_info_alloc_rrset_keys(*rep, alloc, region))
return 0;
if(!parse_copy_decompress(pkt, msg, *rep, region))
return 0;
@@ -688,7 +687,7 @@ reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc,
if(!cp)
return NULL;
/* allocate ub_key structures special or not */
- if(!repinfo_alloc_rrset_keys(cp, alloc, region)) {
+ if(!reply_info_alloc_rrset_keys(cp, alloc, region)) {
if(!region)
reply_info_parsedelete(cp, alloc);
return NULL;
@@ -984,19 +983,20 @@ int edns_opt_list_remove(struct edns_option** list, uint16_t code)
}
static int inplace_cb_reply_call_generic(
- struct inplace_cb_reply* callback_list, enum inplace_cb_list_type type,
+ struct inplace_cb* callback_list, enum inplace_cb_list_type type,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
struct regional* region)
{
- struct inplace_cb_reply* cb;
+ struct inplace_cb* cb;
struct edns_option* opt_list_out = NULL;
if(qstate)
opt_list_out = qstate->edns_opts_front_out;
for(cb=callback_list; cb; cb=cb->next) {
- fptr_ok(fptr_whitelist_inplace_cb_reply_generic(cb->cb, type));
- (void)(*cb->cb)(qinfo, qstate, rep, rcode, edns, &opt_list_out, region,
- cb->cb_arg);
+ fptr_ok(fptr_whitelist_inplace_cb_reply_generic(
+ (inplace_cb_reply_func_type*)cb->cb, type));
+ (void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep,
+ rcode, edns, &opt_list_out, region, cb->id, cb->cb_arg);
}
edns->opt_list = opt_list_out;
return 1;
@@ -1049,11 +1049,40 @@ int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo,
uint8_t* zone, size_t zonelen, struct module_qstate* qstate,
struct regional* region)
{
- struct inplace_cb_query* cb = env->inplace_cb_lists[inplace_cb_query];
+ struct inplace_cb* cb = env->inplace_cb_lists[inplace_cb_query];
+ for(; cb; cb=cb->next) {
+ fptr_ok(fptr_whitelist_inplace_cb_query(
+ (inplace_cb_query_func_type*)cb->cb));
+ (void)(*(inplace_cb_query_func_type*)cb->cb)(qinfo, flags,
+ qstate, addr, addrlen, zone, zonelen, region,
+ cb->id, cb->cb_arg);
+ }
+ return 1;
+}
+
+int inplace_cb_edns_back_parsed_call(struct module_env* env,
+ struct module_qstate* qstate)
+{
+ struct inplace_cb* cb =
+ env->inplace_cb_lists[inplace_cb_edns_back_parsed];
+ for(; cb; cb=cb->next) {
+ fptr_ok(fptr_whitelist_inplace_cb_edns_back_parsed(
+ (inplace_cb_edns_back_parsed_func_type*)cb->cb));
+ (void)(*(inplace_cb_edns_back_parsed_func_type*)cb->cb)(qstate,
+ cb->id, cb->cb_arg);
+ }
+ return 1;
+}
+
+int inplace_cb_query_response_call(struct module_env* env,
+ struct module_qstate* qstate, struct dns_msg* response) {
+ struct inplace_cb* cb =
+ env->inplace_cb_lists[inplace_cb_query_response];
for(; cb; cb=cb->next) {
- fptr_ok(fptr_whitelist_inplace_cb_query(cb->cb));
- (void)(*cb->cb)(qinfo, flags, qstate, addr, addrlen, zone, zonelen,
- region, cb->cb_arg);
+ fptr_ok(fptr_whitelist_inplace_cb_query_response(
+ (inplace_cb_query_response_func_type*)cb->cb));
+ (void)(*(inplace_cb_query_response_func_type*)cb->cb)(qstate,
+ response, cb->id, cb->cb_arg);
}
return 1;
}
@@ -1148,6 +1177,7 @@ struct edns_option* edns_opt_copy_alloc(struct edns_option* list)
if(s->opt_data) {
s->opt_data = memdup(s->opt_data, s->opt_len);
if(!s->opt_data) {
+ free(s);
edns_opt_list_free(result);
return NULL;
}
diff --git a/usr.sbin/unbound/util/data/msgreply.h b/usr.sbin/unbound/util/data/msgreply.h
index 485d49afa87..acbdd3deb61 100644
--- a/usr.sbin/unbound/util/data/msgreply.h
+++ b/usr.sbin/unbound/util/data/msgreply.h
@@ -50,13 +50,13 @@ struct iovec;
struct regional;
struct edns_data;
struct edns_option;
-struct inplace_cb_reply;
-struct inplace_cb_query;
+struct inplace_cb;
struct module_qstate;
struct module_env;
struct msg_parse;
struct rrset_parse;
struct local_rrset;
+struct dns_msg;
/** calculate the prefetch TTL as 90% of original. Calculation
* without numerical overflow (uin32_t) */
@@ -357,6 +357,21 @@ struct reply_info* reply_info_copy(struct reply_info* rep,
struct alloc_cache* alloc, struct regional* region);
/**
+ * Allocate (special) rrset keys.
+ * @param rep: reply info in which the rrset keys to be allocated, rrset[]
+ * array should have bee allocated with NULL pointers.
+ * @param alloc: how to allocate rrset keys.
+ * Not used if region!=NULL, it can be NULL in that case.
+ * @param region: if this parameter is NULL then the alloc is used.
+ * otherwise, rrset keys are allocated in this region.
+ * In a region, no special rrset key structures are needed (not shared).
+ * and no rrset_ref array in the reply needs to be built up.
+ * @return 1 on success, 0 on error
+ */
+int reply_info_alloc_rrset_keys(struct reply_info* rep,
+ struct alloc_cache* alloc, struct regional* region);
+
+/**
* Copy a parsed rrset into given key, decompressing and allocating rdata.
* @param pkt: packet for decompression
* @param msg: the parser message (for flags for trust).
@@ -608,6 +623,29 @@ int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo,
struct regional* region);
/**
+ * Call the registered functions in the inplace_cb_edns_back_parsed linked list.
+ * This function is going to get called after parsing the EDNS data on the
+ * reply from a nameserver.
+ * @param env: module environment.
+ * @param qstate: module qstate.
+ * @return false on failure (a callback function returned an error).
+ */
+int inplace_cb_edns_back_parsed_call(struct module_env* env,
+ struct module_qstate* qstate);
+
+/**
+ * Call the registered functions in the inplace_cb_query_reponse linked list.
+ * This function is going to get called after receiving a reply from a
+ * nameserver.
+ * @param env: module environment.
+ * @param qstate: module qstate.
+ * @param response: received response
+ * @return false on failure (a callback function returned an error).
+ */
+int inplace_cb_query_response_call(struct module_env* env,
+ struct module_qstate* qstate, struct dns_msg* response);
+
+/**
* Copy edns option list allocated to the new region
*/
struct edns_option* edns_opt_copy_region(struct edns_option* list,
diff --git a/usr.sbin/unbound/util/data/packed_rrset.h b/usr.sbin/unbound/util/data/packed_rrset.h
index a2f116afba4..28f603d6f98 100644
--- a/usr.sbin/unbound/util/data/packed_rrset.h
+++ b/usr.sbin/unbound/util/data/packed_rrset.h
@@ -57,6 +57,10 @@ typedef uint64_t rrset_id_type;
* this is set on SOA rrsets in the authority section, to keep its TTL separate
* from the SOA in the answer section from a direct SOA query or ANY query. */
#define PACKED_RRSET_SOA_NEG 0x4
+/** This rrset is considered to have a fixed TTL; its TTL doesn't have to be
+ * updated on encoding in a reply. This flag is not expected to be set in
+ * cached data. */
+#define PACKED_RRSET_FIXEDTTL 0x80000000
/** number of rrs and rrsets for integer overflow protection. More than
* this is not really possible (64K packet has much less RRs and RRsets) in
@@ -83,6 +87,7 @@ struct packed_rrset_key {
* o PACKED_RRSET_NSEC_AT_APEX
* o PACKED_RRSET_PARENT_SIDE
* o PACKED_RRSET_SOA_NEG
+ * o PACKED_RRSET_FIXEDTTL (not supposed to be cached)
*/
uint32_t flags;
/** the rrset type in network format */
diff --git a/usr.sbin/unbound/util/fptr_wlist.c b/usr.sbin/unbound/util/fptr_wlist.c
index 8bd7b973c2f..2797d1fe844 100644
--- a/usr.sbin/unbound/util/fptr_wlist.c
+++ b/usr.sbin/unbound/util/fptr_wlist.c
@@ -49,6 +49,7 @@
#include "services/outside_network.h"
#include "services/mesh.h"
#include "services/localzone.h"
+#include "services/authzone.h"
#include "services/cache/infra.h"
#include "services/cache/rrset.h"
#include "services/view.h"
@@ -75,6 +76,7 @@
#ifdef UB_ON_WINDOWS
#include "winrc/win_svc.h"
#endif
+#include "respip/respip.h"
#ifdef WITH_PYTHONMODULE
#include "pythonmod/pythonmod.h"
@@ -82,6 +84,12 @@
#ifdef USE_CACHEDB
#include "cachedb/cachedb.h"
#endif
+#ifdef USE_IPSECMOD
+#include "ipsecmod/ipsecmod.h"
+#endif
+#ifdef CLIENT_SUBNET
+#include "edns-subnet/subnetmod.h"
+#endif
int
fptr_whitelist_comm_point(comm_point_callback_type *fptr)
@@ -205,6 +213,8 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *))
else if(fptr == &probetree_cmp) return 1;
else if(fptr == &replay_var_compare) return 1;
else if(fptr == &view_cmp) return 1;
+ else if(fptr == &auth_zone_cmp) return 1;
+ else if(fptr == &auth_data_cmp) return 1;
return 0;
}
@@ -218,6 +228,9 @@ fptr_whitelist_hash_sizefunc(lruhash_sizefunc_type fptr)
else if(fptr == &rate_sizefunc) return 1;
else if(fptr == &ip_rate_sizefunc) return 1;
else if(fptr == &test_slabhash_sizefunc) return 1;
+#ifdef CLIENT_SUBNET
+ else if(fptr == &msg_cache_sizefunc) return 1;
+#endif
return 0;
}
@@ -256,6 +269,9 @@ fptr_whitelist_hash_deldatafunc(lruhash_deldatafunc_type fptr)
else if(fptr == &key_entry_deldatafunc) return 1;
else if(fptr == &rate_deldatafunc) return 1;
else if(fptr == &test_slabhash_deldata) return 1;
+#ifdef CLIENT_SUBNET
+ else if(fptr == &subnet_data_delete) return 1;
+#endif
return 0;
}
@@ -297,6 +313,16 @@ fptr_whitelist_modenv_attach_sub(int (*fptr)(
}
int
+fptr_whitelist_modenv_add_sub(int (*fptr)(
+ struct module_qstate* qstate, struct query_info* qinfo,
+ uint16_t qflags, int prime, int valrec, struct module_qstate** newq,
+ struct mesh_state** sub))
+{
+ if(fptr == &mesh_add_sub) return 1;
+ return 0;
+}
+
+int
fptr_whitelist_modenv_kill_sub(void (*fptr)(struct module_qstate* newq))
{
if(fptr == &mesh_state_delete) return 1;
@@ -318,12 +344,19 @@ fptr_whitelist_mod_init(int (*fptr)(struct module_env* env, int id))
if(fptr == &iter_init) return 1;
else if(fptr == &val_init) return 1;
else if(fptr == &dns64_init) return 1;
+ else if(fptr == &respip_init) return 1;
#ifdef WITH_PYTHONMODULE
else if(fptr == &pythonmod_init) return 1;
#endif
#ifdef USE_CACHEDB
else if(fptr == &cachedb_init) return 1;
#endif
+#ifdef USE_IPSECMOD
+ else if(fptr == &ipsecmod_init) return 1;
+#endif
+#ifdef CLIENT_SUBNET
+ else if(fptr == &subnetmod_init) return 1;
+#endif
return 0;
}
@@ -333,12 +366,19 @@ fptr_whitelist_mod_deinit(void (*fptr)(struct module_env* env, int id))
if(fptr == &iter_deinit) return 1;
else if(fptr == &val_deinit) return 1;
else if(fptr == &dns64_deinit) return 1;
+ else if(fptr == &respip_deinit) return 1;
#ifdef WITH_PYTHONMODULE
else if(fptr == &pythonmod_deinit) return 1;
#endif
#ifdef USE_CACHEDB
else if(fptr == &cachedb_deinit) return 1;
#endif
+#ifdef USE_IPSECMOD
+ else if(fptr == &ipsecmod_deinit) return 1;
+#endif
+#ifdef CLIENT_SUBNET
+ else if(fptr == &subnetmod_deinit) return 1;
+#endif
return 0;
}
@@ -349,12 +389,19 @@ fptr_whitelist_mod_operate(void (*fptr)(struct module_qstate* qstate,
if(fptr == &iter_operate) return 1;
else if(fptr == &val_operate) return 1;
else if(fptr == &dns64_operate) return 1;
+ else if(fptr == &respip_operate) return 1;
#ifdef WITH_PYTHONMODULE
else if(fptr == &pythonmod_operate) return 1;
#endif
#ifdef USE_CACHEDB
else if(fptr == &cachedb_operate) return 1;
#endif
+#ifdef USE_IPSECMOD
+ else if(fptr == &ipsecmod_operate) return 1;
+#endif
+#ifdef CLIENT_SUBNET
+ else if(fptr == &subnetmod_operate) return 1;
+#endif
return 0;
}
@@ -365,12 +412,19 @@ fptr_whitelist_mod_inform_super(void (*fptr)(
if(fptr == &iter_inform_super) return 1;
else if(fptr == &val_inform_super) return 1;
else if(fptr == &dns64_inform_super) return 1;
+ else if(fptr == &respip_inform_super) return 1;
#ifdef WITH_PYTHONMODULE
else if(fptr == &pythonmod_inform_super) return 1;
#endif
#ifdef USE_CACHEDB
else if(fptr == &cachedb_inform_super) return 1;
#endif
+#ifdef USE_IPSECMOD
+ else if(fptr == &ipsecmod_inform_super) return 1;
+#endif
+#ifdef CLIENT_SUBNET
+ else if(fptr == &subnetmod_inform_super) return 1;
+#endif
return 0;
}
@@ -381,12 +435,19 @@ fptr_whitelist_mod_clear(void (*fptr)(struct module_qstate* qstate,
if(fptr == &iter_clear) return 1;
else if(fptr == &val_clear) return 1;
else if(fptr == &dns64_clear) return 1;
+ else if(fptr == &respip_clear) return 1;
#ifdef WITH_PYTHONMODULE
else if(fptr == &pythonmod_clear) return 1;
#endif
#ifdef USE_CACHEDB
else if(fptr == &cachedb_clear) return 1;
#endif
+#ifdef USE_IPSECMOD
+ else if(fptr == &ipsecmod_clear) return 1;
+#endif
+#ifdef CLIENT_SUBNET
+ else if(fptr == &subnetmod_clear) return 1;
+#endif
return 0;
}
@@ -396,12 +457,19 @@ fptr_whitelist_mod_get_mem(size_t (*fptr)(struct module_env* env, int id))
if(fptr == &iter_get_mem) return 1;
else if(fptr == &val_get_mem) return 1;
else if(fptr == &dns64_get_mem) return 1;
+ else if(fptr == &respip_get_mem) return 1;
#ifdef WITH_PYTHONMODULE
else if(fptr == &pythonmod_get_mem) return 1;
#endif
#ifdef USE_CACHEDB
else if(fptr == &cachedb_get_mem) return 1;
#endif
+#ifdef USE_IPSECMOD
+ else if(fptr == &ipsecmod_get_mem) return 1;
+#endif
+#ifdef CLIENT_SUBNET
+ else if(fptr == &subnetmod_get_mem) return 1;
+#endif
return 0;
}
@@ -462,7 +530,37 @@ int fptr_whitelist_inplace_cb_reply_generic(inplace_cb_reply_func_type* fptr,
return 0;
}
-int fptr_whitelist_inplace_cb_query(inplace_cb_query_func_type* ATTR_UNUSED(fptr))
+int fptr_whitelist_inplace_cb_query(inplace_cb_query_func_type* fptr)
+{
+#ifdef CLIENT_SUBNET
+ if(fptr == &ecs_whitelist_check)
+ return 1;
+#else
+ (void)fptr;
+#endif
+ return 0;
+}
+
+int fptr_whitelist_inplace_cb_edns_back_parsed(
+ inplace_cb_edns_back_parsed_func_type* fptr)
{
+#ifdef CLIENT_SUBNET
+ if(fptr == &ecs_edns_back_parsed)
+ return 1;
+#else
+ (void)fptr;
+#endif
+ return 0;
+}
+
+int fptr_whitelist_inplace_cb_query_response(
+ inplace_cb_query_response_func_type* fptr)
+{
+#ifdef CLIENT_SUBNET
+ if(fptr == &ecs_query_response)
+ return 1;
+#else
+ (void)fptr;
+#endif
return 0;
}
diff --git a/usr.sbin/unbound/util/fptr_wlist.h b/usr.sbin/unbound/util/fptr_wlist.h
index 5ab69f88758..39e3f2d7f21 100644
--- a/usr.sbin/unbound/util/fptr_wlist.h
+++ b/usr.sbin/unbound/util/fptr_wlist.h
@@ -234,6 +234,15 @@ int fptr_whitelist_modenv_attach_sub(int (*fptr)(
uint16_t qflags, int prime, int valrec, struct module_qstate** newq));
/**
+ * Check function pointer whitelist for module_env add_sub callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_modenv_add_sub(int (*fptr)(struct module_qstate* qstate,
+ struct query_info* qinfo, uint16_t qflags, int prime, int valrec,
+ struct module_qstate** newq, struct mesh_state** sub));
+/**
* Check function pointer whitelist for module_env kill_sub callback values.
*
* @param fptr: function pointer to check.
@@ -351,6 +360,22 @@ int fptr_whitelist_inplace_cb_reply_generic(inplace_cb_reply_func_type* fptr,
*/
int fptr_whitelist_inplace_cb_query(inplace_cb_query_func_type* fptr);
+/**
+ * Check function pointer whitelist for inplace_cb_edns_back_parsed func values.
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_inplace_cb_edns_back_parsed(
+ inplace_cb_edns_back_parsed_func_type* fptr);
+
+/**
+ * Check function pointer whitelist for inplace_cb_query_response func values.
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_inplace_cb_query_response(
+ inplace_cb_query_response_func_type* fptr);
+
/** Due to module breakage by fptr wlist, these test app declarations
* are presented here */
/**
diff --git a/usr.sbin/unbound/util/iana_ports.inc b/usr.sbin/unbound/util/iana_ports.inc
index 5709a4976c1..dba3e62270c 100644
--- a/usr.sbin/unbound/util/iana_ports.inc
+++ b/usr.sbin/unbound/util/iana_ports.inc
@@ -29,7 +29,6 @@
44,
45,
46,
-47,
48,
49,
50,
@@ -41,7 +40,6 @@
57,
58,
59,
-61,
62,
63,
64,
@@ -661,6 +659,7 @@
847,
848,
853,
+854,
860,
861,
862,
@@ -3776,6 +3775,7 @@
4188,
4191,
4192,
+4197,
4199,
4300,
4301,
@@ -4455,6 +4455,7 @@
6446,
6455,
6456,
+6464,
6471,
6480,
6481,
@@ -4571,6 +4572,8 @@
7013,
7014,
7015,
+7016,
+7017,
7019,
7020,
7021,
@@ -4729,6 +4732,7 @@
8002,
8003,
8005,
+8006,
8008,
8019,
8020,
@@ -4850,6 +4854,7 @@
8793,
8800,
8804,
+8805,
8808,
8873,
8880,
@@ -5458,3 +5463,4 @@
48556,
48619,
48653,
+49001,
diff --git a/usr.sbin/unbound/util/log.c b/usr.sbin/unbound/util/log.c
index 439541a7ce4..c14b45834ad 100644
--- a/usr.sbin/unbound/util/log.c
+++ b/usr.sbin/unbound/util/log.c
@@ -103,8 +103,12 @@ log_init(const char* filename, int use_syslog, const char* chrootdir)
use_syslog?"syslog":(filename&&filename[0]?filename:"stderr"));
lock_quick_lock(&log_lock);
}
- if(logfile && logfile != stderr)
- fclose(logfile);
+ if(logfile && logfile != stderr) {
+ FILE* cl = logfile;
+ logfile = NULL; /* set to NULL before it is closed, so that
+ other threads have a valid logfile or NULL */
+ fclose(cl);
+ }
#ifdef HAVE_SYSLOG_H
if(logging_to_syslog) {
closelog();
diff --git a/usr.sbin/unbound/util/module.c b/usr.sbin/unbound/util/module.c
index 91983b18274..f4b715d141b 100644
--- a/usr.sbin/unbound/util/module.c
+++ b/usr.sbin/unbound/util/module.c
@@ -123,121 +123,29 @@ edns_register_option(uint16_t opt_code, int bypass_cache_stage,
return 1;
}
-static int
-inplace_cb_reply_register_generic(inplace_cb_reply_func_type* cb,
- enum inplace_cb_list_type type, void* cb_arg, struct module_env* env)
-{
- struct inplace_cb_reply* callback;
- struct inplace_cb_reply** prevp;
- if(env->worker) {
- log_err("invalid edns callback registration: "
- "trying to register callback after module init phase");
- return 0;
- }
-
- callback = (struct inplace_cb_reply*)calloc(1, sizeof(*callback));
- if(callback == NULL) {
- log_err("out of memory during edns callback registration.");
- return 0;
- }
- callback->next = NULL;
- callback->cb = cb;
- callback->cb_arg = cb_arg;
-
- prevp = (struct inplace_cb_reply**) &env->inplace_cb_lists[type];
- /* append at end of list */
- while(*prevp != NULL)
- prevp = &((*prevp)->next);
- *prevp = callback;
- return 1;
-}
-
-int
-inplace_cb_reply_register(inplace_cb_reply_func_type* cb, void* cb_arg,
- struct module_env* env)
-{
- return inplace_cb_reply_register_generic(cb, inplace_cb_reply, cb_arg,
- env);
-}
-
-int
-inplace_cb_reply_cache_register(inplace_cb_reply_func_type* cb, void* cb_arg,
- struct module_env* env)
-{
- return inplace_cb_reply_register_generic(cb, inplace_cb_reply_cache,
- cb_arg, env);
-}
-
int
-inplace_cb_reply_local_register(inplace_cb_reply_func_type* cb, void* cb_arg,
- struct module_env* env)
+inplace_cb_register(void* cb, enum inplace_cb_list_type type, void* cbarg,
+ struct module_env* env, int id)
{
- return inplace_cb_reply_register_generic(cb, inplace_cb_reply_local,
- cb_arg, env);
-}
-
-int
-inplace_cb_reply_servfail_register(inplace_cb_reply_func_type* cb, void* cb_arg,
- struct module_env* env)
-{
- return inplace_cb_reply_register_generic(cb, inplace_cb_reply_servfail,
- cb_arg, env);
-}
-
-static void
-inplace_cb_reply_delete_generic(struct module_env* env,
- enum inplace_cb_list_type type)
-{
- struct inplace_cb_reply* curr = env->inplace_cb_lists[type];
- struct inplace_cb_reply* tmp;
- /* delete list */
- while(curr) {
- tmp = curr->next;
- free(curr);
- curr = tmp;
- }
- /* update head pointer */
- env->inplace_cb_lists[type] = NULL;
-}
-
-void inplace_cb_reply_delete(struct module_env* env)
-{
- inplace_cb_reply_delete_generic(env, inplace_cb_reply);
-}
-
-void inplace_cb_reply_cache_delete(struct module_env* env)
-{
- inplace_cb_reply_delete_generic(env, inplace_cb_reply_cache);
-}
-
-void inplace_cb_reply_servfail_delete(struct module_env* env)
-{
- inplace_cb_reply_delete_generic(env, inplace_cb_reply_servfail);
-}
-
-int
-inplace_cb_query_register(inplace_cb_query_func_type* cb, void* cb_arg,
- struct module_env* env)
-{
- struct inplace_cb_query* callback;
- struct inplace_cb_query** prevp;
+ struct inplace_cb* callback;
+ struct inplace_cb** prevp;
if(env->worker) {
log_err("invalid edns callback registration: "
"trying to register callback after module init phase");
return 0;
}
- callback = (struct inplace_cb_query*)calloc(1, sizeof(*callback));
+ callback = (struct inplace_cb*)calloc(1, sizeof(*callback));
if(callback == NULL) {
log_err("out of memory during edns callback registration.");
return 0;
}
+ callback->id = id;
callback->next = NULL;
callback->cb = cb;
- callback->cb_arg = cb_arg;
+ callback->cb_arg = cbarg;
- prevp = (struct inplace_cb_query**)
- &env->inplace_cb_lists[inplace_cb_query];
+ prevp = (struct inplace_cb**) &env->inplace_cb_lists[type];
/* append at end of list */
while(*prevp != NULL)
prevp = &((*prevp)->next);
@@ -246,27 +154,30 @@ inplace_cb_query_register(inplace_cb_query_func_type* cb, void* cb_arg,
}
void
-inplace_cb_query_delete(struct module_env* env)
-{
- struct inplace_cb_query* curr = env->inplace_cb_lists[inplace_cb_query];
- struct inplace_cb_query* tmp;
- /* delete list */
- while(curr) {
- tmp = curr->next;
- free(curr);
- curr = tmp;
+inplace_cb_delete(struct module_env* env, enum inplace_cb_list_type type,
+ int id)
+{
+ struct inplace_cb* temp = env->inplace_cb_lists[type];
+ struct inplace_cb* prev = NULL;
+
+ while(temp) {
+ if(temp->id == id) {
+ if(!prev) {
+ env->inplace_cb_lists[type] = temp->next;
+ free(temp);
+ temp = env->inplace_cb_lists[type];
+ }
+ else {
+ prev->next = temp->next;
+ free(temp);
+ temp = prev->next;
+ }
+ }
+ else {
+ prev = temp;
+ temp = temp->next;
+ }
}
- /* update head pointer */
- env->inplace_cb_lists[inplace_cb_query] = NULL;
-}
-
-void
-inplace_cb_lists_delete(struct module_env* env)
-{
- inplace_cb_reply_delete(env);
- inplace_cb_reply_cache_delete(env);
- inplace_cb_reply_servfail_delete(env);
- inplace_cb_query_delete(env);
}
struct edns_known_option*
@@ -292,9 +203,11 @@ edns_bypass_cache_stage(struct edns_option* list, struct module_env* env)
}
int
-edns_unique_mesh_state(struct edns_option* list, struct module_env* env)
+unique_mesh_state(struct edns_option* list, struct module_env* env)
{
size_t i;
+ if(env->unique_mesh)
+ return 1;
for(; list; list=list->next)
for(i=0; i<env->edns_known_options_num; i++)
if(env->edns_known_options[i].opt_code == list->opt_code &&
diff --git a/usr.sbin/unbound/util/module.h b/usr.sbin/unbound/util/module.h
index d3db3eaec15..6e75539d916 100644
--- a/usr.sbin/unbound/util/module.h
+++ b/usr.sbin/unbound/util/module.h
@@ -174,6 +174,9 @@ struct val_anchors;
struct val_neg_cache;
struct iter_forwards;
struct iter_hints;
+struct respip_set;
+struct respip_client_info;
+struct respip_addr_info;
/** Maximum number of modules in operation */
#define MAX_MODULE 16
@@ -194,6 +197,11 @@ enum inplace_cb_list_type {
inplace_cb_reply_servfail,
/* Inplace callbacks for when a query is ready to be sent to the back.*/
inplace_cb_query,
+ /* Inplace callback for when a reply is received from the back. */
+ inplace_cb_query_response,
+ /* Inplace callback for when EDNS is parsed on a reply received from the
+ * back. */
+ inplace_cb_edns_back_parsed,
/* Total number of types. Used for array initialization.
* Should always be last. */
inplace_cb_types_total
@@ -211,6 +219,19 @@ struct edns_known_option {
};
/**
+ * Inplace callback list of registered routines to be called.
+ */
+struct inplace_cb {
+ /** next in list */
+ struct inplace_cb* next;
+ /** Inplace callback routine */
+ void* cb;
+ void* cb_arg;
+ /** module id */
+ int id;
+};
+
+/**
* Inplace callback function called before replying.
* Called as func(edns, qstate, opt_list_out, qinfo, reply_info, rcode,
* region, python_callback)
@@ -229,24 +250,7 @@ struct edns_known_option {
typedef int inplace_cb_reply_func_type(struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
struct edns_data* edns, struct edns_option** opt_list_out,
- struct regional* region, void* python_callback);
-
-/**
- * Inplace callback list of registered routines to be called before replying
- * with a resolved query.
- */
-struct inplace_cb_reply {
- /** next in list */
- struct inplace_cb_reply* next;
- /**
- * Inplace callback routine for cache stage response.
- * called as cb(qinfo, qstate, qinfo, reply_info, rcode, edns,
- * opt_list_out, region, python_callback);
- * python_callback is only used for registering a python callback function.
- */
- inplace_cb_reply_func_type* cb;
- void* cb_arg;
-};
+ struct regional* region, int id, void* callback);
/**
* Inplace callback function called before sending the query to a nameserver.
@@ -268,24 +272,30 @@ struct inplace_cb_reply {
typedef int inplace_cb_query_func_type(struct query_info* qinfo, uint16_t flags,
struct module_qstate* qstate, struct sockaddr_storage* addr,
socklen_t addrlen, uint8_t* zone, size_t zonelen, struct regional* region,
- void* python_callback);
+ int id, void* callback);
/**
- * Inplace callback list of registered routines to be called before quering a
- * nameserver.
+ * Inplace callback function called after parsing edns on query reply.
+ * Called as func(qstate, cb_args)
+ * Where:
+ * qstate: the query state
+ * id: module id
+ * cb_args: argument passed when registering callback.
*/
-struct inplace_cb_query {
- /** next in list */
- struct inplace_cb_query* next;
- /**
- * Inplace callback routine for cache stage response.
- * called as cb(qinfo, flags, qstate, addr, addrlen, zone, zonelen,
- * region, python_callback);
- * python_callback is only used for registering a python callback function.
- */
- inplace_cb_query_func_type* cb;
- void* cb_arg;
-};
+typedef int inplace_cb_edns_back_parsed_func_type(struct module_qstate* qstate,
+ int id, void* cb_args);
+
+/**
+ * Inplace callback function called after parsing query response.
+ * Called as func(qstate, id, cb_args)
+ * Where:
+ * qstate: the query state
+ * response: query response
+ * id: module id
+ * cb_args: argument passed when registering callback.
+ */
+typedef int inplace_cb_query_response_func_type(struct module_qstate* qstate,
+ struct dns_msg* response, int id, void* cb_args);
/**
* Module environment.
@@ -373,6 +383,37 @@ struct module_env {
int valrec, struct module_qstate** newq);
/**
+ * Add detached query.
+ * Creates it if it does not exist already.
+ * Does not make super/sub references.
+ * Performs a cycle detection - for double check - and fails if there is
+ * one.
+ * Updates stat items in mesh_area structure.
+ * Pass if it is priming query or not.
+ * return:
+ * o if error (malloc) happened.
+ * o need to initialise the new state (module init; it is a new state).
+ * so that the next run of the query with this module is successful.
+ * o no init needed, attachment successful.
+ * o added subquery, created if it did not exist already.
+ *
+ * @param qstate: the state to find mesh state, and that wants to receive
+ * the results from the new subquery.
+ * @param qinfo: what to query for (copied).
+ * @param qflags: what flags to use (RD / CD flag or not).
+ * @param prime: if it is a (stub) priming query.
+ * @param valrec: if it is a validation recursion query (lookup of key, DS).
+ * @param newq: If the new subquery needs initialisation, it is returned,
+ * otherwise NULL is returned.
+ * @param sub: The added mesh state, created if it did not exist already.
+ * @return: false on error, true if success (and init may be needed).
+ */
+ int (*add_sub)(struct module_qstate* qstate,
+ struct query_info* qinfo, uint16_t qflags, int prime,
+ int valrec, struct module_qstate** newq,
+ struct mesh_state** sub);
+
+ /**
* Kill newly attached sub. If attach_sub returns newq for
* initialisation, but that fails, then this routine will cleanup and
* delete the fresly created sub.
@@ -442,7 +483,7 @@ struct module_env {
void* modinfo[MAX_MODULE];
/* Shared linked list of inplace callback functions */
- void* inplace_cb_lists[inplace_cb_types_total];
+ struct inplace_cb* inplace_cb_lists[inplace_cb_types_total];
/**
* Shared array of known edns options (size MAX_KNOWN_EDNS_OPTS).
@@ -451,6 +492,9 @@ struct module_env {
struct edns_known_option* edns_known_options;
/* Number of known edns options */
size_t edns_known_options_num;
+
+ /* Make every mesh state unique, do not aggregate mesh states. */
+ int unique_mesh;
};
/**
@@ -508,6 +552,8 @@ struct sock_list {
struct sockaddr_storage addr;
};
+struct respip_action_info;
+
/**
* Module state, per query.
*/
@@ -562,6 +608,19 @@ struct module_qstate {
int no_cache_lookup;
/** whether modules should store answer in the cache */
int no_cache_store;
+
+ /**
+ * Attributes of clients that share the qstate that may affect IP-based
+ * actions.
+ */
+ struct respip_client_info* client_info;
+
+ /** Extended result of response-ip action processing, mainly
+ * for logging purposes. */
+ struct respip_action_info* respip_action_info;
+
+ /** whether the reply should be dropped */
+ int is_drop;
};
/**
@@ -680,85 +739,28 @@ int edns_register_option(uint16_t opt_code, int bypass_cache_stage,
int no_aggregation, struct module_env* env);
/**
- * Register an inplace callback function called before replying with a resolved
- * query.
- * @param cb: pointer to the callback function.
- * @param cb_arg: optional argument for the callback function.
- * @param env: the module environment.
- * @return true on success, false on failure (out of memory or trying to
- * register after the environment is copied to the threads.)
- */
-int inplace_cb_reply_register(inplace_cb_reply_func_type* cb, void* cb_arg,
- struct module_env* env);
-
-/**
- * Register an inplace callback function called before replying from the cache.
- * @param cb: pointer to the callback function.
- * @param cb_arg: optional argument for the callback function.
- * @param env: the module environment.
- * @return true on success, false on failure (out of memory or trying to
- * register after the environment is copied to the threads.)
- */
-int inplace_cb_reply_cache_register(inplace_cb_reply_func_type* cb, void* cb_arg,
- struct module_env* env);
-
-/**
- * Register an inplace callback function called before replying with local
- * data or Chaos reply.
+ * Register an inplace callback function.
* @param cb: pointer to the callback function.
- * @param cb_arg: optional argument for the callback function.
+ * @param type: inplace callback type.
+ * @param cbarg: argument for the callback function, or NULL.
* @param env: the module environment.
+ * @param id: module id.
* @return true on success, false on failure (out of memory or trying to
* register after the environment is copied to the threads.)
*/
-int inplace_cb_reply_local_register(inplace_cb_reply_func_type* cb, void* cb_arg,
- struct module_env* env);
-
-/**
- * Register an inplace callback function called before replying with servfail.
- * @param cb: pointer to the callback function.
- * @param cb_arg: optional argument for the callback function.
- * @param env: the module environment.
- * @return true on success, false on failure (out of memory or trying to
- * register after the environment is copied to the threads.)
- */
-int inplace_cb_reply_servfail_register(inplace_cb_reply_func_type* cb,
- void* cb_arg, struct module_env* env);
-
-/**
- * Delete the inplace_cb_reply callback linked list.
- * @param env: the module environment.
- */
-void inplace_cb_reply_delete(struct module_env* env);
-
-/**
- * Delete the inplace_cb_reply_cache callback linked list.
- * @param env: the module environment.
- */
-void inplace_cb_reply_cache_delete(struct module_env* env);
-
-/**
- * Delete the inplace_cb_reply_servfail callback linked list.
- * @param env: the module environment.
- */
-void inplace_cb_reply_servfail_delete(struct module_env* env);
-
-/**
- * Register an inplace callback function called before quering a nameserver.
- * @param cb: pointer to the callback function.
- * @param cb_arg: optional argument for the callback function.
- * @param env: the module environment.
- * @return true on success, false on failure (out of memory or trying to
- * register after the environment is copied to the threads.)
- */
-int inplace_cb_query_register(inplace_cb_query_func_type* cb, void* cb_arg,
- struct module_env* env);
+int
+inplace_cb_register(void* cb, enum inplace_cb_list_type type, void* cbarg,
+ struct module_env* env, int id);
/**
- * Delete the inplace_cb_query callback linked list.
+ * Delete callback for specified type and module id.
* @param env: the module environment.
+ * @param type: inplace callback type.
+ * @param id: module id.
*/
-void inplace_cb_query_delete(struct module_env* env);
+void
+inplace_cb_delete(struct module_env* env, enum inplace_cb_list_type type,
+ int id);
/**
* Delete all the inplace callback linked lists.
@@ -787,13 +789,14 @@ int edns_bypass_cache_stage(struct edns_option* list,
struct module_env* env);
/**
- * Check if an edns option needs a unique mesh state.
+ * Check if an unique mesh state is required. Might be triggered by EDNS option
+ * or set for the complete env.
* @param list: the edns options.
* @param env: the module environment.
* @return true if an edns option needs a unique mesh state,
* false otherwise.
*/
-int edns_unique_mesh_state(struct edns_option* list, struct module_env* env);
+int unique_mesh_state(struct edns_option* list, struct module_env* env);
/**
* Log the known edns options.
diff --git a/usr.sbin/unbound/util/netevent.c b/usr.sbin/unbound/util/netevent.c
index 8e66b9045fa..6990cdb36f3 100644
--- a/usr.sbin/unbound/util/netevent.c
+++ b/usr.sbin/unbound/util/netevent.c
@@ -47,6 +47,7 @@
#include "sldns/pkthdr.h"
#include "sldns/sbuffer.h"
#include "dnstap/dnstap.h"
+#include "dnscrypt/dnscrypt.h"
#ifdef HAVE_OPENSSL_SSL_H
#include <openssl/ssl.h>
#endif
@@ -665,6 +666,7 @@ comm_point_udp_callback(int fd, short event, void* arg)
struct comm_reply rep;
ssize_t rcv;
int i;
+ struct sldns_buffer *buffer;
rep.c = (struct comm_point*)arg;
log_assert(rep.c->type == comm_udp);
@@ -701,7 +703,12 @@ comm_point_udp_callback(int fd, short event, void* arg)
fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
/* send back immediate reply */
- (void)comm_point_send_udp_msg(rep.c, rep.c->buffer,
+#ifdef USE_DNSCRYPT
+ buffer = rep.c->dnscrypt_buffer;
+#else
+ buffer = rep.c->buffer;
+#endif
+ (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
@@ -717,6 +724,10 @@ setup_tcp_handler(struct comm_point* c, int fd, int cur, int max)
log_assert(c->type == comm_tcp);
log_assert(c->fd == -1);
sldns_buffer_clear(c->buffer);
+#ifdef USE_DNSCRYPT
+ if (c->dnscrypt)
+ sldns_buffer_clear(c->dnscrypt_buffer);
+#endif
c->tcp_is_reading = 1;
c->tcp_byte_count = 0;
c->tcp_timeout_msec = TCP_QUERY_TIMEOUT;
@@ -1310,7 +1321,13 @@ static int
comm_point_tcp_handle_write(int fd, struct comm_point* c)
{
ssize_t r;
+ struct sldns_buffer *buffer;
log_assert(c->type == comm_tcp);
+#ifdef USE_DNSCRYPT
+ buffer = c->dnscrypt_buffer;
+#else
+ buffer = c->buffer;
+#endif
if(c->tcp_is_reading && !c->ssl)
return 0;
log_assert(fd != -1);
@@ -1364,15 +1381,15 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
if(c->tcp_do_fastopen == 1) {
/* this form of sendmsg() does both a connect() and send() so need to
look for various flavours of error*/
- uint16_t len = htons(sldns_buffer_limit(c->buffer));
+ uint16_t len = htons(sldns_buffer_limit(buffer));
struct msghdr msg;
struct iovec iov[2];
c->tcp_do_fastopen = 0;
memset(&msg, 0, sizeof(msg));
iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
- iov[1].iov_base = sldns_buffer_begin(c->buffer);
- iov[1].iov_len = sldns_buffer_limit(c->buffer);
+ iov[1].iov_base = sldns_buffer_begin(buffer);
+ iov[1].iov_len = sldns_buffer_limit(buffer);
log_assert(iov[0].iov_len > 0);
log_assert(iov[1].iov_len > 0);
msg.msg_name = &c->repinfo.addr;
@@ -1390,19 +1407,41 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
if(errno == EINTR || errno == EAGAIN)
return 1;
/* Not handling EISCONN here as shouldn't ever hit that case.*/
- if(errno != 0 && verbosity < 2)
+ if(errno != EPIPE && errno != 0 && verbosity < 2)
return 0; /* silence lots of chatter in the logs */
- else if(errno != 0)
+ if(errno != EPIPE && errno != 0) {
log_err_addr("tcp sendmsg", strerror(errno),
&c->repinfo.addr, c->repinfo.addrlen);
- return 0;
+ return 0;
+ }
+ /* fallthrough to nonFASTOPEN
+ * (MSG_FASTOPEN on Linux 3 produces EPIPE)
+ * we need to perform connect() */
+ if(connect(fd, (struct sockaddr *)&c->repinfo.addr, c->repinfo.addrlen) == -1) {
+#ifdef EINPROGRESS
+ if(errno == EINPROGRESS)
+ return 1; /* wait until connect done*/
+#endif
+#ifdef USE_WINSOCK
+ if(WSAGetLastError() == WSAEINPROGRESS ||
+ WSAGetLastError() == WSAEWOULDBLOCK)
+ return 1; /* wait until connect done*/
+#endif
+ if(tcp_connect_errno_needs_log(
+ (struct sockaddr *)&c->repinfo.addr, c->repinfo.addrlen)) {
+ log_err_addr("outgoing tcp: connect after EPIPE for fastopen",
+ strerror(errno), &c->repinfo.addr, c->repinfo.addrlen);
+ }
+ return 0;
+ }
+
} else {
c->tcp_byte_count += r;
if(c->tcp_byte_count < sizeof(uint16_t))
return 1;
- sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
+ sldns_buffer_set_position(buffer, c->tcp_byte_count -
sizeof(uint16_t));
- if(sldns_buffer_remaining(c->buffer) == 0) {
+ if(sldns_buffer_remaining(buffer) == 0) {
tcp_callback_writer(c);
return 1;
}
@@ -1411,13 +1450,13 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
#endif /* USE_MSG_FASTOPEN */
if(c->tcp_byte_count < sizeof(uint16_t)) {
- uint16_t len = htons(sldns_buffer_limit(c->buffer));
+ uint16_t len = htons(sldns_buffer_limit(buffer));
#ifdef HAVE_WRITEV
struct iovec iov[2];
iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
- iov[1].iov_base = sldns_buffer_begin(c->buffer);
- iov[1].iov_len = sldns_buffer_limit(c->buffer);
+ iov[1].iov_base = sldns_buffer_begin(buffer);
+ iov[1].iov_len = sldns_buffer_limit(buffer);
log_assert(iov[0].iov_len > 0);
log_assert(iov[1].iov_len > 0);
r = writev(fd, iov, 2);
@@ -1459,16 +1498,16 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
c->tcp_byte_count += r;
if(c->tcp_byte_count < sizeof(uint16_t))
return 1;
- sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
+ sldns_buffer_set_position(buffer, c->tcp_byte_count -
sizeof(uint16_t));
- if(sldns_buffer_remaining(c->buffer) == 0) {
+ if(sldns_buffer_remaining(buffer) == 0) {
tcp_callback_writer(c);
return 1;
}
}
- log_assert(sldns_buffer_remaining(c->buffer) > 0);
- r = send(fd, (void*)sldns_buffer_current(c->buffer),
- sldns_buffer_remaining(c->buffer), 0);
+ log_assert(sldns_buffer_remaining(buffer) > 0);
+ r = send(fd, (void*)sldns_buffer_current(buffer),
+ sldns_buffer_remaining(buffer), 0);
if(r == -1) {
#ifndef USE_WINSOCK
if(errno == EINTR || errno == EAGAIN)
@@ -1487,9 +1526,9 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
#endif
return 0;
}
- sldns_buffer_skip(c->buffer, r);
+ sldns_buffer_skip(buffer, r);
- if(sldns_buffer_remaining(c->buffer) == 0) {
+ if(sldns_buffer_remaining(buffer) == 0) {
tcp_callback_writer(c);
}
@@ -1503,6 +1542,20 @@ comm_point_tcp_handle_callback(int fd, short event, void* arg)
log_assert(c->type == comm_tcp);
ub_comm_base_now(c->ev->base);
+#ifdef USE_DNSCRYPT
+ /* Initialize if this is a dnscrypt socket */
+ if(c->tcp_parent) {
+ c->dnscrypt = c->tcp_parent->dnscrypt;
+ }
+ if(c->dnscrypt && c->dnscrypt_buffer == c->buffer) {
+ c->dnscrypt_buffer = sldns_buffer_new(sldns_buffer_capacity(c->buffer));
+ if(!c->dnscrypt_buffer) {
+ log_err("Could not allocate dnscrypt buffer");
+ return;
+ }
+ }
+#endif
+
if(event&UB_EV_READ) {
if(!comm_point_tcp_handle_read(fd, c, 0)) {
reclaim_tcp_handler(c);
@@ -1605,6 +1658,10 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
#ifdef USE_MSG_FASTOPEN
c->tcp_do_fastopen = 0;
#endif
+#ifdef USE_DNSCRYPT
+ c->dnscrypt = 0;
+ c->dnscrypt_buffer = buffer;
+#endif
c->inuse = 0;
c->callback = callback;
c->cb_arg = callback_arg;
@@ -1655,6 +1712,10 @@ comm_point_create_udp_ancil(struct comm_base *base, int fd,
c->type = comm_udp;
c->tcp_do_close = 0;
c->do_not_close = 0;
+#ifdef USE_DNSCRYPT
+ c->dnscrypt = 0;
+ c->dnscrypt_buffer = buffer;
+#endif
c->inuse = 0;
c->tcp_do_toggle_rw = 0;
c->tcp_check_nb_connect = 0;
@@ -1726,6 +1787,12 @@ comm_point_create_tcp_handler(struct comm_base *base,
#ifdef USE_MSG_FASTOPEN
c->tcp_do_fastopen = 0;
#endif
+#ifdef USE_DNSCRYPT
+ c->dnscrypt = 0;
+ /* We don't know just yet if this is a dnscrypt channel. Allocation
+ * will be done when handling the callback. */
+ c->dnscrypt_buffer = c->buffer;
+#endif
c->repinfo.c = c;
c->callback = callback;
c->cb_arg = callback_arg;
@@ -1789,6 +1856,10 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize,
#ifdef USE_MSG_FASTOPEN
c->tcp_do_fastopen = 0;
#endif
+#ifdef USE_DNSCRYPT
+ c->dnscrypt = 0;
+ c->dnscrypt_buffer = NULL;
+#endif
c->callback = NULL;
c->cb_arg = NULL;
evbits = UB_EV_READ | UB_EV_PERSIST;
@@ -1857,6 +1928,10 @@ comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
#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;
@@ -1914,6 +1989,10 @@ comm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
#ifdef USE_MSG_FASTOPEN
c->tcp_do_fastopen = 0;
#endif
+#ifdef USE_DNSCRYPT
+ c->dnscrypt = 0;
+ c->dnscrypt_buffer = c->buffer;
+#endif
c->callback = callback;
c->cb_arg = callback_arg;
/* ub_event stuff */
@@ -1970,6 +2049,10 @@ comm_point_create_raw(struct comm_base* base, int fd, int writing,
#ifdef USE_MSG_FASTOPEN
c->tcp_do_fastopen = 0;
#endif
+#ifdef USE_DNSCRYPT
+ c->dnscrypt = 0;
+ c->dnscrypt_buffer = c->buffer;
+#endif
c->callback = callback;
c->cb_arg = callback_arg;
/* ub_event stuff */
@@ -2034,8 +2117,14 @@ 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) {
sldns_buffer_free(c->buffer);
+#ifdef USE_DNSCRYPT
+ if(c->dnscrypt && c->dnscrypt_buffer != c->buffer) {
+ sldns_buffer_free(c->dnscrypt_buffer);
+ }
+#endif
+ }
ub_event_free(c->ev->ev);
free(c->ev);
free(c);
@@ -2044,14 +2133,23 @@ comm_point_delete(struct comm_point* c)
void
comm_point_send_reply(struct comm_reply *repinfo)
{
+ struct sldns_buffer* buffer;
log_assert(repinfo && repinfo->c);
+#ifdef USE_DNSCRYPT
+ buffer = repinfo->c->dnscrypt_buffer;
+ if(!dnsc_handle_uncurved_request(repinfo)) {
+ return;
+ }
+#else
+ buffer = repinfo->c->buffer;
+#endif
if(repinfo->c->type == comm_udp) {
if(repinfo->srctype)
comm_point_send_udp_msg_if(repinfo->c,
- repinfo->c->buffer, (struct sockaddr*)&repinfo->addr,
+ buffer, (struct sockaddr*)&repinfo->addr,
repinfo->addrlen, repinfo);
else
- comm_point_send_udp_msg(repinfo->c, repinfo->c->buffer,
+ comm_point_send_udp_msg(repinfo->c, buffer,
(struct sockaddr*)&repinfo->addr, repinfo->addrlen);
#ifdef USE_DNSTAP
if(repinfo->c->dtenv != NULL &&
@@ -2160,8 +2258,15 @@ size_t comm_point_get_mem(struct comm_point* c)
s = sizeof(*c) + sizeof(*c->ev);
if(c->timeout)
s += sizeof(*c->timeout);
- if(c->type == comm_tcp || c->type == comm_local)
+ if(c->type == comm_tcp || c->type == comm_local) {
s += sizeof(*c->buffer) + sldns_buffer_capacity(c->buffer);
+#ifdef USE_DNSCRYPT
+ s += sizeof(*c->dnscrypt_buffer);
+ if(c->buffer != c->dnscrypt_buffer) {
+ s += sldns_buffer_capacity(c->dnscrypt_buffer);
+ }
+#endif
+ }
if(c->type == comm_tcp_accept) {
int i;
for(i=0; i<c->max_tcp_count; i++)
diff --git a/usr.sbin/unbound/util/netevent.h b/usr.sbin/unbound/util/netevent.h
index 2ce716b850e..54740266d0a 100644
--- a/usr.sbin/unbound/util/netevent.h
+++ b/usr.sbin/unbound/util/netevent.h
@@ -60,6 +60,8 @@
#ifndef NET_EVENT_H
#define NET_EVENT_H
+#include "dnscrypt/dnscrypt.h"
+
struct sldns_buffer;
struct comm_point;
struct comm_reply;
@@ -114,6 +116,13 @@ struct comm_reply {
socklen_t addrlen;
/** return type 0 (none), 4(IP4), 6(IP6) */
int srctype;
+ /* DnsCrypt context */
+#ifdef USE_DNSCRYPT
+ uint8_t client_nonce[crypto_box_HALF_NONCEBYTES];
+ uint8_t nmkey[crypto_box_BEFORENMBYTES];
+ const dnsccert *dnsc_cert;
+ int is_dnscrypted;
+#endif
/** the return source interface data */
union {
#ifdef IPV6_PKTINFO
@@ -124,9 +133,11 @@ struct comm_reply {
#elif defined(IP_RECVDSTADDR)
struct in_addr v4addr;
#endif
- }
+ }
/** variable with return source data */
pktinfo;
+ /** max udp size for udp packets */
+ size_t max_udp_size;
};
/**
@@ -236,6 +247,12 @@ struct comm_point {
int tcp_do_fastopen;
#endif
+#ifdef USE_DNSCRYPT
+ /** Is this a dnscrypt channel */
+ int dnscrypt;
+ /** encrypted buffer pointer. Either to perthread, or own buffer or NULL */
+ struct sldns_buffer* dnscrypt_buffer;
+#endif
/** number of queries outstanding on this socket, used by
* outside network for udp ports */
int inuse;
diff --git a/usr.sbin/unbound/util/shm_side/shm_main.c b/usr.sbin/unbound/util/shm_side/shm_main.c
new file mode 100644
index 00000000000..bba2a839633
--- /dev/null
+++ b/usr.sbin/unbound/util/shm_side/shm_main.c
@@ -0,0 +1,285 @@
+/*
+ * util/shm_side/shm_main.c - SHM for statistics transport
+ *
+ * Copyright (c) 2017, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains functions for the SHM implementation.
+ */
+
+#include "config.h"
+#include <ctype.h>
+#include <stdarg.h>
+#ifdef HAVE_SYS_IPC_H
+#include <sys/ipc.h>
+#endif
+#ifdef HAVE_SYS_SHM_H
+#include <sys/shm.h>
+#endif
+#include <sys/time.h>
+#include <errno.h>
+#include "shm_main.h"
+#include "daemon/daemon.h"
+#include "daemon/worker.h"
+#include "daemon/stats.h"
+#include "services/mesh.h"
+#include "services/cache/rrset.h"
+#include "services/cache/infra.h"
+#include "validator/validator.h"
+#include "util/config_file.h"
+#include "util/fptr_wlist.h"
+#include "util/log.h"
+
+#ifdef HAVE_SHMGET
+/** subtract timers and the values do not overflow or become negative */
+static void
+stat_timeval_subtract(long long *d_sec, long long *d_usec, const struct timeval* end,
+ const struct timeval* start)
+{
+#ifndef S_SPLINT_S
+ time_t end_usec = end->tv_usec;
+ *d_sec = end->tv_sec - start->tv_sec;
+ if(end_usec < start->tv_usec) {
+ end_usec += 1000000;
+ (*d_sec)--;
+ }
+ *d_usec = end_usec - start->tv_usec;
+#endif
+}
+#endif /* HAVE_SHMGET */
+
+int shm_main_init(struct daemon* daemon)
+{
+#ifdef HAVE_SHMGET
+ struct ub_shm_stat_info *shm_stat;
+ size_t shm_size;
+
+ /* sanitize */
+ if(!daemon)
+ return 0;
+ if(!daemon->cfg->shm_enable)
+ return 1;
+ if(daemon->cfg->stat_interval == 0)
+ log_warn("shm-enable is yes but statistics-interval is 0");
+
+ /* Statistics to maintain the number of thread + total */
+ shm_size = (sizeof(struct ub_stats_info) * (daemon->num + 1));
+
+ /* Allocation of needed memory */
+ daemon->shm_info = (struct shm_main_info*)calloc(1, shm_size);
+
+ /* Sanitize */
+ if(!daemon->shm_info) {
+ log_err("shm fail: malloc failure");
+ return 0;
+ }
+
+ daemon->shm_info->key = daemon->cfg->shm_key;
+
+ /* Check for previous create SHM */
+ daemon->shm_info->id_ctl = shmget(daemon->shm_info->key, sizeof(int), SHM_R);
+ daemon->shm_info->id_arr = shmget(daemon->shm_info->key + 1, sizeof(int), SHM_R);
+
+ /* Destroy previous SHM */
+ if (daemon->shm_info->id_ctl >= 0)
+ shmctl(daemon->shm_info->id_ctl, IPC_RMID, NULL);
+
+ /* Destroy previous SHM */
+ if (daemon->shm_info->id_arr >= 0)
+ shmctl(daemon->shm_info->id_arr, IPC_RMID, NULL);
+
+ /* SHM: Create the segment */
+ daemon->shm_info->id_ctl = shmget(daemon->shm_info->key, sizeof(struct ub_shm_stat_info), IPC_CREAT | 0666);
+
+ if (daemon->shm_info->id_ctl < 0)
+ {
+ log_err("SHM failed(id_ctl) cannot shmget(key %d) %s",
+ daemon->shm_info->key, strerror(errno));
+
+ /* Just release memory unused */
+ free(daemon->shm_info);
+
+ return 0;
+ }
+
+ daemon->shm_info->id_arr = shmget(daemon->shm_info->key + 1, shm_size, IPC_CREAT | 0666);
+
+ if (daemon->shm_info->id_arr < 0)
+ {
+ log_err("SHM failed(id_arr) cannot shmget(key %d + 1) %s",
+ daemon->shm_info->key, strerror(errno));
+
+ /* Just release memory unused */
+ free(daemon->shm_info);
+
+ return 0;
+ }
+
+ /* SHM: attach the segment */
+ daemon->shm_info->ptr_ctl = (struct ub_shm_stat_info*)
+ shmat(daemon->shm_info->id_ctl, NULL, 0);
+ if(daemon->shm_info->ptr_ctl == (void *) -1) {
+ log_err("SHM failed(ctl) cannot shmat(%d) %s",
+ daemon->shm_info->id_ctl, strerror(errno));
+
+ /* Just release memory unused */
+ free(daemon->shm_info);
+
+ return 0;
+ }
+
+ daemon->shm_info->ptr_arr = (struct ub_stats_info*)
+ shmat(daemon->shm_info->id_arr, NULL, 0);
+
+ if (daemon->shm_info->ptr_arr == (void *) -1)
+ {
+ log_err("SHM failed(arr) cannot shmat(%d) %s",
+ daemon->shm_info->id_arr, strerror(errno));
+
+ /* Just release memory unused */
+ free(daemon->shm_info);
+
+ return 0;
+ }
+
+ /* Zero fill SHM to stand clean while is not filled by other events */
+ memset(daemon->shm_info->ptr_ctl, 0, sizeof(struct ub_shm_stat_info));
+ memset(daemon->shm_info->ptr_arr, 0, shm_size);
+
+ shm_stat = daemon->shm_info->ptr_ctl;
+ shm_stat->num_threads = daemon->num;
+
+#else
+ (void)daemon;
+#endif /* HAVE_SHMGET */
+ return 1;
+}
+
+void shm_main_shutdown(struct daemon* daemon)
+{
+#ifdef HAVE_SHMGET
+ /* web are OK, just disabled */
+ if(!daemon->cfg->shm_enable)
+ return;
+
+ verbose(VERB_DETAIL, "SHM shutdown - KEY [%d] - ID CTL [%d] ARR [%d] - PTR CTL [%p] ARR [%p]",
+ daemon->shm_info->key, daemon->shm_info->id_ctl, daemon->shm_info->id_arr, daemon->shm_info->ptr_ctl, daemon->shm_info->ptr_arr);
+
+ /* Destroy previous SHM */
+ if (daemon->shm_info->id_ctl >= 0)
+ shmctl(daemon->shm_info->id_ctl, IPC_RMID, NULL);
+
+ if (daemon->shm_info->id_arr >= 0)
+ shmctl(daemon->shm_info->id_arr, IPC_RMID, NULL);
+
+ if (daemon->shm_info->ptr_ctl)
+ shmdt(daemon->shm_info->ptr_ctl);
+
+ if (daemon->shm_info->ptr_arr)
+ shmdt(daemon->shm_info->ptr_arr);
+
+#else
+ (void)daemon;
+#endif /* HAVE_SHMGET */
+}
+
+void shm_main_run(struct worker *worker)
+{
+#ifdef HAVE_SHMGET
+ struct ub_shm_stat_info *shm_stat;
+ struct ub_stats_info *stat_total;
+ struct ub_stats_info *stat_info;
+ int offset;
+
+ verbose(VERB_DETAIL, "SHM run - worker [%d] - daemon [%p] - timenow(%u) - timeboot(%u)",
+ worker->thread_num, worker->daemon, (unsigned)worker->env.now_tv->tv_sec, (unsigned)worker->daemon->time_boot.tv_sec);
+
+ offset = worker->thread_num + 1;
+ stat_total = worker->daemon->shm_info->ptr_arr;
+ stat_info = worker->daemon->shm_info->ptr_arr + offset;
+
+ /* Copy data to the current position */
+ server_stats_compile(worker, stat_info, 0);
+
+ /* First thread, zero fill total, and copy general info */
+ if (worker->thread_num == 0) {
+
+ /* Copy data to the current position */
+ memset(stat_total, 0, sizeof(struct ub_stats_info));
+
+ /* Point to data into SHM */
+ shm_stat = worker->daemon->shm_info->ptr_ctl;
+ shm_stat->time.now_sec = (long long)worker->env.now_tv->tv_sec;
+ shm_stat->time.now_usec = (long long)worker->env.now_tv->tv_usec;
+
+ stat_timeval_subtract(&shm_stat->time.up_sec, &shm_stat->time.up_usec, worker->env.now_tv, &worker->daemon->time_boot);
+ stat_timeval_subtract(&shm_stat->time.elapsed_sec, &shm_stat->time.elapsed_usec, worker->env.now_tv, &worker->daemon->time_last_stat);
+
+ shm_stat->mem.msg = (long long)slabhash_get_mem(worker->env.msg_cache);
+ shm_stat->mem.rrset = (long long)slabhash_get_mem(&worker->env.rrset_cache->table);
+ shm_stat->mem.val = (long long)mod_get_mem(&worker->env,
+ "validator");
+ shm_stat->mem.iter = (long long)mod_get_mem(&worker->env,
+ "iterator");
+ shm_stat->mem.respip = (long long)mod_get_mem(&worker->env,
+ "respip");
+
+ /* subnet mem value is available in shm, also when not enabled,
+ * to make the struct easier to memmap by other applications,
+ * independent of the configuration of unbound */
+ shm_stat->mem.subnet = 0;
+#ifdef CLIENT_SUBNET
+ shm_stat->mem.subnet = (long long)mod_get_mem(&worker->env,
+ "subnet");
+#endif
+ /* ipsecmod mem value is available in shm, also when not enabled,
+ * to make the struct easier to memmap by other applications,
+ * independent of the configuration of unbound */
+ shm_stat->mem.ipsecmod = 0;
+#ifdef USE_IPSECMOD
+ shm_stat->mem.ipsecmod = (long long)mod_get_mem(&worker->env,
+ "ipsecmod");
+#endif
+ }
+
+ server_stats_add(stat_total, stat_info);
+
+ /* print the thread statistics */
+ stat_total->mesh_time_median /= (double)worker->daemon->num;
+
+#else
+ (void)worker;
+#endif /* HAVE_SHMGET */
+}
diff --git a/usr.sbin/unbound/util/shm_side/shm_main.h b/usr.sbin/unbound/util/shm_side/shm_main.h
new file mode 100644
index 00000000000..76c60e48486
--- /dev/null
+++ b/usr.sbin/unbound/util/shm_side/shm_main.h
@@ -0,0 +1,68 @@
+/*
+ * util/shm_side/shm_main.h - control the shared memory for unbound.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains functions for the SHM side.
+ */
+
+#ifndef UTIL_SHM_SIDE_MAIN_H
+#define UTIL_SHM_SIDE_MAIN_H
+struct daemon;
+struct worker;
+
+/* get struct ub_shm_stat_info */
+#include "libunbound/unbound.h"
+
+/**
+ * The SHM info.
+ */
+struct shm_main_info {
+ /** stats_info array, shared memory segment.
+ * [0] is totals, [1..thread_num] are per-thread stats */
+ struct ub_stats_info* ptr_arr;
+ /** the global stats block, shared memory segment */
+ struct ub_shm_stat_info* ptr_ctl;
+ int key;
+ int id_ctl;
+ int id_arr;
+};
+
+int shm_main_init(struct daemon* daemon);
+void shm_main_shutdown(struct daemon* daemon);
+void shm_main_run(struct worker *worker);
+
+#endif /* UTIL_SHM_SIDE_MAIN_H */
diff --git a/usr.sbin/unbound/util/storage/lruhash.c b/usr.sbin/unbound/util/storage/lruhash.c
index 97e99960562..0003ff491e4 100644
--- a/usr.sbin/unbound/util/storage/lruhash.c
+++ b/usr.sbin/unbound/util/storage/lruhash.c
@@ -543,3 +543,89 @@ lruhash_traverse(struct lruhash* h, int wr,
}
lock_quick_unlock(&h->lock);
}
+
+/*
+ * Demote: the opposite of touch, move an entry to the bottom
+ * of the LRU pile.
+ */
+
+void
+lru_demote(struct lruhash* table, struct lruhash_entry* entry)
+{
+ log_assert(table && entry);
+ if (entry == table->lru_end)
+ return; /* nothing to do */
+ /* remove from current lru position */
+ lru_remove(table, entry);
+ /* add at end */
+ entry->lru_next = NULL;
+ entry->lru_prev = table->lru_end;
+
+ if (table->lru_end == NULL)
+ {
+ table->lru_start = entry;
+ }
+ else
+ {
+ table->lru_end->lru_next = entry;
+ }
+ table->lru_end = entry;
+}
+
+struct lruhash_entry*
+lruhash_insert_or_retrieve(struct lruhash* table, hashvalue_type hash,
+ struct lruhash_entry* entry, void* data, void* cb_arg)
+{
+ struct lruhash_bin* bin;
+ struct lruhash_entry* found, *reclaimlist = NULL;
+ size_t need_size;
+ fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
+ fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
+ fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
+ fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
+ fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
+ need_size = table->sizefunc(entry->key, data);
+ if (cb_arg == NULL) cb_arg = table->cb_arg;
+
+ /* find bin */
+ lock_quick_lock(&table->lock);
+ bin = &table->array[hash & table->size_mask];
+ lock_quick_lock(&bin->lock);
+
+ /* see if entry exists already */
+ if ((found = bin_find_entry(table, bin, hash, entry->key)) != NULL) {
+ /* if so: keep the existing data - acquire a writelock */
+ lock_rw_wrlock(&found->lock);
+ }
+ else
+ {
+ /* if not: add to bin */
+ entry->overflow_next = bin->overflow_list;
+ bin->overflow_list = entry;
+ lru_front(table, entry);
+ table->num++;
+ table->space_used += need_size;
+ /* return the entry that was presented, and lock it */
+ found = entry;
+ lock_rw_wrlock(&found->lock);
+ }
+ lock_quick_unlock(&bin->lock);
+ if (table->space_used > table->space_max)
+ reclaim_space(table, &reclaimlist);
+ if (table->num >= table->size)
+ table_grow(table);
+ lock_quick_unlock(&table->lock);
+
+ /* finish reclaim if any (outside of critical region) */
+ while (reclaimlist) {
+ struct lruhash_entry* n = reclaimlist->overflow_next;
+ void* d = reclaimlist->data;
+ (*table->delkeyfunc)(reclaimlist->key, cb_arg);
+ (*table->deldatafunc)(d, cb_arg);
+ reclaimlist = n;
+ }
+
+ /* return the entry that was selected */
+ return found;
+}
+
diff --git a/usr.sbin/unbound/util/storage/lruhash.h b/usr.sbin/unbound/util/storage/lruhash.h
index c3937408232..4759b500123 100644
--- a/usr.sbin/unbound/util/storage/lruhash.h
+++ b/usr.sbin/unbound/util/storage/lruhash.h
@@ -301,6 +301,38 @@ void lru_touch(struct lruhash* table, struct lruhash_entry* entry);
*/
void lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md);
+/************************* getdns functions ************************/
+/*** these are used by getdns only and not by unbound. ***/
+
+/**
+ * Demote entry, so it becomes the least recently used in the LRU list.
+ * Caller must hold hash table lock. The entry must be inserted already.
+ * @param table: hash table.
+ * @param entry: entry to make last in LRU.
+ */
+void lru_demote(struct lruhash* table, struct lruhash_entry* entry);
+
+/**
+ * Insert a new element into the hashtable, or retrieve the corresponding
+ * element of it exits.
+ *
+ * If key is already present data pointer in that entry is kept.
+ * If it is not present, a new entry is created. In that case,
+ * the space calculation function is called with the key, data.
+ * If necessary the least recently used entries are deleted to make space.
+ * If necessary the hash array is grown up.
+ *
+ * @param table: hash table.
+ * @param hash: hash value. User calculates the hash.
+ * @param entry: identifies the entry.
+ * @param data: the data.
+ * @param cb_arg: if not null overrides the cb_arg for the deletefunc.
+ * @return: pointer to the existing entry if the key was already present,
+ * or to the entry argument if it was not.
+ */
+struct lruhash_entry* lruhash_insert_or_retrieve(struct lruhash* table, hashvalue_type hash,
+ struct lruhash_entry* entry, void* data, void* cb_arg);
+
/************************* Internal functions ************************/
/*** these are only exposed for unit tests. ***/
diff --git a/usr.sbin/unbound/util/timehist.c b/usr.sbin/unbound/util/timehist.c
index 98d8db1c8f0..61cc995fd8e 100644
--- a/usr.sbin/unbound/util/timehist.c
+++ b/usr.sbin/unbound/util/timehist.c
@@ -21,16 +21,16 @@
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
@@ -43,6 +43,7 @@
#include <time.h>
#endif
#include <sys/time.h>
+#include <sys/types.h>
#include "util/timehist.h"
#include "util/log.h"
@@ -224,23 +225,23 @@ timehist_quartile(struct timehist* hist, double q)
}
void
-timehist_export(struct timehist* hist, size_t* array, size_t sz)
+timehist_export(struct timehist* hist, long long* array, size_t sz)
{
size_t i;
if(!hist) return;
if(sz > hist->num)
sz = hist->num;
for(i=0; i<sz; i++)
- array[i] = hist->buckets[i].count;
+ array[i] = (long long)hist->buckets[i].count;
}
void
-timehist_import(struct timehist* hist, size_t* array, size_t sz)
+timehist_import(struct timehist* hist, long long* array, size_t sz)
{
size_t i;
if(!hist) return;
if(sz > hist->num)
sz = hist->num;
for(i=0; i<sz; i++)
- hist->buckets[i].count = array[i];
+ hist->buckets[i].count = (size_t)array[i];
}
diff --git a/usr.sbin/unbound/util/timehist.h b/usr.sbin/unbound/util/timehist.h
index d59448399b9..5f88a38a9fd 100644
--- a/usr.sbin/unbound/util/timehist.h
+++ b/usr.sbin/unbound/util/timehist.h
@@ -21,16 +21,16 @@
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
@@ -121,7 +121,7 @@ void timehist_log(struct timehist* hist, const char* name);
* @param array: the array to export to.
* @param sz: number of items in array.
*/
-void timehist_export(struct timehist* hist, size_t* array, size_t sz);
+void timehist_export(struct timehist* hist, long long* array, size_t sz);
/**
* Import histogram from an array.
@@ -129,6 +129,6 @@ void timehist_export(struct timehist* hist, size_t* array, size_t sz);
* @param array: the array to import from.
* @param sz: number of items in array.
*/
-void timehist_import(struct timehist* hist, size_t* array, size_t sz);
+void timehist_import(struct timehist* hist, long long* array, size_t sz);
#endif /* UTIL_TIMEHIST_H */