1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*! \file */
15 
16 /***
17  *** Imports
18  ***/
19 
20 #include <inttypes.h>
21 
22 #include <isc/string.h>
23 #include <isc/util.h>
24 
25 #include <dns/db.h>
26 #include <dns/dbiterator.h>
27 #include <dns/rdata.h>
28 #include <dns/rdataset.h>
29 #include <dns/rdatasetiter.h>
30 #include <dns/result.h>
31 #include <dns/rriterator.h>
32 
33 /***
34  *** RRiterator methods
35  ***/
36 
37 isc_result_t
dns_rriterator_init(dns_rriterator_t * it,dns_db_t * db,dns_dbversion_t * ver,isc_stdtime_t now)38 dns_rriterator_init(dns_rriterator_t *it, dns_db_t *db, dns_dbversion_t *ver,
39 		    isc_stdtime_t now) {
40 	isc_result_t result;
41 	it->magic = RRITERATOR_MAGIC;
42 	it->db = db;
43 	it->dbit = NULL;
44 	it->ver = ver;
45 	it->now = now;
46 	it->node = NULL;
47 	result = dns_db_createiterator(it->db, 0, &it->dbit);
48 	if (result != ISC_R_SUCCESS) {
49 		return (result);
50 	}
51 	it->rdatasetit = NULL;
52 	dns_rdata_init(&it->rdata);
53 	dns_rdataset_init(&it->rdataset);
54 	dns_fixedname_init(&it->fixedname);
55 	INSIST(!dns_rdataset_isassociated(&it->rdataset));
56 	it->result = ISC_R_SUCCESS;
57 	return (it->result);
58 }
59 
60 isc_result_t
dns_rriterator_first(dns_rriterator_t * it)61 dns_rriterator_first(dns_rriterator_t *it) {
62 	REQUIRE(VALID_RRITERATOR(it));
63 	/* Reset state */
64 	if (dns_rdataset_isassociated(&it->rdataset)) {
65 		dns_rdataset_disassociate(&it->rdataset);
66 	}
67 	if (it->rdatasetit != NULL) {
68 		dns_rdatasetiter_destroy(&it->rdatasetit);
69 	}
70 	if (it->node != NULL) {
71 		dns_db_detachnode(it->db, &it->node);
72 	}
73 	it->result = dns_dbiterator_first(it->dbit);
74 
75 	/*
76 	 * The top node may be empty when out of zone glue exists.
77 	 * Walk the tree to find the first node with data.
78 	 */
79 	while (it->result == ISC_R_SUCCESS) {
80 		it->result = dns_dbiterator_current(
81 			it->dbit, &it->node,
82 			dns_fixedname_name(&it->fixedname));
83 		if (it->result != ISC_R_SUCCESS) {
84 			return (it->result);
85 		}
86 
87 		it->result = dns_db_allrdatasets(it->db, it->node, it->ver,
88 						 it->now, &it->rdatasetit);
89 		if (it->result != ISC_R_SUCCESS) {
90 			return (it->result);
91 		}
92 
93 		it->result = dns_rdatasetiter_first(it->rdatasetit);
94 		if (it->result != ISC_R_SUCCESS) {
95 			/*
96 			 * This node is empty. Try next node.
97 			 */
98 			dns_rdatasetiter_destroy(&it->rdatasetit);
99 			dns_db_detachnode(it->db, &it->node);
100 			it->result = dns_dbiterator_next(it->dbit);
101 			continue;
102 		}
103 		dns_rdatasetiter_current(it->rdatasetit, &it->rdataset);
104 		dns_rdataset_getownercase(&it->rdataset,
105 					  dns_fixedname_name(&it->fixedname));
106 		it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER;
107 		it->result = dns_rdataset_first(&it->rdataset);
108 		return (it->result);
109 	}
110 	return (it->result);
111 }
112 
113 isc_result_t
dns_rriterator_nextrrset(dns_rriterator_t * it)114 dns_rriterator_nextrrset(dns_rriterator_t *it) {
115 	REQUIRE(VALID_RRITERATOR(it));
116 	if (dns_rdataset_isassociated(&it->rdataset)) {
117 		dns_rdataset_disassociate(&it->rdataset);
118 	}
119 	it->result = dns_rdatasetiter_next(it->rdatasetit);
120 	/*
121 	 * The while loop body is executed more than once
122 	 * only when an empty dbnode needs to be skipped.
123 	 */
124 	while (it->result == ISC_R_NOMORE) {
125 		dns_rdatasetiter_destroy(&it->rdatasetit);
126 		dns_db_detachnode(it->db, &it->node);
127 		it->result = dns_dbiterator_next(it->dbit);
128 		if (it->result == ISC_R_NOMORE) {
129 			/* We are at the end of the entire database. */
130 			return (it->result);
131 		}
132 		if (it->result != ISC_R_SUCCESS) {
133 			return (it->result);
134 		}
135 		it->result = dns_dbiterator_current(
136 			it->dbit, &it->node,
137 			dns_fixedname_name(&it->fixedname));
138 		if (it->result != ISC_R_SUCCESS) {
139 			return (it->result);
140 		}
141 		it->result = dns_db_allrdatasets(it->db, it->node, it->ver,
142 						 it->now, &it->rdatasetit);
143 		if (it->result != ISC_R_SUCCESS) {
144 			return (it->result);
145 		}
146 		it->result = dns_rdatasetiter_first(it->rdatasetit);
147 	}
148 	if (it->result != ISC_R_SUCCESS) {
149 		return (it->result);
150 	}
151 	dns_rdatasetiter_current(it->rdatasetit, &it->rdataset);
152 	dns_rdataset_getownercase(&it->rdataset,
153 				  dns_fixedname_name(&it->fixedname));
154 	it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER;
155 	it->result = dns_rdataset_first(&it->rdataset);
156 	return (it->result);
157 }
158 
159 isc_result_t
dns_rriterator_next(dns_rriterator_t * it)160 dns_rriterator_next(dns_rriterator_t *it) {
161 	REQUIRE(VALID_RRITERATOR(it));
162 	if (it->result != ISC_R_SUCCESS) {
163 		return (it->result);
164 	}
165 
166 	INSIST(it->dbit != NULL);
167 	INSIST(it->node != NULL);
168 	INSIST(it->rdatasetit != NULL);
169 
170 	it->result = dns_rdataset_next(&it->rdataset);
171 	if (it->result == ISC_R_NOMORE) {
172 		return (dns_rriterator_nextrrset(it));
173 	}
174 	return (it->result);
175 }
176 
177 void
dns_rriterator_pause(dns_rriterator_t * it)178 dns_rriterator_pause(dns_rriterator_t *it) {
179 	REQUIRE(VALID_RRITERATOR(it));
180 	RUNTIME_CHECK(dns_dbiterator_pause(it->dbit) == ISC_R_SUCCESS);
181 }
182 
183 void
dns_rriterator_destroy(dns_rriterator_t * it)184 dns_rriterator_destroy(dns_rriterator_t *it) {
185 	REQUIRE(VALID_RRITERATOR(it));
186 	if (dns_rdataset_isassociated(&it->rdataset)) {
187 		dns_rdataset_disassociate(&it->rdataset);
188 	}
189 	if (it->rdatasetit != NULL) {
190 		dns_rdatasetiter_destroy(&it->rdatasetit);
191 	}
192 	if (it->node != NULL) {
193 		dns_db_detachnode(it->db, &it->node);
194 	}
195 	dns_dbiterator_destroy(&it->dbit);
196 }
197 
198 void
dns_rriterator_current(dns_rriterator_t * it,dns_name_t ** name,uint32_t * ttl,dns_rdataset_t ** rdataset,dns_rdata_t ** rdata)199 dns_rriterator_current(dns_rriterator_t *it, dns_name_t **name, uint32_t *ttl,
200 		       dns_rdataset_t **rdataset, dns_rdata_t **rdata) {
201 	REQUIRE(name != NULL && *name == NULL);
202 	REQUIRE(VALID_RRITERATOR(it));
203 	REQUIRE(it->result == ISC_R_SUCCESS);
204 	REQUIRE(rdataset == NULL || *rdataset == NULL);
205 	REQUIRE(rdata == NULL || *rdata == NULL);
206 
207 	*name = dns_fixedname_name(&it->fixedname);
208 	*ttl = it->rdataset.ttl;
209 
210 	dns_rdata_reset(&it->rdata);
211 	dns_rdataset_current(&it->rdataset, &it->rdata);
212 
213 	if (rdataset != NULL) {
214 		*rdataset = &it->rdataset;
215 	}
216 
217 	if (rdata != NULL) {
218 		*rdata = &it->rdata;
219 	}
220 }
221