diff options
author | Stuart Henderson <sthen@cvs.openbsd.org> | 2017-08-12 11:22:47 +0000 |
---|---|---|
committer | Stuart Henderson <sthen@cvs.openbsd.org> | 2017-08-12 11:22:47 +0000 |
commit | 72a92e1acfb2c25b147862010c351f1c669d159f (patch) | |
tree | d1d5054f9a4e7919b56c9fcb4bf8173967a9a31f /usr.sbin/unbound/util | |
parent | a02d7aa0c1d30c13f6b9b9736d6a9462d8ac2c31 (diff) |
update to unbound 1.6.4, ok florian@
Diffstat (limited to 'usr.sbin/unbound/util')
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 */ |