/** * * \file context.h * @brief getdns context management functions * * Originally taken from the getdns API description pseudo implementation. * */ /* * Copyright (c) 2013, NLnet Labs, Verisign, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the names of the copyright holders nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _GETDNS_CONTEXT_H_ #define _GETDNS_CONTEXT_H_ #include "getdns/getdns.h" #include "getdns/getdns_extra.h" #include "config.h" #include "types-internal.h" #include "extension/default_eventloop.h" #include "util/rbtree.h" #include "ub_loop.h" #include "server.h" #ifdef HAVE_MDNS_SUPPORT #include "util/lruhash.h" #endif #include "rr-iter.h" #include "anchor.h" #include "tls.h" struct getdns_dns_req; struct ub_ctx; enum filechgs { GETDNS_FCHG_ERRORS = -1 , GETDNS_FCHG_NOERROR = 0 , GETDNS_FCHG_NOCHANGES = 0 , GETDNS_FCHG_MTIME = 1 , GETDNS_FCHG_CTIME = 2}; /** function pointer typedefs */ typedef void (*getdns_update_callback) (struct getdns_context *, getdns_context_code_t); typedef void (*getdns_update_callback2) (struct getdns_context *, getdns_context_code_t, void *userarg); /* internal use only for detecting changes to system files */ struct filechg { char fn[_GETDNS_PATH_MAX]; int changes; int errors; struct stat prevstat; }; typedef enum getdns_tls_hs_state { GETDNS_HS_NONE, GETDNS_HS_WRITE, GETDNS_HS_READ, GETDNS_HS_DONE, GETDNS_HS_FAILED } getdns_tls_hs_state_t; typedef enum getdns_conn_state { GETDNS_CONN_CLOSED, GETDNS_CONN_SETUP, GETDNS_CONN_OPEN, GETDNS_CONN_TEARDOWN, GETDNS_CONN_BACKOFF } getdns_conn_state_t; typedef enum getdns_tasrc { GETDNS_TASRC_NONE, GETDNS_TASRC_ZONE, GETDNS_TASRC_APP, GETDNS_TASRC_FETCHING, GETDNS_TASRC_XML, GETDNS_TASRC_XML_UPDATE, GETDNS_TASRC_FAILED } getdns_tasrc; typedef enum getdns_tsig_algo { GETDNS_NO_TSIG = 0, /* Do not use tsig */ GETDNS_HMAC_MD5 = 1, /* 128 bits */ GETDNS_GSS_TSIG = 2, /* Not supported */ GETDNS_HMAC_SHA1 = 3, /* 160 bits */ GETDNS_HMAC_SHA224 = 4, GETDNS_HMAC_SHA256 = 5, GETDNS_HMAC_SHA384 = 6, GETDNS_HMAC_SHA512 = 7 } getdns_tsig_algo; typedef struct getdns_tsig_info { getdns_tsig_algo alg; const char *name; size_t strlen_name; const uint8_t *dname; size_t dname_len; size_t min_size; /* in # octets */ size_t max_size; /* Actual size in # octets */ } getdns_tsig_info; const getdns_tsig_info *_getdns_get_tsig_info(getdns_tsig_algo tsig_alg); /* for doing public key pinning of TLS-capable upstreams: */ typedef struct sha256_pin { char pin[SHA256_DIGEST_LENGTH]; struct sha256_pin *next; } sha256_pin_t; typedef struct getdns_upstream { /* backpointer to containing upstreams structure */ struct getdns_upstreams *upstreams; socklen_t addr_len; struct sockaddr_storage addr; char addr_str[INET6_ADDRSTRLEN]; /** * How is this upstream doing over UDP? * * to_retry = 1, back_off = 1, in context.c:upstream_init() * * When querying over UDP, first a upstream is selected which to_retry * value > 0 in stub.c:upstream_select(). * * Every time a udp request times out, to_retry is decreased, and if * it reaches 0, it is set to minus back_off in * stub.c:stub_next_upstream(). * * to_retry will become > 0 again. because each time an upstream is * selected for a UDP query in stub.c:upstream_select(), all to_retry * counters <= 0 are incremented. * * On continuous failure, the stubs are less likely to be reselected, * because each time to_retry is set to minus back_off, in * stub.c:stub_next_upstream(), the back_off value is doubled. * * Finally, if all upstreams are failing, the upstreams with the * smallest back_off value will be selected, and the back_off value * decremented by one. */ int to_retry; /* (initialized to 1) */ int back_off; /* (initialized to 1) */ size_t udp_responses; size_t udp_timeouts; /* For stateful upstreams, need to share the connection and track the activity on the connection */ int fd; getdns_transport_list_t transport; getdns_eventloop_event event; getdns_eventloop *loop; getdns_tcp_state tcp; /* These are running totals or historical info */ size_t conn_completed; size_t conn_shutdowns; size_t conn_setup_failed; time_t conn_retry_time; uint16_t conn_backoff_interval; size_t conn_backoffs; size_t total_responses; size_t total_timeouts; getdns_auth_state_t best_tls_auth_state; getdns_auth_state_t last_tls_auth_state; /* These are per connection. */ getdns_conn_state_t conn_state; size_t queries_sent; size_t responses_received; size_t responses_timeouts; size_t keepalive_shutdown; uint64_t keepalive_timeout; int server_keepalive_received; /* Management of outstanding requests on stateful transports */ getdns_network_req *write_queue; getdns_network_req *write_queue_last; _getdns_rbtree_t netreq_by_query_id; /* TLS specific connection handling*/ _getdns_tls_connection* tls_obj; _getdns_tls_session* tls_session; getdns_tls_hs_state_t tls_hs_state; getdns_auth_state_t tls_auth_state; unsigned tls_fallback_ok : 1; char *tls_cipher_list; char *tls_curves_list; /* Auth credentials*/ char tls_auth_name[256]; sha256_pin_t *tls_pubkey_pinset; /* When requests have been scheduled asynchronously on an upstream * that is kept open, and a synchronous call is then done with the * upstream before all scheduled requests have been answered, answers * for the asynchronous requests may be received on the open upstream. * Those cannot be processed immediately, because then asynchronous * callbacks will be fired as a side-effect. * * finished_dnsreqs is a list of dnsreqs for which answers have been * received during a synchronous request. They will be processed * when the asynchronous eventloop is run. For this the finished_event * will be scheduled to the registered asynchronous event loop with a * timeout of 1, so it will fire immediately (but not while scheduling) * when the asynchronous eventloop is run. */ getdns_dns_req *finished_dnsreqs; getdns_eventloop_event finished_event; unsigned is_sync_loop : 1; /* EDNS cookies */ uint32_t secret; uint8_t client_cookie[8]; uint8_t prev_client_cookie[8]; uint8_t server_cookie[32]; unsigned has_client_cookie : 1; unsigned has_prev_client_cookie : 1; unsigned has_server_cookie : 1; unsigned server_cookie_len : 5; /* TSIG */ uint8_t tsig_dname[256]; size_t tsig_dname_len; size_t tsig_size; uint8_t tsig_key[256]; getdns_tsig_algo tsig_alg; } getdns_upstream; typedef struct getdns_log_config { getdns_logfunc_type func; void *userarg; uint64_t system; getdns_loglevel_type level; } getdns_log_config; typedef struct getdns_upstreams { struct mem_funcs mf; size_t referenced; size_t count; size_t current_udp; size_t current_stateful; uint16_t max_backoff_value; uint16_t tls_backoff_time; uint16_t tls_connection_retries; getdns_log_config log; getdns_upstream upstreams[]; } getdns_upstreams; typedef enum tas_state { TAS_LOOKUP_ADDRESSES = 0, TAS_WRITE_GET_XML, TAS_READ_XML_HDR, TAS_READ_XML_DOC, TAS_WRITE_GET_PS7, TAS_READ_PS7_HDR, TAS_READ_PS7_DOC, TAS_DONE, TAS_RETRY, TAS_RETRY_GET_PS7, TAS_RETRY_PS7_HDR, TAS_RETRY_PS7_DOC, TAS_RETRY_DONE } tas_state; typedef enum _getdns_property { PROP_INHERIT = 0, PROP_UNKNOWN = 1, PROP_UNABLE = 2, PROP_ABLE = 3 } _getdns_property; typedef struct tas_connection { getdns_eventloop *loop; getdns_network_req *req; _getdns_rrset_spc rrset_spc; _getdns_rrset *rrset; _getdns_rrtype_iter rr_spc; _getdns_rrtype_iter *rr; int fd; getdns_eventloop_event event; tas_state state; getdns_tcp_state tcp; char *http; getdns_bindata xml; } tas_connection; struct getdns_context { /* Context values */ getdns_resolution_t resolution_type; getdns_namespace_t *namespaces; size_t namespace_count; uint64_t timeout; uint64_t idle_timeout; getdns_redirects_t follow_redirects; getdns_list *dns_root_servers; #if defined(HAVE_LIBUNBOUND) && !defined(HAVE_UB_CTX_SET_STUB) char root_servers_fn[FILENAME_MAX]; #endif getdns_append_name_t append_name; /* Suffix buffer containing a list of (length byte | dname) where * length bytes contains the length of the following dname. * The last dname should be the zero byte. */ const uint8_t *suffixes; /* Length of all suffixes in the suffix buffer */ size_t suffixes_len; uint8_t *trust_anchors; size_t trust_anchors_len; getdns_tasrc trust_anchors_source; tas_connection a; tas_connection aaaa; uint8_t tas_hdr_spc[512]; char *trust_anchors_url; char *trust_anchors_verify_CA; char *trust_anchors_verify_email; _getdns_ksks root_ksk; char *appdata_dir; _getdns_property can_write_appdata; char *tls_ca_path; char *tls_ca_file; char *tls_cipher_list; char *tls_curves_list; getdns_upstreams *upstreams; uint16_t limit_outstanding_queries; uint32_t dnssec_allowed_skew; getdns_tls_authentication_t tls_auth; /* What user requested for TLS*/ getdns_tls_authentication_t tls_auth_min; /* Derived minimum auth allowed*/ uint8_t round_robin_upstreams; uint16_t max_backoff_value; uint16_t tls_backoff_time; uint16_t tls_connection_retries; getdns_transport_list_t *dns_transports; size_t dns_transport_count; uint8_t edns_extended_rcode; uint8_t edns_version; uint8_t edns_do_bit; int edns_maximum_udp_payload_size; /* -1 is unset */ uint8_t edns_client_subnet_private; uint16_t tls_query_padding_blocksize; _getdns_tls_context* tls_ctx; getdns_update_callback update_callback; getdns_update_callback2 update_callback2; void *update_userarg; getdns_log_config log; int processing; int destroying; struct mem_funcs mf; struct mem_funcs my_mf; #ifdef HAVE_LIBUNBOUND /* The underlying contexts that do the real work */ struct ub_ctx *unbound_ctx; int unbound_ta_set; #ifdef HAVE_UNBOUND_EVENT_API _getdns_ub_loop ub_loop; #endif #endif /* A tree to hold local host information*/ _getdns_rbtree_t local_hosts; /* which resolution type the contexts are configured for * 0 means nothing set */ getdns_resolution_t resolution_type_set; /* * outbound requests -> transaction to getdns_dns_req */ _getdns_rbtree_t outbound_requests; /* network requests */ size_t netreqs_in_flight; _getdns_rbtree_t pending_netreqs; getdns_network_req *first_pending_netreq; getdns_eventloop_event pending_timeout_event; struct listen_set *server; /* Event loop extension. */ getdns_eventloop *extension; #ifdef HAVE_LIBUNBOUND getdns_eventloop_event ub_event; /* lock to prevent nested ub_event scheduling */ int ub_event_scheduling; #endif /* The default extension */ _getdns_default_eventloop default_eventloop; _getdns_default_eventloop sync_eventloop; /* request extension defaults */ getdns_dict *header; getdns_dict *add_opt_parameters; unsigned add_warning_for_bad_dns : 1; unsigned dnssec_return_all_statuses : 1; unsigned dnssec_return_full_validation_chain : 1; unsigned dnssec_return_only_secure : 1; unsigned dnssec_return_status : 1; unsigned dnssec_return_validation_chain : 1; #ifdef DNSSEC_ROADBLOCK_AVOIDANCE unsigned dnssec_roadblock_avoidance : 1; #endif unsigned edns_cookies : 1; unsigned return_api_information : 1; /* Not used */ unsigned return_both_v4_and_v6 : 1; unsigned return_call_reporting : 1; uint16_t specify_class; /* * Context for doing system queries. * For example to resolve data.iana.org or to resolver the addresses * of upstreams without specified addresses. */ getdns_context *sys_ctxt; /* List of dnsreqs that want to be notified when we have fetched a * trust anchor from data.iana.org. */ getdns_dns_req *ta_notify; /* * state data used to detect changes to the system config files */ struct filechg fchg_resolvconf; struct filechg fchg_hosts; uint8_t trust_anchors_spc[1024]; #ifdef USE_WINSOCK /* We need to run WSAStartup() to be able to use getaddrinfo() */ WSADATA wsaData; #endif /* MDNS */ #ifdef HAVE_MDNS_SUPPORT /* * If supporting MDNS, context may be instantiated either in basic mode * or in full mode. If working in extended mode, two multicast sockets are * left open, for IPv4 and IPv6. Data can be received on either socket. * The context also keeps a list of open queries, characterized by a * name and an RR type, and a list of received answers, characterized * by name, RR type and data value. */ int mdns_extended_support; /* 0 = no support, 1 = supported, 2 = initialization needed */ int mdns_connection_nb; /* typically 0 or 2 for IPv4 and IPv6 */ struct mdns_network_connection * mdns_connection; struct lruhash * mdns_cache; #endif /* HAVE_MDNS_SUPPORT */ }; /* getdns_context */ void _getdns_upstream_log(getdns_upstream *upstream, uint64_t system, getdns_loglevel_type level, const char *fmt, ...); void _getdns_context_log(getdns_context *context, uint64_t system, getdns_loglevel_type level, const char *fmt, ...); /** internal functions **/ /** * Sets up the unbound contexts with stub or recursive behavior * if needed. * @param context previously initialized getdns_context * @return GETDNS_RETURN_GOOD on success */ getdns_return_t _getdns_context_prepare_for_resolution(getdns_context *context); /* Register a getdns_dns_req with context. * - Without pluggable unbound event API, * ub_fd() is scheduled when this was the first request. */ void _getdns_context_track_outbound_request(getdns_dns_req *dnsreq); /* Deregister getdns_dns_req from the context. * - Without pluggable unbound event API, * ub_fd() is scheduled when this was the first request. * - Potential timeout events will be cleared. * - All associated getdns_dns_reqs (to get the validation chain) * will be canceled. */ void _getdns_context_clear_outbound_request(getdns_dns_req *dnsreq); /* Cancels and frees a getdns_dns_req (without calling user callbacks) * - Deregisters getdns_dns_req with _getdns_context_clear_outbound_request() * - Cancels associated getdns_network_reqs * (by calling ub_cancel() or _getdns_cancel_stub_request()) * - Frees the getdns_dns_req */ void _getdns_context_cancel_request(getdns_dns_req *dnsreq); /* Calls user callback (with GETDNS_CALLBACK_TIMEOUT + response dict), then * cancels and frees the getdns_dns_req with _getdns_context_cancel_request() */ void _getdns_context_request_timed_out(getdns_dns_req *dnsreq); struct getdns_bindata *_getdns_bindata_copy( struct mem_funcs *mfs, size_t size, const uint8_t *data); void _getdns_bindata_destroy( struct mem_funcs *mfs, struct getdns_bindata *bindata); /* perform name resolution in /etc/hosts */ getdns_return_t _getdns_context_local_namespace_resolve( getdns_dns_req* req, struct getdns_dict **response); void _getdns_context_ub_read_cb(void *userarg); void _getdns_upstreams_dereference(getdns_upstreams *upstreams); void _getdns_upstream_shutdown(getdns_upstream *upstream); FILE *_getdns_context_get_priv_fp(getdns_context *context, const char *fn); uint8_t *_getdns_context_get_priv_file(getdns_context *context, const char *fn, uint8_t *buf, size_t buf_len, size_t *file_sz); int _getdns_context_write_priv_file(getdns_context *context, const char *fn, getdns_bindata *content); int _getdns_context_can_write_appdata(getdns_context *context); getdns_context *_getdns_context_get_sys_ctxt( getdns_context *context, getdns_eventloop *loop); #endif /* _GETDNS_CONTEXT_H_ */