summaryrefslogtreecommitdiff
path: root/usr.sbin/unbound/services/authzone.h
blob: 07614ed82963d33b37891b20a781db318be2843a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
/*
 * services/authzone.h - authoritative zone that is locally hosted.
 *
 * Copyright (c) 2017, NLnet Labs. All rights reserved.
 *
 * This software is open source.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * 
 * Neither the name of the NLNET LABS nor the names of its contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * \file
 *
 * This file contains the functions for an authority zone.  This zone
 * is queried by the iterator, just like a stub or forward zone, but then
 * the data is locally held.
 */

#ifndef SERVICES_AUTHZONE_H
#define SERVICES_AUTHZONE_H
#include "util/rbtree.h"
#include "util/locks.h"
#include "services/mesh.h"
#include "services/rpz.h"
struct ub_packed_rrset_key;
struct regional;
struct config_file;
struct config_auth;
struct query_info;
struct dns_msg;
struct edns_data;
struct module_env;
struct worker;
struct comm_point;
struct comm_timer;
struct comm_reply;
struct auth_rrset;
struct auth_nextprobe;
struct auth_probe;
struct auth_transfer;
struct auth_master;
struct auth_chunk;

/**
 * Authoritative zones, shared.
 */
struct auth_zones {
	/** lock on the authzone trees */
	lock_rw_type lock;
	/** rbtree of struct auth_zone */
	rbtree_type ztree;
	/** rbtree of struct auth_xfer */
	rbtree_type xtree;
	/** do we have downstream enabled */
	int have_downstream;
	/** number of queries upstream */
	size_t num_query_up;
	/** number of queries downstream */
	size_t num_query_down;
	/** first auth zone containing rpz item in linked list */
	struct auth_zone* rpz_first;
	/** rw lock for rpz linked list, needed when iterating or editing linked
	 * list. */
	lock_rw_type rpz_lock;
};

/**
 * Auth zone.  Authoritative data, that is fetched from instead of sending
 * packets to the internet.
 */
struct auth_zone {
	/** rbtree node, key is name and class */
	rbnode_type node;

	/** zone name, in uncompressed wireformat */
	uint8_t* name;
	/** length of zone name */
	size_t namelen;
	/** number of labels in zone name */
	int namelabs;
	/** the class of this zone, in host byteorder.
	 * uses 'dclass' to not conflict with c++ keyword class. */
	uint16_t dclass;

	/** lock on the data in the structure
	 * For the node, parent, name, namelen, namelabs, dclass, you
	 * need to also hold the zones_tree lock to change them (or to
	 * delete this zone) */
	lock_rw_type lock;

	/** auth data for this zone
	 * rbtree of struct auth_data */
	rbtree_type data;

	/** zonefile name (or NULL for no zonefile) */
	char* zonefile;
	/** fallback to the internet on failure or ttl-expiry of auth zone */
	int fallback_enabled;
	/** the zone has expired (enabled by the xfer worker), fallback
	 * happens if that option is enabled. */
	int zone_expired;
	/** zone is a slave zone (it has masters) */
	int zone_is_slave;
	/** for downstream: this zone answers queries towards the downstream
	 * clients */
	int for_downstream;
	/** for upstream: this zone answers queries that unbound intends to
	 * send upstream. */
	int for_upstream;
	/** check ZONEMD records */
	int zonemd_check;
	/** reject absence of ZONEMD records */
	int zonemd_reject_absence;
	/** RPZ zones */
	struct rpz* rpz;
	/** store the env (worker thread specific) for the zonemd callbacks
	 * from the mesh with the results of the lookup, if nonNULL, some
	 * worker has already picked up the zonemd verification task and
	 * this worker does not have to do it as well. */
	struct module_env* zonemd_callback_env;
	/** for the zonemd callback, the type of data looked up */
	uint16_t zonemd_callback_qtype;
	/** zone has been deleted */
	int zone_deleted;
	/** deletelist pointer, unused normally except during delete */
	struct auth_zone* delete_next;
	/* not protected by auth_zone lock, must be last items in struct */
	/** next auth zone containing RPZ data, or NULL */
	struct auth_zone* rpz_az_next;
	/** previous auth zone containing RPZ data, or NULL */
	struct auth_zone* rpz_az_prev;
};

