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