diff options
author | Stuart Henderson <sthen@cvs.openbsd.org> | 2024-04-12 15:45:25 +0000 |
---|---|---|
committer | Stuart Henderson <sthen@cvs.openbsd.org> | 2024-04-12 15:45:25 +0000 |
commit | 3602361106df8e297c23ee4ea6f39b63d995c36c (patch) | |
tree | e8fd4bbeb42338595df7e17342b2a5ef8dd2e8d9 /usr.sbin/unbound/util | |
parent | 4b11a11f25856354bcf490574c8194bc479951da (diff) |
merge unbound update
Diffstat (limited to 'usr.sbin/unbound/util')
-rw-r--r-- | usr.sbin/unbound/util/config_file.c | 10 | ||||
-rw-r--r-- | usr.sbin/unbound/util/config_file.h | 6 | ||||
-rw-r--r-- | usr.sbin/unbound/util/configlexer.lex | 3 | ||||
-rw-r--r-- | usr.sbin/unbound/util/configparser.y | 45 | ||||
-rw-r--r-- | usr.sbin/unbound/util/data/msgencode.c | 4 | ||||
-rw-r--r-- | usr.sbin/unbound/util/data/msgparse.c | 25 | ||||
-rw-r--r-- | usr.sbin/unbound/util/data/msgparse.h | 18 | ||||
-rw-r--r-- | usr.sbin/unbound/util/fptr_wlist.c | 2 | ||||
-rw-r--r-- | usr.sbin/unbound/util/log.c | 2 | ||||
-rw-r--r-- | usr.sbin/unbound/util/module.c | 18 | ||||
-rw-r--r-- | usr.sbin/unbound/util/module.h | 10 | ||||
-rw-r--r-- | usr.sbin/unbound/util/net_help.c | 105 | ||||
-rw-r--r-- | usr.sbin/unbound/util/net_help.h | 18 | ||||
-rw-r--r-- | usr.sbin/unbound/util/netevent.c | 102 |
14 files changed, 324 insertions, 44 deletions
diff --git a/usr.sbin/unbound/util/config_file.c b/usr.sbin/unbound/util/config_file.c index b7aed66dc19..8d1fd552191 100644 --- a/usr.sbin/unbound/util/config_file.c +++ b/usr.sbin/unbound/util/config_file.c @@ -271,6 +271,7 @@ config_create(void) cfg->val_permissive_mode = 0; cfg->aggressive_nsec = 1; cfg->ignore_cd = 0; + cfg->disable_edns_do = 0; cfg->serve_expired = 0; cfg->serve_expired_ttl = 0; cfg->serve_expired_ttl_reset = 0; @@ -381,6 +382,7 @@ config_create(void) #ifdef USE_CACHEDB if(!(cfg->cachedb_backend = strdup("testframe"))) goto error_exit; if(!(cfg->cachedb_secret = strdup("default"))) goto error_exit; + cfg->cachedb_no_store = 0; #ifdef USE_REDIS if(!(cfg->redis_server_host = strdup("127.0.0.1"))) goto error_exit; cfg->redis_server_path = NULL; @@ -388,6 +390,7 @@ config_create(void) cfg->redis_timeout = 100; cfg->redis_server_port = 6379; cfg->redis_expire_records = 0; + cfg->redis_logical_db = 0; #endif /* USE_REDIS */ #endif /* USE_CACHEDB */ #ifdef USE_IPSET @@ -690,6 +693,7 @@ int config_set_option(struct config_file* cfg, const char* opt, else S_YNO("val-permissive-mode:", val_permissive_mode) else S_YNO("aggressive-nsec:", aggressive_nsec) else S_YNO("ignore-cd-flag:", ignore_cd) + else S_YNO("disable-edns-do:", disable_edns_do) else if(strcmp(opt, "serve-expired:") == 0) { IS_YES_OR_NO; cfg->serve_expired = (strcmp(val, "yes") == 0); SERVE_EXPIRED = cfg->serve_expired; } @@ -819,6 +823,9 @@ int config_set_option(struct config_file* cfg, const char* opt, { IS_NUMBER_OR_ZERO; cfg->ipsecmod_max_ttl = atoi(val); } else S_YNO("ipsecmod-strict:", ipsecmod_strict) #endif +#ifdef USE_CACHEDB + else S_YNO("cachedb-no-store:", cachedb_no_store) +#endif /* USE_CACHEDB */ else if(strcmp(opt, "define-tag:") ==0) { return config_add_tag(cfg, val); /* val_sig_skew_min, max and val_max_restart are copied into val_env @@ -1149,6 +1156,7 @@ config_get_option(struct config_file* cfg, const char* opt, else O_YNO(opt, "val-permissive-mode", val_permissive_mode) else O_YNO(opt, "aggressive-nsec", aggressive_nsec) else O_YNO(opt, "ignore-cd-flag", ignore_cd) + else O_YNO(opt, "disable-edns-do", disable_edns_do) else O_YNO(opt, "serve-expired", serve_expired) else O_DEC(opt, "serve-expired-ttl", serve_expired_ttl) else O_YNO(opt, "serve-expired-ttl-reset", serve_expired_ttl_reset) @@ -1306,6 +1314,7 @@ config_get_option(struct config_file* cfg, const char* opt, #ifdef USE_CACHEDB else O_STR(opt, "backend", cachedb_backend) else O_STR(opt, "secret-seed", cachedb_secret) + else O_YNO(opt, "cachedb-no-store", cachedb_no_store) #ifdef USE_REDIS else O_STR(opt, "redis-server-host", redis_server_host) else O_DEC(opt, "redis-server-port", redis_server_port) @@ -1313,6 +1322,7 @@ config_get_option(struct config_file* cfg, const char* opt, else O_STR(opt, "redis-server-password", redis_server_password) else O_DEC(opt, "redis-timeout", redis_timeout) else O_YNO(opt, "redis-expire-records", redis_expire_records) + else O_DEC(opt, "redis-logical-db", redis_logical_db) #endif /* USE_REDIS */ #endif /* USE_CACHEDB */ #ifdef USE_IPSET diff --git a/usr.sbin/unbound/util/config_file.h b/usr.sbin/unbound/util/config_file.h index 452f3c6a78f..ad22b8330e3 100644 --- a/usr.sbin/unbound/util/config_file.h +++ b/usr.sbin/unbound/util/config_file.h @@ -409,6 +409,8 @@ struct config_file { int aggressive_nsec; /** ignore the CD flag in incoming queries and refuse them bogus data */ int ignore_cd; + /** disable EDNS DO flag in outgoing requests */ + int disable_edns_do; /** serve expired entries and prefetch them */ int serve_expired; /** serve expired entries until TTL after expiration */ @@ -699,6 +701,8 @@ struct config_file { char* cachedb_backend; /** secret seed for hash key calculation */ char* cachedb_secret; + /** cachedb that does not store, but only reads from database, if on */ + int cachedb_no_store; #ifdef USE_REDIS /** redis server's IP address or host name */ char* redis_server_host; @@ -712,6 +716,8 @@ struct config_file { int redis_timeout; /** set timeout on redis records based on DNS response ttl */ int redis_expire_records; + /** set the redis logical database upon connection */ + int redis_logical_db; #endif #endif /** Downstream DNS Cookies */ diff --git a/usr.sbin/unbound/util/configlexer.lex b/usr.sbin/unbound/util/configlexer.lex index 3fcdfa62e03..fdc267434c7 100644 --- a/usr.sbin/unbound/util/configlexer.lex +++ b/usr.sbin/unbound/util/configlexer.lex @@ -403,6 +403,7 @@ val-clean-additional{COLON} { YDVAR(1, VAR_VAL_CLEAN_ADDITIONAL) } val-permissive-mode{COLON} { YDVAR(1, VAR_VAL_PERMISSIVE_MODE) } aggressive-nsec{COLON} { YDVAR(1, VAR_AGGRESSIVE_NSEC) } ignore-cd-flag{COLON} { YDVAR(1, VAR_IGNORE_CD_FLAG) } +disable-edns-do{COLON} { YDVAR(1, VAR_DISABLE_EDNS_DO) } serve-expired{COLON} { YDVAR(1, VAR_SERVE_EXPIRED) } serve-expired-ttl{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_TTL) } serve-expired-ttl-reset{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_TTL_RESET) } @@ -557,12 +558,14 @@ ipsecmod-strict{COLON} { YDVAR(1, VAR_IPSECMOD_STRICT) } cachedb{COLON} { YDVAR(0, VAR_CACHEDB) } backend{COLON} { YDVAR(1, VAR_CACHEDB_BACKEND) } secret-seed{COLON} { YDVAR(1, VAR_CACHEDB_SECRETSEED) } +cachedb-no-store{COLON} { YDVAR(1, VAR_CACHEDB_NO_STORE) } redis-server-host{COLON} { YDVAR(1, VAR_CACHEDB_REDISHOST) } redis-server-port{COLON} { YDVAR(1, VAR_CACHEDB_REDISPORT) } redis-server-path{COLON} { YDVAR(1, VAR_CACHEDB_REDISPATH) } redis-server-password{COLON} { YDVAR(1, VAR_CACHEDB_REDISPASSWORD) } redis-timeout{COLON} { YDVAR(1, VAR_CACHEDB_REDISTIMEOUT) } redis-expire-records{COLON} { YDVAR(1, VAR_CACHEDB_REDISEXPIRERECORDS) } +redis-logical-db{COLON} { YDVAR(1, VAR_CACHEDB_REDISLOGICALDB) } ipset{COLON} { YDVAR(0, VAR_IPSET) } name-v4{COLON} { YDVAR(1, VAR_IPSET_NAME_V4) } name-v6{COLON} { YDVAR(1, VAR_IPSET_NAME_V6) } diff --git a/usr.sbin/unbound/util/configparser.y b/usr.sbin/unbound/util/configparser.y index d8f25a67ebb..da5d6608f1d 100644 --- a/usr.sbin/unbound/util/configparser.y +++ b/usr.sbin/unbound/util/configparser.y @@ -179,6 +179,7 @@ extern struct config_parser_state* cfg_parser; %token VAR_CACHEDB VAR_CACHEDB_BACKEND VAR_CACHEDB_SECRETSEED %token VAR_CACHEDB_REDISHOST VAR_CACHEDB_REDISPORT VAR_CACHEDB_REDISTIMEOUT %token VAR_CACHEDB_REDISEXPIRERECORDS VAR_CACHEDB_REDISPATH VAR_CACHEDB_REDISPASSWORD +%token VAR_CACHEDB_REDISLOGICALDB %token VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM VAR_FOR_UPSTREAM %token VAR_AUTH_ZONE VAR_ZONEFILE VAR_MASTER VAR_URL VAR_FOR_DOWNSTREAM %token VAR_FALLBACK_ENABLED VAR_TLS_ADDITIONAL_PORT VAR_LOW_RTT VAR_LOW_RTT_PERMIL @@ -198,7 +199,7 @@ extern struct config_parser_state* cfg_parser; %token VAR_INTERFACE_ACTION VAR_INTERFACE_VIEW VAR_INTERFACE_TAG %token VAR_INTERFACE_TAG_ACTION VAR_INTERFACE_TAG_DATA %token VAR_PROXY_PROTOCOL_PORT VAR_STATISTICS_INHIBIT_ZERO -%token VAR_HARDEN_UNKNOWN_ADDITIONAL +%token VAR_HARDEN_UNKNOWN_ADDITIONAL VAR_DISABLE_EDNS_DO VAR_CACHEDB_NO_STORE %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -332,7 +333,7 @@ content_server: server_num_threads | server_verbosity | server_port | server_tcp_reuse_timeout | server_tcp_auth_query_timeout | server_interface_automatic_ports | server_ede | server_proxy_protocol_port | server_statistics_inhibit_zero | - server_harden_unknown_additional + server_harden_unknown_additional | server_disable_edns_do ; stubstart: VAR_STUB_ZONE { @@ -2060,6 +2061,15 @@ server_ignore_cd_flag: VAR_IGNORE_CD_FLAG STRING_ARG free($2); } ; +server_disable_edns_do: VAR_DISABLE_EDNS_DO STRING_ARG + { + OUTYY(("P(server_disable_edns_do:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->disable_edns_do = (strcmp($2, "yes")==0); + free($2); + } + ; server_serve_expired: VAR_SERVE_EXPIRED STRING_ARG { OUTYY(("P(server_serve_expired:%s)\n", $2)); @@ -3701,7 +3711,8 @@ contents_cachedb: contents_cachedb content_cachedb | ; content_cachedb: cachedb_backend_name | cachedb_secret_seed | redis_server_host | redis_server_port | redis_timeout | - redis_expire_records | redis_server_path | redis_server_password + redis_expire_records | redis_server_path | redis_server_password | + cachedb_no_store | redis_logical_db ; cachedb_backend_name: VAR_CACHEDB_BACKEND STRING_ARG { @@ -3727,6 +3738,19 @@ cachedb_secret_seed: VAR_CACHEDB_SECRETSEED STRING_ARG #endif } ; +cachedb_no_store: VAR_CACHEDB_NO_STORE STRING_ARG + { + #ifdef USE_CACHEDB + OUTYY(("P(cachedb_no_store:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->cachedb_no_store = (strcmp($2, "yes")==0); + #else + OUTYY(("P(Compiled without cachedb, ignoring)\n")); + #endif + free($2); + } + ; redis_server_host: VAR_CACHEDB_REDISHOST STRING_ARG { #if defined(USE_CACHEDB) && defined(USE_REDIS) @@ -3804,6 +3828,21 @@ redis_expire_records: VAR_CACHEDB_REDISEXPIRERECORDS STRING_ARG free($2); } ; +redis_logical_db: VAR_CACHEDB_REDISLOGICALDB STRING_ARG + { + #if defined(USE_CACHEDB) && defined(USE_REDIS) + int db; + OUTYY(("P(redis_logical_db:%s)\n", $2)); + db = atoi($2); + if((db == 0 && strcmp($2, "0") != 0) || db < 0) + yyerror("valid redis logical database index expected"); + else cfg_parser->cfg->redis_logical_db = db; + #else + OUTYY(("P(Compiled without cachedb or redis, ignoring)\n")); + #endif + free($2); + } + ; server_tcp_connection_limit: VAR_TCP_CONNECTION_LIMIT STRING_ARG STRING_ARG { OUTYY(("P(server_tcp_connection_limit:%s %s)\n", $2, $3)); diff --git a/usr.sbin/unbound/util/data/msgencode.c b/usr.sbin/unbound/util/data/msgencode.c index 93423f985bd..898ff8412a4 100644 --- a/usr.sbin/unbound/util/data/msgencode.c +++ b/usr.sbin/unbound/util/data/msgencode.c @@ -1015,8 +1015,10 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, ede_size = calc_ede_option_size(edns, &ede_txt_size); if(sldns_buffer_capacity(pkt) < udpsize) udpsize = sldns_buffer_capacity(pkt); + if(!edns || !edns->edns_present) { + attach_edns = 0; /* EDEs are optional, try to fit anything else before them */ - if(udpsize < LDNS_HEADER_SIZE + edns_field_size - ede_size) { + } else if(udpsize < LDNS_HEADER_SIZE + edns_field_size - ede_size) { /* packet too small to contain edns, omit it. */ attach_edns = 0; } else { diff --git a/usr.sbin/unbound/util/data/msgparse.c b/usr.sbin/unbound/util/data/msgparse.c index b5414c6d0a5..d06b7bb25e6 100644 --- a/usr.sbin/unbound/util/data/msgparse.c +++ b/usr.sbin/unbound/util/data/msgparse.c @@ -47,6 +47,7 @@ #include "util/regional.h" #include "util/rfc_1982.h" #include "util/edns.h" +#include "util/net_help.h" #include "sldns/rrdef.h" #include "sldns/sbuffer.h" #include "sldns/parseutil.h" @@ -1306,3 +1307,27 @@ log_edns_opt_list(enum verbosity_value level, const char* info_str, } } +/** remove RR from msgparse RRset, return true if rrset is entirely bad */ +int +msgparse_rrset_remove_rr(const char* str, sldns_buffer* pkt, struct rrset_parse* rrset, + struct rr_parse* prev, struct rr_parse* rr, struct sockaddr_storage* addr, socklen_t addrlen) +{ + if(verbosity >= VERB_QUERY && rrset->dname_len <= LDNS_MAX_DOMAINLEN && str) { + uint8_t buf[LDNS_MAX_DOMAINLEN+1]; + dname_pkt_copy(pkt, buf, rrset->dname); + if(addr) + log_name_addr(VERB_QUERY, str, buf, addr, addrlen); + else log_nametypeclass(VERB_QUERY, str, buf, + rrset->type, ntohs(rrset->rrset_class)); + } + if(prev) + prev->next = rr->next; + else rrset->rr_first = rr->next; + if(rrset->rr_last == rr) + rrset->rr_last = prev; + rrset->rr_count --; + rrset->size -= rr->size; + /* rr struct still exists, but is unlinked, so that in the for loop + * the rr->next works fine to continue. */ + return rrset->rr_count == 0; +} diff --git a/usr.sbin/unbound/util/data/msgparse.h b/usr.sbin/unbound/util/data/msgparse.h index b7dc235d677..8e5c94a28cb 100644 --- a/usr.sbin/unbound/util/data/msgparse.h +++ b/usr.sbin/unbound/util/data/msgparse.h @@ -371,4 +371,22 @@ void msgparse_bucket_remove(struct msg_parse* msg, struct rrset_parse* rrset); void log_edns_opt_list(enum verbosity_value level, const char* info_str, struct edns_option* list); +/** + * Remove RR from msgparse RRset. + * @param str: this string is used for logging if verbose. If NULL, there is + * no logging of the remove. + * @param pkt: packet in buffer that is removed from. Used to log the name + * of the item removed. + * @param rrset: RRset that the RR is removed from. + * @param prev: previous RR in list, or NULL. + * @param rr: RR that is removed. + * @param addr: address used for logging, if verbose, or NULL then it is not + * used. + * @param addrlen: length of addr, if that is not NULL. + * @return true if rrset is entirely bad, it would then need to be removed. + */ +int msgparse_rrset_remove_rr(const char* str, struct sldns_buffer* pkt, + struct rrset_parse* rrset, struct rr_parse* prev, struct rr_parse* rr, + struct sockaddr_storage* addr, socklen_t addrlen); + #endif /* UTIL_DATA_MSGPARSE_H */ diff --git a/usr.sbin/unbound/util/fptr_wlist.c b/usr.sbin/unbound/util/fptr_wlist.c index 11cce1a2a04..a792a342954 100644 --- a/usr.sbin/unbound/util/fptr_wlist.c +++ b/usr.sbin/unbound/util/fptr_wlist.c @@ -169,7 +169,9 @@ int fptr_whitelist_event(void (*fptr)(int, short, void *)) { if(fptr == &comm_point_udp_callback) return 1; +#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG) else if(fptr == &comm_point_udp_ancil_callback) return 1; +#endif else if(fptr == &comm_point_tcp_accept_callback) return 1; else if(fptr == &comm_point_tcp_handle_callback) return 1; else if(fptr == &comm_timer_callback) return 1; diff --git a/usr.sbin/unbound/util/log.c b/usr.sbin/unbound/util/log.c index dfbb2334994..a15ee920c0f 100644 --- a/usr.sbin/unbound/util/log.c +++ b/usr.sbin/unbound/util/log.c @@ -187,7 +187,7 @@ void log_ident_set_default(const char* id) default_ident = id; } -void log_ident_revert_to_default() +void log_ident_revert_to_default(void) { ident = default_ident; } diff --git a/usr.sbin/unbound/util/module.c b/usr.sbin/unbound/util/module.c index 773dab853d2..62e5de4a05b 100644 --- a/usr.sbin/unbound/util/module.c +++ b/usr.sbin/unbound/util/module.c @@ -194,6 +194,24 @@ char* errinf_to_str_servfail(struct module_qstate* qstate) return p; } +char* errinf_to_str_misc(struct module_qstate* qstate) +{ + char buf[20480]; + char* p = buf; + size_t left = sizeof(buf); + struct errinf_strlist* s; + if(!qstate->errinf) + snprintf(p, left, "misc failure"); + else for(s=qstate->errinf; s; s=s->next) { + snprintf(p, left, "%s%s", (s==qstate->errinf?"":" "), s->str); + left -= strlen(p); p += strlen(p); + } + p = strdup(buf); + if(!p) + log_err("malloc failure in errinf_to_str"); + return p; +} + void errinf_rrset(struct module_qstate* qstate, struct ub_packed_rrset_key *rr) { char buf[1024]; diff --git a/usr.sbin/unbound/util/module.h b/usr.sbin/unbound/util/module.h index 5b6fcc93cf1..8a9da3f931a 100644 --- a/usr.sbin/unbound/util/module.h +++ b/usr.sbin/unbound/util/module.h @@ -691,6 +691,8 @@ struct module_qstate { struct respip_action_info* respip_action_info; /** if the query is rpz passthru, no further rpz processing for it */ int rpz_passthru; + /* Flag tcp required. */ + int tcp_required; /** whether the reply should be dropped */ int is_drop; @@ -843,6 +845,14 @@ sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate); char* errinf_to_str_servfail(struct module_qstate* qstate); /** + * Create error info in string. For misc failures that are not servfail. + * @param qstate: query state. + * @return string or NULL on malloc failure (already logged). + * This string is malloced and has to be freed by caller. + */ +char* errinf_to_str_misc(struct module_qstate* qstate); + +/** * Initialize the edns known options by allocating the required space. * @param env: the module environment. * @return false on failure (no memory). diff --git a/usr.sbin/unbound/util/net_help.c b/usr.sbin/unbound/util/net_help.c index dec46da20e2..8970247926d 100644 --- a/usr.sbin/unbound/util/net_help.c +++ b/usr.sbin/unbound/util/net_help.c @@ -953,6 +953,111 @@ void log_crypto_err_code(const char* str, unsigned long err) } #ifdef HAVE_SSL +/** Print crypt erro with SSL_get_error want code and err_get_error code */ +static void log_crypto_err_io_code_arg(const char* str, int r, + unsigned long err, int err_present) +{ + int print_errno = 0, print_crypto_err = 0; + const char* inf = NULL; + + switch(r) { + case SSL_ERROR_NONE: + inf = "no error"; + break; + case SSL_ERROR_ZERO_RETURN: + inf = "channel closed"; + break; + case SSL_ERROR_WANT_READ: + inf = "want read"; + break; + case SSL_ERROR_WANT_WRITE: + inf = "want write"; + break; + case SSL_ERROR_WANT_CONNECT: + inf = "want connect"; + break; + case SSL_ERROR_WANT_ACCEPT: + inf = "want accept"; + break; + case SSL_ERROR_WANT_X509_LOOKUP: + inf = "want X509 lookup"; + break; +#ifdef SSL_ERROR_WANT_ASYNC + case SSL_ERROR_WANT_ASYNC: + inf = "want async"; + break; +#endif +#ifdef SSL_ERROR_WANT_ASYNC_JOB + case SSL_ERROR_WANT_ASYNC_JOB: + inf = "want async job"; + break; +#endif +#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB + case SSL_ERROR_WANT_CLIENT_HELLO_CB: + inf = "want client hello cb"; + break; +#endif + case SSL_ERROR_SYSCALL: + print_errno = 1; + inf = "syscall"; + break; + case SSL_ERROR_SSL: + print_crypto_err = 1; + inf = "SSL, usually protocol, error"; + break; + default: + inf = "unknown SSL_get_error result code"; + print_errno = 1; + print_crypto_err = 1; + } + if(print_crypto_err) { + if(print_errno) { + char buf[1024]; + snprintf(buf, sizeof(buf), "%s with errno %s", + str, strerror(errno)); + if(err_present) + log_crypto_err_code(buf, err); + else log_crypto_err(buf); + } else { + if(err_present) + log_crypto_err_code(str, err); + else log_crypto_err(str); + } + } else { + if(print_errno) { + if(errno == 0) + log_err("str: syscall error with errno %s", + strerror(errno)); + else log_err("str: %s", strerror(errno)); + } else { + log_err("str: %s", inf); + } + } +} +#endif /* HAVE_SSL */ + +void log_crypto_err_io(const char* str, int r) +{ +#ifdef HAVE_SSL + log_crypto_err_io_code_arg(str, r, 0, 0); +#else + (void)str; + (void)r; +#endif /* HAVE_SSL */ +} + +void log_crypto_err_io_code(const char* str, int r, unsigned long err) +{ +#ifdef HAVE_SSL + log_crypto_err_io_code_arg(str, r, err, 1); +#else + (void)str; + (void)r; + (void)err; +#endif /* HAVE_SSL */ +} + +#ifdef HAVE_SSL /** log certificate details */ void log_cert(unsigned level, const char* str, void* cert) diff --git a/usr.sbin/unbound/util/net_help.h b/usr.sbin/unbound/util/net_help.h index a9de910d546..edaea42353d 100644 --- a/usr.sbin/unbound/util/net_help.h +++ b/usr.sbin/unbound/util/net_help.h @@ -430,6 +430,24 @@ void log_crypto_err(const char* str); void log_crypto_err_code(const char* str, unsigned long err); /** + * Log an error from libcrypto that came from SSL_write and so on, with + * a value from SSL_get_error, calls log_err. If that fails it logs with + * log_crypto_err. + * @param str: what failed + * @param r: output of SSL_get_error on the I/O operation result. + */ +void log_crypto_err_io(const char* str, int r); + +/** + * Log an error from libcrypt that came from an I/O routine with the + * errcode from ERR_get_error. Calls log_err() and log_crypto_err_code. + * @param str: what failed + * @param r: output of SSL_get_error on the I/O operation result. + * @param err: error code from ERR_get_error + */ +void log_crypto_err_io_code(const char* str, int r, unsigned long err); + +/** * Log certificate details verbosity, string, of X509 cert * @param level: verbosity level * @param str: string to prefix on output diff --git a/usr.sbin/unbound/util/netevent.c b/usr.sbin/unbound/util/netevent.c index b9395a8998b..141e48d48b3 100644 --- a/usr.sbin/unbound/util/netevent.c +++ b/usr.sbin/unbound/util/netevent.c @@ -892,15 +892,18 @@ static int udp_recv_needs_log(int err) static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep, int stream) { size_t size; - struct pp2_header *header = pp2_read_header(buf); - if(header == NULL) return 0; + struct pp2_header *header; + int err = pp2_read_header(sldns_buffer_begin(buf), + sldns_buffer_remaining(buf)); + if(err) return 0; + header = (struct pp2_header*)sldns_buffer_begin(buf); size = PP2_HEADER_SIZE + ntohs(header->len); if((header->ver_cmd & 0xF) == PP2_CMD_LOCAL) { /* A connection from the proxy itself. * No need to do anything with addresses. */ goto done; } - if(header->fam_prot == 0x00) { + if(header->fam_prot == PP2_UNSPEC_UNSPEC) { /* Unspecified family and protocol. This could be used for * health checks by proxies. * No need to do anything with addresses. */ @@ -908,8 +911,8 @@ static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep, } /* Read the proxied address */ switch(header->fam_prot) { - case 0x11: /* AF_INET|STREAM */ - case 0x12: /* AF_INET|DGRAM */ + case PP2_INET_STREAM: + case PP2_INET_DGRAM: { struct sockaddr_in* addr = (struct sockaddr_in*)&rep->client_addr; @@ -920,8 +923,8 @@ static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep, } /* Ignore the destination address; it should be us. */ break; - case 0x21: /* AF_INET6|STREAM */ - case 0x22: /* AF_INET6|DGRAM */ + case PP2_INET6_STREAM: + case PP2_INET6_DGRAM: { struct sockaddr_in6* addr = (struct sockaddr_in6*)&rep->client_addr; @@ -934,6 +937,10 @@ static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep, } /* Ignore the destination address; it should be us. */ break; + default: + log_err("proxy_protocol: unsupported family and " + "protocol 0x%x", (int)header->fam_prot); + return 0; } rep->is_proxied = 1; done: @@ -948,10 +955,10 @@ done: return 1; } +#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG) void comm_point_udp_ancil_callback(int fd, short event, void* arg) { -#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG) struct comm_reply rep; struct msghdr msg; struct iovec iov[1]; @@ -1063,21 +1070,21 @@ comm_point_udp_ancil_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_if(rep.c, rep.c->buffer, + struct sldns_buffer *buffer; +#ifdef USE_DNSCRYPT + buffer = rep.c->dnscrypt_buffer; +#else + buffer = rep.c->buffer; +#endif + (void)comm_point_send_udp_msg_if(rep.c, buffer, (struct sockaddr*)&rep.remote_addr, rep.remote_addrlen, &rep); } if(!rep.c || rep.c->fd == -1) /* commpoint closed */ break; } -#else - (void)fd; - (void)event; - (void)arg; - fatal_exit("recvmsg: No support for IPV6_PKTINFO; IP_PKTINFO or IP_RECVDSTADDR. " - "Please disable interface-automatic"); -#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */ } +#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */ void comm_point_udp_callback(int fd, short event, void* arg) @@ -1665,7 +1672,8 @@ ssl_handshake(struct comm_point* c) } else { unsigned long err = ERR_get_error(); if(!squelch_err_ssl_handshake(err)) { - log_crypto_err_code("ssl handshake failed", err); + log_crypto_err_io_code("ssl handshake failed", + want, err); log_addr(VERB_OPS, "ssl handshake failed", &c->repinfo.remote_addr, c->repinfo.remote_addrlen); @@ -1815,23 +1823,30 @@ ssl_handle_read(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", + want); return 0; } c->tcp_byte_count += r; + sldns_buffer_skip(c->buffer, r); if(c->tcp_byte_count != current_read_size) return 1; c->pp2_header_state = pp2_header_init; } } if(c->pp2_header_state == pp2_header_init) { - header = pp2_read_header(c->buffer); - if(!header) { + int err; + err = pp2_read_header( + sldns_buffer_begin(c->buffer), + sldns_buffer_limit(c->buffer)); + if(err) { log_err("proxy_protocol: could not parse " - "PROXYv2 header"); + "PROXYv2 header (%s)", + pp_lookup_error(err)); return 0; } + header = (struct pp2_header*)sldns_buffer_begin(c->buffer); want_read_size = ntohs(header->len); - if(sldns_buffer_remaining(c->buffer) < + if(sldns_buffer_limit(c->buffer) < PP2_HEADER_SIZE + want_read_size) { log_err_addr("proxy_protocol: not enough " "buffer size to read PROXYv2 header", "", @@ -1876,10 +1891,12 @@ ssl_handle_read(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", + want); return 0; } c->tcp_byte_count += r; + sldns_buffer_skip(c->buffer, r); if(c->tcp_byte_count != current_read_size) return 1; c->pp2_header_state = pp2_header_done; } @@ -1890,6 +1907,7 @@ ssl_handle_read(struct comm_point* c) c->repinfo.remote_addrlen); return 0; } + sldns_buffer_flip(c->buffer); if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) { log_err_addr("proxy_protocol: could not consume " "PROXYv2 header", "", &c->repinfo.remote_addr, @@ -1934,7 +1952,7 @@ ssl_handle_read(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", want); return 0; } c->tcp_byte_count += r; @@ -1984,7 +2002,7 @@ ssl_handle_read(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", want); return 0; } sldns_buffer_skip(c->buffer, (ssize_t)r); @@ -2075,7 +2093,7 @@ ssl_handle_write(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_write"); + log_crypto_err_io("could not SSL_write", want); return 0; } if(c->tcp_write_and_read) { @@ -2127,7 +2145,7 @@ ssl_handle_write(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_write"); + log_crypto_err_io("could not SSL_write", want); return 0; } if(c->tcp_write_and_read) { @@ -2211,19 +2229,25 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) goto recv_error_initial; } c->tcp_byte_count += r; + sldns_buffer_skip(c->buffer, r); if(c->tcp_byte_count != current_read_size) return 1; c->pp2_header_state = pp2_header_init; } } if(c->pp2_header_state == pp2_header_init) { - header = pp2_read_header(c->buffer); - if(!header) { + int err; + err = pp2_read_header( + sldns_buffer_begin(c->buffer), + sldns_buffer_limit(c->buffer)); + if(err) { log_err("proxy_protocol: could not parse " - "PROXYv2 header"); + "PROXYv2 header (%s)", + pp_lookup_error(err)); return 0; } + header = (struct pp2_header*)sldns_buffer_begin(c->buffer); want_read_size = ntohs(header->len); - if(sldns_buffer_remaining(c->buffer) < + if(sldns_buffer_limit(c->buffer) < PP2_HEADER_SIZE + want_read_size) { log_err_addr("proxy_protocol: not enough " "buffer size to read PROXYv2 header", "", @@ -2250,6 +2274,7 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) goto recv_error; } c->tcp_byte_count += r; + sldns_buffer_skip(c->buffer, r); if(c->tcp_byte_count != current_read_size) return 1; c->pp2_header_state = pp2_header_done; } @@ -2260,6 +2285,7 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) c->repinfo.remote_addrlen); return 0; } + sldns_buffer_flip(c->buffer); if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) { log_err_addr("proxy_protocol: could not consume " "PROXYv2 header", "", &c->repinfo.remote_addr, @@ -2913,7 +2939,7 @@ ssl_http_read_more(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", want); return 0; } verbose(VERB_ALGO, "ssl http read more skip to %d + %d", @@ -3364,7 +3390,7 @@ ssize_t http2_recv_cb(nghttp2_session* ATTR_UNUSED(session), uint8_t* buf, strerror(errno)); return NGHTTP2_ERR_CALLBACK_FAILURE; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", want); return NGHTTP2_ERR_CALLBACK_FAILURE; } return r; @@ -3619,7 +3645,7 @@ ssl_http_write_more(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_write"); + log_crypto_err_io("could not SSL_write", want); return 0; } sldns_buffer_skip(c->buffer, (ssize_t)r); @@ -3692,7 +3718,7 @@ ssize_t http2_send_cb(nghttp2_session* ATTR_UNUSED(session), const uint8_t* buf, strerror(errno)); return NGHTTP2_ERR_CALLBACK_FAILURE; } - log_crypto_err("could not SSL_write"); + log_crypto_err_io("could not SSL_write", want); return NGHTTP2_ERR_CALLBACK_FAILURE; } return r; @@ -3958,11 +3984,7 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, evbits = UB_EV_READ | UB_EV_PERSIST; /* ub_event stuff */ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, -#ifdef USE_WINSOCK comm_point_udp_callback, c); -#else - comm_point_udp_ancil_callback, c); -#endif if(c->ev->ev == NULL) { log_err("could not baseset udp event"); comm_point_delete(c); @@ -3977,6 +3999,7 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, return c; } +#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG) struct comm_point* comm_point_create_udp_ancil(struct comm_base *base, int fd, sldns_buffer* buffer, int pp2_enabled, @@ -4039,6 +4062,7 @@ comm_point_create_udp_ancil(struct comm_base *base, int fd, c->event_added = 1; return c; } +#endif static struct comm_point* comm_point_create_tcp_handler(struct comm_base *base, |