/**
 * Auth data. One domain name, and the RRs to go with it.
 */
struct auth_data {
	/** rbtree node, key is name only */
	rbnode_type node;
	/** domain name */
	uint8_t* name;
	/** length of name */
	size_t namelen;
	/** number of labels in name */
	int namelabs;
	/** the data rrsets, with different types, linked list.
	 * if the list if NULL the node would be an empty non-terminal,
	 * but in this data structure such nodes that represent an empty
	 * non-terminal are not needed; they just don't exist.
	 */
	struct auth_rrset* rrsets;
};

/**
 * A auth data RRset
 */
struct auth_rrset {
	/** next in list */
	struct auth_rrset* next;
	/** RR type in host byteorder */
	uint16_t type;
	/** RRset data item */
	struct packed_rrset_data* data;
};

/**
 * Authoritative zone transfer structure.
 * Create and destroy needs the auth_zones* biglock.
 * The structure consists of different tasks.  Each can be unowned (-1) or
 * owner by a worker (worker-num).  A worker can pick up a task and then do
 * it.  This means the events (timeouts, sockets) are for that worker.
 * 
 * (move this to tasks).
 * They don't have locks themselves, the worker (that owns it) uses it,
 * also as part of callbacks, hence it has separate zonename pointers for
 * lookup in the main zonetree.  If the zone has no transfers, this
 * structure is not created.
 */
struct auth_xfer {
	/** rbtree node, key is name and class */
	rbnode_type node;

	/** lock on this structure, and on the workernum elements of the
	 * tasks.  First hold the tree-lock in auth_zones, find the auth_xfer,
	 * lock this lock.  Then a worker can reassign itself to fill up
	 * one of the tasks. 
	 * Once it has the task assigned to it, the worker can access the
	 * other elements of the task structure without a lock, because that
	 * is necessary for the eventloop and callbacks from that. */
	lock_basic_type lock;

	/** zone name, in uncompressed wireformat */
	uint8_t* name;
	/** length of zone name */
	size_t namelen;
	/** number of labels in zone name */
	int namelabs;
	/** the class of this zone, in host byteorder.
	 * uses 'dclass' to not conflict with c++ keyword class. */
	uint16_t dclass;

	/** task to wait for next-probe-timeout,
	 * once timeouted, see if a SOA probe is needed, or already
	 * in progress */
	struct auth_nextprobe* task_nextprobe;

	/** task for SOA probe.  Check if the zone can be updated */
	struct auth_probe* task_probe;

	/** Task for transfer.  Transferring and updating the zone.  This
	 * includes trying (potentially) several upstream masters.  Downloading
	 * and storing the zone */
	struct auth_transfer* task_transfer;

	/** a notify was received, but a zone transfer or probe was already
	 * acted on.
	 * However, the zone transfer could signal a newer serial number.
	 * The serial number of that notify is saved below.  The transfer and
	 * probe tasks should check this once done to see if they need to
	 * restart the transfer task for the newer notify serial.
	 * Hold the lock to access this member (and the serial).
	 */
	int notify_received;
	/** true if the notify_received has a serial number */
	int notify_has_serial;
	/** serial number of the notify */
	uint32_t notify_serial;
	/** the list of masters for checking notifies.  This list is
	 * empty on start, and a copy of the list from the probe_task when
	 * it is done looking them up. */
	struct auth_master* allow_notify_list;

	/* protected by the lock on the structure, information about
	 * the loaded authority zone. */
	/** is the zone currently considered expired? after expiry also older
         * serial numbers are allowed (not just newer) */
	int zone_expired;
	/** do we have a zone (if 0, no zone data at all) */
	int have_zone;

