1 /**
2  *
3  * \file context.h
4  * @brief getdns context management functions
5  *
6  * Originally taken from the getdns API description pseudo implementation.
7  *
8  */
9 
10 /*
11  * Copyright (c) 2013, NLnet Labs, Verisign, Inc.
12  * All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are met:
16  * * Redistributions of source code must retain the above copyright
17  *   notice, this list of conditions and the following disclaimer.
18  * * Redistributions in binary form must reproduce the above copyright
19  *   notice, this list of conditions and the following disclaimer in the
20  *   documentation and/or other materials provided with the distribution.
21  * * Neither the names of the copyright holders nor the
22  *   names of its contributors may be used to endorse or promote products
23  *   derived from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28  * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
29  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 #ifndef _GETDNS_CONTEXT_H_
38 #define _GETDNS_CONTEXT_H_
39 
40 #include "getdns/getdns.h"
41 #include "getdns/getdns_extra.h"
42 #include "config.h"
43 #include "types-internal.h"
44 #include "extension/default_eventloop.h"
45 #include "util/rbtree.h"
46 #include "ub_loop.h"
47 #include "server.h"
48 #ifdef HAVE_MDNS_SUPPORT
49 #include "util/lruhash.h"
50 #endif
51 #include "rr-iter.h"
52 #include "anchor.h"
53 #include "tls.h"
54 
55 struct getdns_dns_req;
56 struct ub_ctx;
57 
58 enum filechgs { GETDNS_FCHG_ERRORS = -1
59  , GETDNS_FCHG_NOERROR   = 0
60  , GETDNS_FCHG_NOCHANGES = 0
61  , GETDNS_FCHG_MTIME     = 1
62  , GETDNS_FCHG_CTIME     = 2};
63 
64 /** function pointer typedefs */
65 typedef void (*getdns_update_callback) (struct getdns_context *,
66     getdns_context_code_t);
67 
68 typedef void (*getdns_update_callback2) (struct getdns_context *,
69     getdns_context_code_t, void *userarg);
70 
71 /* internal use only for detecting changes to system files */
72 struct filechg {
73 	char fn[_GETDNS_PATH_MAX];
74 	int  changes;
75 	int  errors;
76 	struct stat prevstat;
77 };
78 
79 typedef enum getdns_tls_hs_state {
80 	GETDNS_HS_NONE,
81 	GETDNS_HS_WRITE,
82 	GETDNS_HS_READ,
83 	GETDNS_HS_DONE,
84 	GETDNS_HS_FAILED
85 } getdns_tls_hs_state_t;
86 
87 typedef enum getdns_conn_state {
88 	GETDNS_CONN_CLOSED,
89 	GETDNS_CONN_SETUP,
90 	GETDNS_CONN_OPEN,
91 	GETDNS_CONN_TEARDOWN,
92 	GETDNS_CONN_BACKOFF
93 } getdns_conn_state_t;
94 
95 typedef enum getdns_tasrc {
96 	GETDNS_TASRC_NONE,
97 	GETDNS_TASRC_ZONE,
98 	GETDNS_TASRC_APP,
99 	GETDNS_TASRC_FETCHING,
100 	GETDNS_TASRC_XML,
101 	GETDNS_TASRC_XML_UPDATE,
102 	GETDNS_TASRC_FAILED
103 } getdns_tasrc;
104 
105 typedef enum getdns_tsig_algo {
106 	GETDNS_NO_TSIG     = 0, /* Do not use tsig */
107 	GETDNS_HMAC_MD5    = 1, /* 128 bits */
108 	GETDNS_GSS_TSIG    = 2, /* Not supported */
109 	GETDNS_HMAC_SHA1   = 3, /* 160 bits */
110 	GETDNS_HMAC_SHA224 = 4,
111 	GETDNS_HMAC_SHA256 = 5,
112 	GETDNS_HMAC_SHA384 = 6,
113 	GETDNS_HMAC_SHA512 = 7
114 } getdns_tsig_algo;
115 
116 
117 typedef struct getdns_tsig_info {
118 	getdns_tsig_algo  alg;
119 	const char       *name;
120 	size_t            strlen_name;
121 	const uint8_t    *dname;
122 	size_t            dname_len;
123 	size_t            min_size; /* in # octets */
124 	size_t            max_size; /* Actual size in # octets */
125 } getdns_tsig_info;
126 
127 const getdns_tsig_info *_getdns_get_tsig_info(getdns_tsig_algo tsig_alg);
128 
129 /* for doing public key pinning of TLS-capable upstreams: */
130 typedef struct sha256_pin {
131 	uint8_t pin[SHA256_DIGEST_LENGTH];
132 	struct sha256_pin *next;
133 } sha256_pin_t;
134 
135 typedef struct getdns_upstream {
136 	/* backpointer to containing upstreams structure */
137 	struct getdns_upstreams *upstreams;
138 
139 	socklen_t                addr_len;
140 	struct sockaddr_storage  addr;
141 	char                     addr_str[INET6_ADDRSTRLEN];
142 
143 	/**
144 	 * How is this upstream doing over UDP?
145 	 *
146 	 * to_retry = 1, back_off = 1, in context.c:upstream_init()
147 	 *
148 	 * When querying over UDP, first a upstream is selected which to_retry
149 	 * value > 0 in stub.c:upstream_select().
150 	 *
151 	 * Every time a udp request times out, to_retry is decreased, and if
152 	 * it reaches 0, it is set to minus back_off in
153 	 * stub.c:stub_next_upstream().
154 	 *
155 	 * to_retry will become > 0 again. because each time an upstream is
156 	 * selected for a UDP query in stub.c:upstream_select(), all to_retry
157 	 * counters <= 0 are incremented.
158 	 *
159 	 * On continuous failure, the stubs are less likely to be reselected,
160 	 * because each time to_retry is set to minus back_off, in
161 	 * stub.c:stub_next_upstream(), the back_off value is doubled.
162 	 *
163 	 * Finally, if all upstreams are failing, the upstreams with the
164 	 * smallest back_off value will be selected, and the back_off value
165 	 * decremented by one.
166 	 */
167 	int                      to_retry;  /* (initialized to 1) */
168 	int                      back_off;  /* (initialized to 1) */
169 	size_t                   udp_responses;
170 	size_t                   udp_timeouts;
171 
172 	/* For stateful upstreams, need to share the connection and track the
173 	   activity on the connection */
174 	int                      fd;
175 	getdns_transport_list_t  transport;
176 	getdns_eventloop_event   event;
177 	getdns_eventloop        *loop;
178 	getdns_tcp_state         tcp;
179 	/* These are running totals or historical info */
180 	size_t                   conn_completed;
181 	size_t                   conn_shutdowns;
182 	size_t                   conn_setup_failed;
183 	time_t                   conn_retry_time;
184 	uint16_t                 conn_backoff_interval;
185 	size_t                   conn_backoffs;
186 	size_t                   total_responses;
187 	size_t                   total_timeouts;
188 	getdns_auth_state_t      best_tls_auth_state;
189 	getdns_auth_state_t      last_tls_auth_state;
190 	/* These are per connection. */
191 	getdns_conn_state_t      conn_state;
192 	size_t                   queries_sent;
193 	size_t                   responses_received;
194 	size_t                   responses_timeouts;
195 	size_t                   keepalive_shutdown;
196 	uint64_t                 keepalive_timeout;
197 	int                      server_keepalive_received;
198 
199 	/* Management of outstanding requests on stateful transports */
200 	getdns_network_req      *write_queue;
201 	getdns_network_req      *write_queue_last;
202 	_getdns_rbtree_t         netreq_by_query_id;
203 
204 	/* TCP specific connection handling*/
205 	unsigned                 tfo_use_sendto  : 1;
206 	/* TLS specific connection handling*/
207 	unsigned                 tls_fallback_ok : 1;
208 	_getdns_tls_connection*  tls_obj;
209 	_getdns_tls_session*     tls_session;
210 	getdns_tls_hs_state_t    tls_hs_state;
211 	getdns_auth_state_t      tls_auth_state;
212 
213 	/* TLS settings */
214 	char                    *tls_cipher_list;
215 	char                    *tls_ciphersuites;
216 	char                    *tls_curves_list;
217 	getdns_tls_version_t     tls_min_version;
218 	getdns_tls_version_t     tls_max_version;
219 
220 	/* Auth credentials */
221 	char                     tls_auth_name[256];
222 	sha256_pin_t            *tls_pubkey_pinset;
223 
224 	/* When requests have been scheduled asynchronously on an upstream
225 	 * that is kept open, and a synchronous call is then done with the
226 	 * upstream before all scheduled requests have been answered, answers
227 	 * for the asynchronous requests may be received on the open upstream.
228 	 * Those cannot be processed immediately, because then asynchronous
229 	 * callbacks will be fired as a side-effect.
230 	 *
231 	 * finished_dnsreqs is a list of dnsreqs for which answers have been
232 	 * received during a synchronous request.  They will be processed
233 	 * when the asynchronous eventloop is run.  For this the finished_event
234 	 * will be scheduled to the registered asynchronous event loop with a
235 	 * timeout of 1, so it will fire immediately (but not while scheduling)
236 	 * when the asynchronous eventloop is run.
237 	 */
238 	getdns_dns_req          *finished_dnsreqs;
239 	getdns_eventloop_event   finished_event;
240 	unsigned is_sync_loop : 1;
241 
242 	/* EDNS cookies */
243 	uint32_t secret;
244 	uint8_t  client_cookie[8];
245 	uint8_t  prev_client_cookie[8];
246 	uint8_t  server_cookie[32];
247 
248 	unsigned has_client_cookie : 1;
249 	unsigned has_prev_client_cookie : 1;
250 	unsigned has_server_cookie : 1;
251 	unsigned server_cookie_len : 5;
252 
253 	/* TSIG */
254 	uint8_t          tsig_dname[256];
255 	size_t           tsig_dname_len;
256 	size_t           tsig_size;
257 	uint8_t          tsig_key[256];
258 	getdns_tsig_algo tsig_alg;
259 
260 } getdns_upstream;
261 
262 typedef struct getdns_log_config {
263 	getdns_logfunc_type  func;
264 	void                *userarg;
265 	uint64_t             system;
266 	getdns_loglevel_type level;
267 } getdns_log_config;
268 
269 typedef struct getdns_upstreams {
270 	struct mem_funcs mf;
271 	size_t referenced;
272 	size_t count;
273 	size_t current_udp;
274 	size_t current_stateful;
275 	uint16_t max_backoff_value;
276 	uint16_t tls_backoff_time;
277 	uint16_t tls_connection_retries;
278 	getdns_log_config log;
279 	getdns_upstream upstreams[];
280 } getdns_upstreams;
281 
282 typedef enum tas_state {
283 	TAS_LOOKUP_ADDRESSES = 0,
284 	TAS_WRITE_GET_XML,
285 	TAS_READ_XML_HDR,
286 	TAS_READ_XML_DOC,
287 	TAS_WRITE_GET_PS7,
288 	TAS_READ_PS7_HDR,
289 	TAS_READ_PS7_DOC,
290 	TAS_DONE,
291 	TAS_RETRY,
292 	TAS_RETRY_GET_PS7,
293 	TAS_RETRY_PS7_HDR,
294 	TAS_RETRY_PS7_DOC,
295 	TAS_RETRY_DONE
296 } tas_state;
297 
298 typedef enum _getdns_property {
299 	PROP_INHERIT =  0,
300 	PROP_UNKNOWN =  1,
301 	PROP_UNABLE  =  2,
302 	PROP_ABLE    =  3
303 } _getdns_property;
304 
305 typedef struct tas_connection {
306 	getdns_eventloop       *loop;
307 	getdns_network_req     *req;
308 	_getdns_rrset_spc       rrset_spc;
309 	_getdns_rrset          *rrset;
310 	_getdns_rrtype_iter     rr_spc;
311 	_getdns_rrtype_iter    *rr;
312 	int                    fd;
313 	getdns_eventloop_event event;
314 	tas_state              state;
315 	getdns_tcp_state       tcp;
316 	char                  *http;
317 	getdns_bindata         xml;
318 } tas_connection;
319 
320 struct getdns_context {
321 	/* Context values */
322 	getdns_resolution_t  resolution_type;
323 	getdns_namespace_t   *namespaces;
324 	size_t               namespace_count;
325 	uint64_t             timeout;
326 	uint64_t             idle_timeout;
327 	getdns_redirects_t   follow_redirects;
328 	getdns_list          *dns_root_servers;
329 
330 #if defined(HAVE_LIBUNBOUND) && !defined(HAVE_UB_CTX_SET_STUB)
331 	char                 root_servers_fn[FILENAME_MAX];
332 #endif
333 	getdns_append_name_t append_name;
334 	/* Suffix buffer containing a list of (length byte | dname) where
335 	 * length bytes contains the length of the following dname.
336 	 * The last dname should be the zero byte.
337 	 */
338 	const uint8_t        *suffixes;
339 	/* Length of all suffixes in the suffix buffer */
340 	size_t               suffixes_len;
341 
342 	uint8_t              *trust_anchors;
343 	size_t                trust_anchors_len;
344 	getdns_tasrc          trust_anchors_source;
345 
346 	tas_connection        a;
347 	tas_connection        aaaa;
348 	uint8_t               tas_hdr_spc[512];
349 
350 	char                 *trust_anchors_url;
351 	char                 *trust_anchors_verify_CA;
352 	char                 *trust_anchors_verify_email;
353 	uint64_t              trust_anchors_backoff_time;
354 	uint64_t              trust_anchors_backoff_expiry;
355 
356 	_getdns_ksks          root_ksk;
357 
358 	char                 *appdata_dir;
359 	_getdns_property      can_write_appdata;
360 
361 	char                 *tls_ca_path;
362 	char                 *tls_ca_file;
363 	char                 *tls_cipher_list;
364 	char                 *tls_ciphersuites;
365 	char                 *tls_curves_list;
366 	getdns_tls_version_t  tls_min_version;
367 	getdns_tls_version_t  tls_max_version;
368 
369 	getdns_upstreams     *upstreams;
370 	uint16_t             limit_outstanding_queries;
371 	uint32_t             dnssec_allowed_skew;
372 	getdns_tls_authentication_t  tls_auth;  /* What user requested for TLS*/
373 	getdns_tls_authentication_t  tls_auth_min; /* Derived minimum auth allowed*/
374 	uint8_t              round_robin_upstreams;
375 	uint16_t             max_backoff_value;
376 	uint16_t             tls_backoff_time;
377 	uint16_t             tls_connection_retries;
378 
379 	getdns_transport_list_t   *dns_transports;
380 	size_t                     dns_transport_count;
381 
382 	uint8_t edns_extended_rcode;
383 	uint8_t edns_version;
384 	uint8_t edns_do_bit;
385 	int edns_maximum_udp_payload_size; /* -1 is unset */
386 	uint8_t edns_client_subnet_private;
387 	uint16_t tls_query_padding_blocksize;
388 	_getdns_tls_context* tls_ctx;
389 
390 	getdns_update_callback  update_callback;
391 	getdns_update_callback2 update_callback2;
392 	void                   *update_userarg;
393 
394 	getdns_log_config log;
395 
396 	int processing;
397 	int destroying;
398 
399 	struct mem_funcs mf;
400 	struct mem_funcs my_mf;
401 
402 #ifdef HAVE_LIBUNBOUND
403 	/* The underlying contexts that do the real work */
404 	struct ub_ctx *unbound_ctx;
405 	int            unbound_ta_set;
406 #ifdef HAVE_UNBOUND_EVENT_API
407 	_getdns_ub_loop ub_loop;
408 #endif
409 #endif
410 	/* A tree to hold local host information*/
411 	_getdns_rbtree_t local_hosts;
412 
413 	/* which resolution type the contexts are configured for
414 	 * 0 means nothing set
415 	 */
416 	getdns_resolution_t resolution_type_set;
417 
418 	/*
419 	 * outbound requests -> transaction to getdns_dns_req
420 	 */
421 	_getdns_rbtree_t outbound_requests;
422 
423 	/* network requests
424 	 */
425 	size_t netreqs_in_flight;
426 
427 	_getdns_rbtree_t       pending_netreqs;
428 	getdns_network_req    *first_pending_netreq;
429 	getdns_eventloop_event pending_timeout_event;
430 
431 	struct listen_set *server;
432 
433 	/* Event loop extension.  */
434 	getdns_eventloop       *extension;
435 
436 #ifdef HAVE_LIBUNBOUND
437 	getdns_eventloop_event  ub_event;
438 	/* lock to prevent nested ub_event scheduling */
439 	int                     ub_event_scheduling;
440 #endif
441 
442 	/* The default extension */
443 	_getdns_default_eventloop default_eventloop;
444 	_getdns_default_eventloop sync_eventloop;
445 
446 	/* request extension defaults */
447 	getdns_dict *header;
448 	getdns_dict *add_opt_parameters;
449 	unsigned add_warning_for_bad_dns             : 1;
450 	unsigned dnssec                              : 1;
451 	unsigned dnssec_return_all_statuses          : 1;
452 	unsigned dnssec_return_full_validation_chain : 1;
453 	unsigned dnssec_return_only_secure           : 1;
454 	unsigned dnssec_return_status                : 1;
455 	unsigned dnssec_return_validation_chain      : 1;
456 #ifdef DNSSEC_ROADBLOCK_AVOIDANCE
457 	unsigned dnssec_roadblock_avoidance          : 1;
458 #endif
459 	unsigned edns_cookies                        : 1;
460 	unsigned return_api_information              : 1; /* Not used */
461 	unsigned return_both_v4_and_v6               : 1;
462 	unsigned return_call_reporting               : 1;
463 	uint16_t specify_class;
464 
465 	/*
466 	 * Context for doing system queries.
467 	 * For example to resolve data.iana.org or to resolver the addresses
468 	 * of upstreams without specified addresses.
469 	 */
470 	getdns_context *sys_ctxt;
471 
472 	/* List of dnsreqs that want to be notified when we have fetched a
473 	 * trust anchor from data.iana.org.
474 	 */
475 	getdns_dns_req *ta_notify;
476 
477 	/*
478 	 * state data used to detect changes to the system config files
479 	 */
480 	struct filechg fchg_resolvconf;
481 	struct filechg fchg_hosts;
482 
483 	uint8_t trust_anchors_spc[1024];
484 
485 #ifdef USE_WINSOCK
486 	/* We need to run WSAStartup() to be able to use getaddrinfo() */
487 	WSADATA wsaData;
488 #endif
489 
490 	/* MDNS */
491 #ifdef HAVE_MDNS_SUPPORT
492 	/*
493 	 * If supporting MDNS, context may be instantiated either in basic mode
494 	 * or in full mode. If working in extended mode, two multicast sockets are
495 	 * left open, for IPv4 and IPv6. Data can be received on either socket.
496 	 * The context also keeps a list of open queries, characterized by a
497 	 * name and an RR type, and a list of received answers, characterized
498 	 * by name, RR type and data value.
499 	 */
500 	int mdns_extended_support; /* 0 = no support, 1 = supported, 2 = initialization needed */
501 	int mdns_connection_nb; /* typically 0 or 2 for IPv4 and IPv6 */
502 	struct mdns_network_connection * mdns_connection;
503 	struct lruhash * mdns_cache;
504 
505 #endif /* HAVE_MDNS_SUPPORT */
506 }; /* getdns_context */
507 
_getdns_check_log(const getdns_log_config * log,uint64_t system,getdns_loglevel_type level)508 static inline int _getdns_check_log(const getdns_log_config *log,
509     uint64_t system, getdns_loglevel_type level)
510 { assert(log)
511 ; return log->func && (log->system & system) && level <= log->level; }
512 
_getdns_log(const getdns_log_config * log,uint64_t system,getdns_loglevel_type level,const char * fmt,...)513 static inline void _getdns_log(const getdns_log_config *log,
514     uint64_t system, getdns_loglevel_type level, const char *fmt, ...)
515 {
516 	va_list args;
517 
518 	if (!_getdns_check_log(log, system, level))
519 		return;
520 
521 	va_start(args, fmt);
522 	log->func(log->userarg, system, level, fmt, args);
523 	va_end(args);
524 }
525 
_getdns_upstream_log(const getdns_upstream * up,uint64_t system,getdns_loglevel_type level,const char * fmt,...)526 static inline void _getdns_upstream_log(const getdns_upstream *up,
527     uint64_t system, getdns_loglevel_type level, const char *fmt, ...)
528 {
529 	va_list args;
530 
531 	if (!up || !up->upstreams
532 	||  !_getdns_check_log(&up->upstreams->log, system, level))
533 		return;
534 
535 	va_start(args, fmt);
536 	up->upstreams->log.func(
537 	    up->upstreams->log.userarg, system, level, fmt, args);
538 	va_end(args);
539 }
540 
541 
542 /** internal functions **/
543 /**
544  * Sets up the unbound contexts with stub or recursive behavior
545  * if needed.
546  * @param context previously initialized getdns_context
547  * @return GETDNS_RETURN_GOOD on success
548  */
549 getdns_return_t _getdns_context_prepare_for_resolution(getdns_context *context);
550 
551 /* Register a getdns_dns_req with context.
552  * - Without pluggable unbound event API,
553  *   ub_fd() is scheduled when this was the first request.
554  */
555 void _getdns_context_track_outbound_request(getdns_dns_req *dnsreq);
556 
557 /* Deregister getdns_dns_req from the context.
558  * - Without pluggable unbound event API,
559  *   ub_fd() is scheduled when this was the first request.
560  * - Potential timeout events will be cleared.
561  * - All associated getdns_dns_reqs (to get the validation chain)
562  *   will be canceled.
563  */
564 void _getdns_context_clear_outbound_request(getdns_dns_req *dnsreq);
565 
566 /* Cancels and frees a getdns_dns_req (without calling user callbacks)
567  * - Deregisters getdns_dns_req with _getdns_context_clear_outbound_request()
568  * - Cancels associated getdns_network_reqs
569  *   (by calling ub_cancel() or _getdns_cancel_stub_request())
570  * - Frees the getdns_dns_req
571  */
572 void _getdns_context_cancel_request(getdns_dns_req *dnsreq);
573 
574 /* Calls user callback (with GETDNS_CALLBACK_TIMEOUT + response dict), then
575  * cancels and frees the getdns_dns_req with _getdns_context_cancel_request()
576  */
577 void _getdns_context_request_timed_out(getdns_dns_req *dnsreq);
578 
579 struct getdns_bindata *_getdns_bindata_copy(
580     struct mem_funcs *mfs, size_t size, const uint8_t *data);
581 
582 void _getdns_bindata_destroy(
583     struct mem_funcs *mfs,
584     struct getdns_bindata *bindata);
585 
586 /* perform name resolution in /etc/hosts */
587 getdns_return_t _getdns_context_local_namespace_resolve(
588     getdns_dns_req* req, struct getdns_dict **response);
589 
590 void _getdns_context_ub_read_cb(void *userarg);
591 
592 void _getdns_upstreams_dereference(getdns_upstreams *upstreams);
593 
594 void _getdns_upstream_shutdown(getdns_upstream *upstream);
595 
596 FILE *_getdns_context_get_priv_fp(
597     const getdns_context *context, const char *fn);
598 uint8_t *_getdns_context_get_priv_file(const getdns_context *context,
599     const char *fn, uint8_t *buf, size_t buf_len, size_t *file_sz);
600 
601 int _getdns_context_write_priv_file(getdns_context *context,
602     const char *fn, getdns_bindata *content);
603 
604 int _getdns_context_can_write_appdata(getdns_context *context);
605 
606 getdns_context *_getdns_context_get_sys_ctxt(
607     getdns_context *context, getdns_eventloop *loop);
608 
609 #endif /* _GETDNS_CONTEXT_H_ */
610