	/** current serial (from SOA), if we have no zone, 0 */
	uint32_t serial;
	/** retry time (from SOA), time to wait with next_probe
	 * if no master responds */
	time_t retry;
	/** refresh time (from SOA), time to wait with next_probe
	 * if everything is fine */
	time_t refresh;
	/** expiry time (from SOA), time until zone data is not considered
	 * valid any more, if no master responds within this time, either
	 * with the current zone or a new zone. */
	time_t expiry;

	/** zone lease start time (start+expiry is expiration time).
	 * this is renewed every SOA probe and transfer.  On zone load
	 * from zonefile it is also set (with probe set soon to check) */
	time_t lease_time;
};

/**
 * The next probe task.
 * This task consists of waiting for the probetimeout.  It is a task because
 * it needs an event in the eventtable.  Once the timeout has passed, that
 * worker can (potentially) become the auth_probe worker, or if another worker
 * is already doing that, do nothing.  Tasks becomes unowned.
 * The probe worker, if it detects nothing has to be done picks up this task,
 * if unowned.
 */
struct auth_nextprobe {
	/* Worker pointer. NULL means unowned. */
	struct worker* worker;
	/* module env for this task */
	struct module_env* env;

	/** increasing backoff for failures */
	time_t backoff;
	/** Timeout for next probe (for SOA) */
	time_t next_probe;
	/** timeout callback for next_probe or expiry(if that is sooner).
	 * it is on the worker's event_base */
	struct comm_timer* timer;
};

/**
 * The probe task.
 * Send a SOA UDP query to see if the zone needs to be updated (or similar,
 * potential, HTTP probe query) and check serial number.
 * If yes, start the auth_transfer task.  If no, make sure auth_nextprobe
 * timeout wait task is running.
 * Needs to be a task, because the UDP query needs an event entry.
 * This task could also be started by eg. a NOTIFY being received, even though
 * another worker is performing the nextprobe task (and that worker keeps
 * waiting uninterrupted).
 */
struct auth_probe {
	/* Worker pointer. NULL means unowned. */
	struct worker* worker;
	/* module env for this task */
	struct module_env* env;

	/** list of upstream masters for this zone, from config */
	struct auth_master* masters;

	/** for the hostname lookups, which master is current */
	struct auth_master* lookup_target;
	/** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */
	int lookup_aaaa;
	/** we only want to do lookups for making config work (for notify),
	 * don't proceed with UDP SOA probe queries */
	int only_lookup;
	/** we have seen a new lease this scan, because one of the masters
	 * replied with the current SOA serial version */
	int have_new_lease;

	/** once notified, or the timeout has been reached. a scan starts. */
	/** the scan specific target (notify source), or NULL if none */
	struct auth_master* scan_specific;
	/** scan tries all the upstream masters. the scan current target. 
	 * or NULL if not working on sequential scan */
	struct auth_master* scan_target;
	/** if not NULL, the specific addr for the current master */
	struct auth_addr* scan_addr;

	/** dns id of packet in flight */
	uint16_t id;
	/** the SOA probe udp event.
	 * on the workers event base. */
	struct comm_point* cp;
	/** is the cp for ip6 or ip4 */
	int cp_is_ip6;
	/** timeout for packets.
	 * on the workers event base. */
	struct comm_timer* timer;
	/** timeout in msec */
	int timeout;
};

/**
 * The transfer task.
 * Once done, make sure the nextprobe waiting task is running, whether done
 * with failure or success.  If failure, use shorter timeout for wait time.
 */
struct auth_transfer {
	/* Worker pointer. NULL means unowned. */
	struct worker* worker;
	/* module env for this task */
	struct module_env* env;

	/** xfer data that has been transferred, the data is applied
	 * once the transfer has completed correctly */
	struct auth_chunk* chunks_first;
	/** last element in chunks list (to append new data at the end) */
	struct auth_chunk* chunks_last;

	/** list of upstream masters for this zone, from config */
	struct auth_master* masters;

	/** for the hostname lookups, which master is current */
	struct auth_master* lookup_target;
	/** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */
	int lookup_aaaa;

	/** once notified, or the timeout has been reached. a scan starts. */
	/** the scan specific target (notify source), or NULL if none */
	struct auth_master* scan_specific;
	/** scan tries all the upstream masters. the scan current target. 
	 * or NULL if not working on sequential scan */
	struct auth_master* scan_target;
	/** what address we are scanning for the master, or NULL if the
	 * master is in IP format itself */
	struct auth_addr* scan_addr;
	/** the zone transfer in progress (or NULL if in scan).  It is
	 * from this master */
	struct auth_master* master;

	/** failed ixfr transfer, retry with axfr (to the current master),
	 * the IXFR was 'REFUSED', 'SERVFAIL', 'NOTIMPL' or the contents of
	 * the IXFR did not apply cleanly (out of sync, delete of nonexistent
	 * data or add of duplicate data).  Flag is cleared once the retry
	 * with axfr is done. */
	int ixfr_fail;
	/** we saw an ixfr-indicating timeout, count of them */
	int ixfr_possible_timeout_count;
	/** we are doing IXFR right now */
	int on_ixfr;
	/** did we detect the current AXFR/IXFR serial number yet, 0 not yet,
	 * 1 we saw the first, 2 we saw the second, 3 must be last SOA in xfr*/
	int got_xfr_serial;
	/** number of RRs scanned for AXFR/IXFR detection */
	size_t rr_scan_num;
	/** we are doing an IXFR but we detected an AXFR contents */
	int on_ixfr_is_axfr;
	/** the serial number for the current AXFR/IXFR incoming reply,
	 * for IXFR, the outermost SOA records serial */
	uint32_t incoming_xfr_serial;

	/** dns id of AXFR query */
	uint16_t id;
	/** the transfer (TCP) to the master.
	 * on the workers event base. */
	struct comm_point* cp;
	/** timeout for the transfer.
	 * on the workers event base. */
	struct comm_timer* timer;
};

/** list of addresses */
struct auth_addr {
	/** next in list */
	struct auth_addr* next;
	/** IP address */
	struct sockaddr_storage addr;
	/** addr length */
	socklen_t addrlen;
};

/** auth zone master upstream, and the config settings for it */
struct auth_master {
	/** next master in list */
	struct auth_master* next;
	/** master IP address (and port), or hostname, string */
	char* host;
	/** for http, filename */
	char* file;
	/** use HTTP for this master */
	int http;
	/** use IXFR for this master */
	int ixfr;
	/** this is an allow notify member, the master can send notifies
	 * to us, but we don't send SOA probes, or zone transfer from it */
	int allow_notify;
	/** use ssl for channel */
	int ssl;
	/** the port number (for urls) */
	int port;
	/** if the host is a hostname, the list of resolved addrs, if any*/
	struct auth_addr* list;
};

/** auth zone master zone transfer data chunk */
struct auth_chunk {
	/** next chunk in list */
	struct auth_chunk* next;
	/** the data from this chunk, this is what was received.
	 * for an IXFR that means results from comm_net tcp actions,
	 * packets. also for an AXFR. For HTTP a zonefile chunk. */
	uint8_t* data;
	/** length of allocated data */
	size_t len;
};

/**
 * Create auth zones structure
 */
struct auth_zones* auth_zones_create(void);

/**
 * Apply configuration to auth zones.  Reads zonefiles.
 * @param az: auth zones structure
 * @param cfg: config to apply.
 * @param setup: if true, also sets up values in the auth zones structure
 * @param is_rpz: set to 1 if at least one RPZ zone is configured.
 * @param env: environment for offline verification.
 * @param mods: modules in environment.
 * @return false on failure.
 */
int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
	int setup, int* is_rpz, struct module_env* env,
	struct module_stack* mods);

/** initial pick up of worker timeouts, ties events to worker event loop
 * @param az: auth zones structure
 * @param env: worker env, of first worker that receives the events (if any)
 * 	in its eventloop.
 */
void auth_xfer_pickup_initial(struct auth_zones* az, struct module_env* env);

/**
 * Cleanup auth zones.  This removes all events from event bases.
 * Stops the xfr tasks.  But leaves zone data.
 * @param az: auth zones structure.
 */
void auth_zones_cleanup(struct auth_zones* az);

/**
 * Delete auth zones structure
 */
void auth_zones_delete(struct auth_zones* az);

/**
 * Write auth zone data to file, in zonefile format.
 */
int auth_zone_write_file(struct auth_zone* z, const char* fname);

/**
 * Use auth zones to lookup the answer to a query.
 * The query is from the iterator.  And the auth zones attempts to provide
 * the answer instead of going to the internet.
 *
 * @param az: auth zones structure.
 * @param qinfo: query info to lookup.
 * @param region: region to use to allocate the reply in.
 * @param msg: reply is stored here (if one).
 * @param fallback: if true, fallback to making a query to the internet.
 * @param dp_nm: name of delegation point to look for.  This zone is used
 *	to answer the query.
 *	If the dp_nm is not found, fallback is set to true and false returned.
 * @param dp_nmlen: length of dp_nm.
 * @return 0: failure (an error of some sort, like servfail).
 *         if 0 and fallback is true, fallback to the internet.
 *         if 0 and fallback is false, like getting servfail.
 *         If true, an answer is available.
 */
int auth_zones_lookup(struct auth_zones* az, struct query_info* qinfo,
	struct regional* region, struct dns_msg** msg, int* fallback,
	uint8_t* dp_nm, size_t dp_nmlen);

/**
 * Answer query from auth zone.  Create authoritative answer.
 * @param az: auth zones structure.
 * @param env: the module environment.
 * @param qinfo: query info (parsed).
 * @param edns: edns info (parsed).
 * @param buf: buffer with query ID and flags, also for reply.
 * @param repinfo: reply information for a communication point.
 * @param temp: temporary storage region.
 * @return false if not answered
 */
int auth_zones_answer(struct auth_zones* az, struct module_env* env,
	struct query_info* qinfo, struct edns_data* edns,
	struct comm_reply* repinfo, struct sldns_buffer* buf, struct regional* temp);

/** 
 * Find the auth zone that is above the given qname.
 * Return NULL when there is no auth_zone above the give name, otherwise
 * returns the closest auth_zone above the qname that pertains to it.
 * @param az: auth zones structure.
 * @param name: query to look up for.
 * @param name_len: length of name.
 * @param dclass: class of zone to find.
 * @return NULL or auth_zone that pertains to the query.
 */
struct auth_zone* auth_zones_find_zone(struct auth_zones* az,
	uint8_t* name, size_t name_len, uint16_t dclass);

/** find an auth zone by name (exact match by name or NULL returned) */
struct auth_zone* auth_zone_find(struct auth_zones* az, uint8_t* nm,
	size_t nmlen, uint16_t dclass);

/** find an xfer zone by name (exact match by name or NULL returned) */
struct auth_xfer* auth_xfer_find(struct auth_zones* az, uint8_t* nm,
	size_t nmlen, uint16_t dclass);

/** create an auth zone. returns wrlocked zone. caller must have wrlock
 * on az. returns NULL on malloc failure */
struct auth_zone* auth_zone_create(struct auth_zones* az, uint8_t* nm,
	size_t nmlen, uint16_t dclass);

/** set auth zone zonefile string. caller must have lock on zone */
int auth_zone_set_zonefile(struct auth_zone* z, char* zonefile);

/** set auth zone fallback. caller must have lock on zone.
 * fallbackstr is "yes" or "no". false on parse failure. */
int auth_zone_set_fallback(struct auth_zone* z, char* fallbackstr);

/** see if the auth zone for the name can fallback
 * @param az: auth zones
 * @param nm: name of delegation point.
 * @param nmlen: length of nm.
 * @param dclass: class of zone to look for.
 * @return true if fallback_enabled is true. false if not.
 * if the zone does not exist, fallback is true (more lenient)
 * also true if zone does not do upstream requests.
 */
int auth_zones_can_fallback(struct auth_zones* az, uint8_t* nm, size_t nmlen,
	uint16_t dclass);

/** process notify for auth zones.
 * first checks the access list.  Then processes the notify. This starts
 * the probe sequence or it notes the serial number (if any)
 * @param az: auth zones structure.
 * @param env: module env of the worker that is handling the notify. it will
 * 	pick up the task probe (or transfer), unless already in progress by
 * 	another worker.
 * @param nm: name of the zone.  Uncompressed. from query.
 * @param nmlen: length of name.
 * @param dclass: class of zone.
 * @param addr: source address of notify
 * @param addrlen: length of addr.
 * @param has_serial: if true, the notify has a serial attached.
 * @param serial: the serial number, if has_serial is true.
 * @param refused: is set to true on failure to note refused access.
 * @return fail on failures (refused is false) and when access is
 * 	denied (refused is true).  True when processed.
 */
int auth_zones_notify(struct auth_zones* az, struct module_env* env,
	uint8_t* nm, size_t nmlen, uint16_t dclass,
	struct sockaddr_storage* addr, socklen_t addrlen, int has_serial,
	uint32_t serial, int* refused);

/** process notify packet and read serial number from SOA.
 * returns 0 if no soa record in the notify */
int auth_zone_parse_notify_serial(struct sldns_buffer* pkt, uint32_t *serial);

/** for the zone and if not already going, starts the probe sequence.
 * false if zone cannot be found.  This is like a notify arrived and was
 * accepted for that zone. */
int auth_zones_startprobesequence(struct auth_zones* az,
	struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t dclass);

/** read auth zone from zonefile. caller must lock zone. false on failure */
int auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg);

/** find the apex SOA RRset, if it exists. NULL if no SOA RRset. */
struct auth_rrset* auth_zone_get_soa_rrset(struct auth_zone* z);

/** find serial number of zone or false if none (no SOA record) */
int auth_zone_get_serial(struct auth_zone* z, uint32_t* serial);

/** Find auth_zone SOA and populate the values in xfr(soa values). */
int xfr_find_soa(struct auth_zone* z, struct auth_xfer* xfr);

/** compare auth_zones for sorted rbtree */
int auth_zone_cmp(const void* z1, const void* z2);

/** compare auth_data for sorted rbtree */
int auth_data_cmp(const void* z1, const void* z2);

/** compare auth_xfer for sorted rbtree */
int auth_xfer_cmp(const void* z1, const void* z2);

/** Create auth_xfer structure.
 * Caller must have wrlock on az. Returns locked xfer zone.
 * @param az: zones structure.
 * @param z: zone with name and class
 * @return xfer zone or NULL
 */
struct auth_xfer* auth_xfer_create(struct auth_zones* az, struct auth_zone* z);

/**
 * Set masters in auth xfer structure from config.
 * @param list: pointer to start of list.  The malloced list is returned here.
 * @param c: the config items to copy over.
 * @param with_http: if true, http urls are also included, before the masters.
 * @return false on failure.
 */
int xfer_set_masters(struct auth_master** list, struct config_auth* c,
	int with_http);

/** xfer nextprobe timeout callback, this is part of task_nextprobe */
void auth_xfer_timer(void* arg);

/** callback for commpoint udp replies to task_probe */
int auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err,
        struct comm_reply* repinfo);
/** callback for task_transfer tcp connections */
int auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err,
        struct comm_reply* repinfo);
/** callback for task_transfer http connections */
int auth_xfer_transfer_http_callback(struct comm_point* c, void* arg, int err,
        struct comm_reply* repinfo);
/** xfer probe timeout callback, part of task_probe */
void auth_xfer_probe_timer_callback(void* arg);
/** xfer transfer timeout callback, part of task_transfer */
void auth_xfer_transfer_timer_callback(void* arg);
/** mesh callback for task_probe on lookup of host names */
void auth_xfer_probe_lookup_callback(void* arg, int rcode,
	struct sldns_buffer* buf, enum sec_status sec, char* why_bogus,
	int was_ratelimited);
/** mesh callback for task_transfer on lookup of host names */
void auth_xfer_transfer_lookup_callback(void* arg, int rcode,
	struct sldns_buffer* buf, enum sec_status sec, char* why_bogus,
	int was_ratelimited);

/*
 * Compares two 32-bit serial numbers as defined in RFC1982.  Returns
 * <0 if a < b, 0 if a == b, and >0 if a > b.  The result is undefined
 * if a != b but neither is greater or smaller (see RFC1982 section
 * 3.2.).
 */
int compare_serial(uint32_t a, uint32_t b);

/**
 * Generate ZONEMD digest for the auth zone.
 * @param z: the auth zone to digest.
 * 	omits zonemd at apex and its RRSIG from the digest.
 * @param scheme: the collation scheme to use.  Numbers as defined for ZONEMD.
 * @param hashalgo: the hash algo, from the registry defined for ZONEMD type.
 * @param hash: the result buffer.
 * @param buflen: size of the result buffer, must be large enough. or the
 * 	routine fails.
 * @param resultlen: size of the hash in the result buffer of the result.
 * @param region: temp region for allocs during canonicalisation.
 * @param buf: temp buffer during canonicalisation.
 * @param reason: failure reason, returns a string, NULL on success.
 * @return false on failure.
 */
int auth_zone_generate_zonemd_hash(struct auth_zone* z, int scheme,
	int hashalgo, uint8_t* hash, size_t buflen, size_t* resultlen,
	struct regional* region, struct sldns_buffer* buf, char** reason);

/** ZONEMD scheme definitions */
#define ZONEMD_SCHEME_SIMPLE 1

/** ZONEMD hash algorithm definition for SHA384 */
#define ZONEMD_ALGO_SHA384 1
/** ZONEMD hash algorithm definition for SHA512 */
#define ZONEMD_ALGO_SHA512 2

/** returns true if a zonemd hash algo is supported */
int zonemd_hashalgo_supported(int hashalgo);
/** returns true if a zonemd scheme is supported */
int zonemd_scheme_supported(int scheme);

/**
 * Check ZONEMD digest for the auth zone.
 * @param z: auth zone to digest.
 * @param scheme: zonemd scheme.
 * @param hashalgo: zonemd hash algorithm.
 * @param hash: the hash to check.
 * @param hashlen: length of hash buffer.
 * @param region: temp region for allocs during canonicalisation.
 * @param buf: temp buffer during canonicalisation.
 * @param reason: string returned with failure reason.
 * 	If the hash cannot be checked, but it is allowed, for unknown
 * 	algorithms, the routine returns success, and the reason is nonNULL,
 * 	with the allowance reason.
 * @return false on failure.
 */
int auth_zone_generate_zonemd_check(struct auth_zone* z, int scheme,
	int hashalgo, uint8_t* hash, size_t hashlen, struct regional* region,
	struct sldns_buffer* buf, char** reason);

/**
 * Perform ZONEMD checks and verification for the auth zone.
 * This includes DNSSEC verification if applicable.
 * @param z: auth zone to check.  Caller holds lock. wrlock.
 * @param env: with temp region, buffer and config.
 * @param mods: module stack for validator env.
 * @param result: if not NULL, result string strdupped in here.
 * @param offline: if true, there is no spawned lookup when online is needed.
 * 	Those zones are skipped for ZONEMD checking.
 * @param only_online: if true, only for ZONEMD that need online lookup
 * 	of DNSKEY chain of trust are processed.
 */
void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
	struct module_stack* mods, char** result, int offline,
	int only_online);

/** mesh callback for zonemd on lookup of dnskey */
void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode,
	struct sldns_buffer* buf, enum sec_status sec, char* why_bogus,
	int was_ratelimited);

/**
 * Check the ZONEMD records that need online DNSSEC chain lookups,
 * for them spawn the lookup process to get it checked out.
 * Attaches the lookup process to the worker event base and mesh state.
 * @param az: auth zones, every zones is checked.
 * @param env: env of the worker where the task is attached.
 */
void auth_zones_pickup_zonemd_verify(struct auth_zones* az,
	struct module_env* env);

#endif /* SERVICES_AUTHZONE_H */