| @@ -1,1718 +1,1718 @@ | | | @@ -1,1718 +1,1718 @@ |
1 | /* $NetBSD: xfrout.c,v 1.11 2016/05/26 16:49:56 christos Exp $ */ | | 1 | /* $NetBSD: xfrout.c,v 1.12 2016/10/09 14:53:54 christos Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC") | | 4 | * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC") |
5 | * Copyright (C) 1999-2003 Internet Software Consortium. | | 5 | * Copyright (C) 1999-2003 Internet Software Consortium. |
6 | * | | 6 | * |
7 | * Permission to use, copy, modify, and/or distribute this software for any | | 7 | * Permission to use, copy, modify, and/or distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above | | 8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. | | 9 | * copyright notice and this permission notice appear in all copies. |
10 | * | | 10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH | | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH |
12 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | | 12 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
13 | * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, | | 13 | * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, |
14 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | | 14 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM |
15 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | | 15 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE |
16 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | | 16 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
17 | * PERFORMANCE OF THIS SOFTWARE. | | 17 | * PERFORMANCE OF THIS SOFTWARE. |
18 | */ | | 18 | */ |
19 | | | 19 | |
20 | /* Id */ | | 20 | /* Id */ |
21 | | | 21 | |
22 | #include <config.h> | | 22 | #include <config.h> |
23 | | | 23 | |
24 | #include <isc/formatcheck.h> | | 24 | #include <isc/formatcheck.h> |
25 | #include <isc/mem.h> | | 25 | #include <isc/mem.h> |
26 | #include <isc/timer.h> | | 26 | #include <isc/timer.h> |
27 | #include <isc/print.h> | | 27 | #include <isc/print.h> |
28 | #include <isc/stats.h> | | 28 | #include <isc/stats.h> |
29 | #include <isc/util.h> | | 29 | #include <isc/util.h> |
30 | | | 30 | |
31 | #include <dns/db.h> | | 31 | #include <dns/db.h> |
32 | #include <dns/dbiterator.h> | | 32 | #include <dns/dbiterator.h> |
33 | #include <dns/dlz.h> | | 33 | #include <dns/dlz.h> |
34 | #include <dns/fixedname.h> | | 34 | #include <dns/fixedname.h> |
35 | #include <dns/journal.h> | | 35 | #include <dns/journal.h> |
36 | #include <dns/message.h> | | 36 | #include <dns/message.h> |
37 | #include <dns/peer.h> | | 37 | #include <dns/peer.h> |
38 | #include <dns/rdataclass.h> | | 38 | #include <dns/rdataclass.h> |
39 | #include <dns/rdatalist.h> | | 39 | #include <dns/rdatalist.h> |
40 | #include <dns/rdataset.h> | | 40 | #include <dns/rdataset.h> |
41 | #include <dns/rdatasetiter.h> | | 41 | #include <dns/rdatasetiter.h> |
42 | #include <dns/result.h> | | 42 | #include <dns/result.h> |
43 | #include <dns/rriterator.h> | | 43 | #include <dns/rriterator.h> |
44 | #include <dns/soa.h> | | 44 | #include <dns/soa.h> |
45 | #include <dns/stats.h> | | 45 | #include <dns/stats.h> |
46 | #include <dns/timer.h> | | 46 | #include <dns/timer.h> |
47 | #include <dns/tsig.h> | | 47 | #include <dns/tsig.h> |
48 | #include <dns/view.h> | | 48 | #include <dns/view.h> |
49 | #include <dns/zone.h> | | 49 | #include <dns/zone.h> |
50 | #include <dns/zt.h> | | 50 | #include <dns/zt.h> |
51 | | | 51 | |
52 | #include <named/client.h> | | 52 | #include <named/client.h> |
53 | #include <named/log.h> | | 53 | #include <named/log.h> |
54 | #include <named/server.h> | | 54 | #include <named/server.h> |
55 | #include <named/xfrout.h> | | 55 | #include <named/xfrout.h> |
56 | | | 56 | |
57 | #include "pfilter.h" | | 57 | #include "pfilter.h" |
58 | | | 58 | |
59 | /*! \file | | 59 | /*! \file |
60 | * \brief | | 60 | * \brief |
61 | * Outgoing AXFR and IXFR. | | 61 | * Outgoing AXFR and IXFR. |
62 | */ | | 62 | */ |
63 | | | 63 | |
64 | /* | | 64 | /* |
65 | * TODO: | | 65 | * TODO: |
66 | * - IXFR over UDP | | 66 | * - IXFR over UDP |
67 | */ | | 67 | */ |
68 | | | 68 | |
69 | #define XFROUT_COMMON_LOGARGS \ | | 69 | #define XFROUT_COMMON_LOGARGS \ |
70 | ns_g_lctx, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT | | 70 | ns_g_lctx, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT |
71 | | | 71 | |
72 | #define XFROUT_PROTOCOL_LOGARGS \ | | 72 | #define XFROUT_PROTOCOL_LOGARGS \ |
73 | XFROUT_COMMON_LOGARGS, ISC_LOG_INFO | | 73 | XFROUT_COMMON_LOGARGS, ISC_LOG_INFO |
74 | | | 74 | |
75 | #define XFROUT_DEBUG_LOGARGS(n) \ | | 75 | #define XFROUT_DEBUG_LOGARGS(n) \ |
76 | XFROUT_COMMON_LOGARGS, ISC_LOG_DEBUG(n) | | 76 | XFROUT_COMMON_LOGARGS, ISC_LOG_DEBUG(n) |
77 | | | 77 | |
78 | #define XFROUT_RR_LOGARGS \ | | 78 | #define XFROUT_RR_LOGARGS \ |
79 | XFROUT_COMMON_LOGARGS, XFROUT_RR_LOGLEVEL | | 79 | XFROUT_COMMON_LOGARGS, XFROUT_RR_LOGLEVEL |
80 | | | 80 | |
81 | #define XFROUT_RR_LOGLEVEL ISC_LOG_DEBUG(8) | | 81 | #define XFROUT_RR_LOGLEVEL ISC_LOG_DEBUG(8) |
82 | | | 82 | |
83 | /*% | | 83 | /*% |
84 | * Fail unconditionally and log as a client error. | | 84 | * Fail unconditionally and log as a client error. |
85 | * The test against ISC_R_SUCCESS is there to keep the Solaris compiler | | 85 | * The test against ISC_R_SUCCESS is there to keep the Solaris compiler |
86 | * from complaining about "end-of-loop code not reached". | | 86 | * from complaining about "end-of-loop code not reached". |
87 | */ | | 87 | */ |
88 | #define FAILC(code, msg) \ | | 88 | #define FAILC(code, msg) \ |
89 | do { \ | | 89 | do { \ |
90 | result = (code); \ | | 90 | result = (code); \ |
91 | ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, \ | | 91 | ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, \ |
92 | NS_LOGMODULE_XFER_OUT, ISC_LOG_INFO, \ | | 92 | NS_LOGMODULE_XFER_OUT, ISC_LOG_INFO, \ |
93 | "bad zone transfer request: %s (%s)", \ | | 93 | "bad zone transfer request: %s (%s)", \ |
94 | msg, isc_result_totext(code)); \ | | 94 | msg, isc_result_totext(code)); \ |
95 | if (result != ISC_R_SUCCESS) goto failure; \ | | 95 | if (result != ISC_R_SUCCESS) goto failure; \ |
96 | } while (/*CONSTCOND*/0) | | 96 | } while (/*CONSTCOND*/0) |
97 | | | 97 | |
98 | #define FAILQ(code, msg, question, rdclass) \ | | 98 | #define FAILQ(code, msg, question, rdclass) \ |
99 | do { \ | | 99 | do { \ |
100 | char _buf1[DNS_NAME_FORMATSIZE]; \ | | 100 | char _buf1[DNS_NAME_FORMATSIZE]; \ |
101 | char _buf2[DNS_RDATACLASS_FORMATSIZE]; \ | | 101 | char _buf2[DNS_RDATACLASS_FORMATSIZE]; \ |
102 | result = (code); \ | | 102 | result = (code); \ |
103 | dns_name_format(question, _buf1, sizeof(_buf1)); \ | | 103 | dns_name_format(question, _buf1, sizeof(_buf1)); \ |
104 | dns_rdataclass_format(rdclass, _buf2, sizeof(_buf2)); \ | | 104 | dns_rdataclass_format(rdclass, _buf2, sizeof(_buf2)); \ |
105 | ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, \ | | 105 | ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, \ |
106 | NS_LOGMODULE_XFER_OUT, ISC_LOG_INFO, \ | | 106 | NS_LOGMODULE_XFER_OUT, ISC_LOG_INFO, \ |
107 | "bad zone transfer request: '%s/%s': %s (%s)", \ | | 107 | "bad zone transfer request: '%s/%s': %s (%s)", \ |
108 | _buf1, _buf2, msg, isc_result_totext(code)); \ | | 108 | _buf1, _buf2, msg, isc_result_totext(code)); \ |
109 | if (result != ISC_R_SUCCESS) goto failure; \ | | 109 | if (result != ISC_R_SUCCESS) goto failure; \ |
110 | } while (/*CONSTCOND*/0) | | 110 | } while (/*CONSTCOND*/0) |
111 | | | 111 | |
112 | #define CHECK(op) \ | | 112 | #define CHECK(op) \ |
113 | do { result = (op); \ | | 113 | do { result = (op); \ |
114 | if (result != ISC_R_SUCCESS) goto failure; \ | | 114 | if (result != ISC_R_SUCCESS) goto failure; \ |
115 | } while (/*CONSTCOND*/0) | | 115 | } while (/*CONSTCOND*/0) |
116 | | | 116 | |
117 | /**************************************************************************/ | | 117 | /**************************************************************************/ |
118 | | | 118 | |
119 | static inline void | | 119 | static inline void |
120 | inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { | | 120 | inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { |
121 | isc_stats_increment(ns_g_server->nsstats, counter); | | 121 | isc_stats_increment(ns_g_server->nsstats, counter); |
122 | if (zone != NULL) { | | 122 | if (zone != NULL) { |
123 | isc_stats_t *zonestats = dns_zone_getrequeststats(zone); | | 123 | isc_stats_t *zonestats = dns_zone_getrequeststats(zone); |
124 | if (zonestats != NULL) | | 124 | if (zonestats != NULL) |
125 | isc_stats_increment(zonestats, counter); | | 125 | isc_stats_increment(zonestats, counter); |
126 | } | | 126 | } |
127 | } | | 127 | } |
128 | | | 128 | |
129 | /**************************************************************************/ | | 129 | /**************************************************************************/ |
130 | | | 130 | |
131 | /*% Log an RR (for debugging) */ | | 131 | /*% Log an RR (for debugging) */ |
132 | | | 132 | |
133 | static void | | 133 | static void |
134 | log_rr(dns_name_t *name, dns_rdata_t *rdata, isc_uint32_t ttl) { | | 134 | log_rr(dns_name_t *name, dns_rdata_t *rdata, isc_uint32_t ttl) { |
135 | isc_result_t result; | | 135 | isc_result_t result; |
136 | isc_buffer_t buf; | | 136 | isc_buffer_t buf; |
137 | char mem[2000]; | | 137 | char mem[2000]; |
138 | dns_rdatalist_t rdl; | | 138 | dns_rdatalist_t rdl; |
139 | dns_rdataset_t rds; | | 139 | dns_rdataset_t rds; |
140 | dns_rdata_t rd = DNS_RDATA_INIT; | | 140 | dns_rdata_t rd = DNS_RDATA_INIT; |
141 | | | 141 | |
142 | dns_rdatalist_init(&rdl); | | 142 | dns_rdatalist_init(&rdl); |
143 | rdl.type = rdata->type; | | 143 | rdl.type = rdata->type; |
144 | rdl.rdclass = rdata->rdclass; | | 144 | rdl.rdclass = rdata->rdclass; |
145 | rdl.ttl = ttl; | | 145 | rdl.ttl = ttl; |
146 | if (rdata->type == dns_rdatatype_sig || | | 146 | if (rdata->type == dns_rdatatype_sig || |
147 | rdata->type == dns_rdatatype_rrsig) | | 147 | rdata->type == dns_rdatatype_rrsig) |
148 | rdl.covers = dns_rdata_covers(rdata); | | 148 | rdl.covers = dns_rdata_covers(rdata); |
149 | else | | 149 | else |
150 | rdl.covers = dns_rdatatype_none; | | 150 | rdl.covers = dns_rdatatype_none; |
151 | dns_rdataset_init(&rds); | | 151 | dns_rdataset_init(&rds); |
152 | dns_rdata_init(&rd); | | 152 | dns_rdata_init(&rd); |
153 | dns_rdata_clone(rdata, &rd); | | 153 | dns_rdata_clone(rdata, &rd); |
154 | ISC_LIST_APPEND(rdl.rdata, &rd, link); | | 154 | ISC_LIST_APPEND(rdl.rdata, &rd, link); |
155 | RUNTIME_CHECK(dns_rdatalist_tordataset(&rdl, &rds) == ISC_R_SUCCESS); | | 155 | RUNTIME_CHECK(dns_rdatalist_tordataset(&rdl, &rds) == ISC_R_SUCCESS); |
156 | | | 156 | |
157 | isc_buffer_init(&buf, mem, sizeof(mem)); | | 157 | isc_buffer_init(&buf, mem, sizeof(mem)); |
158 | result = dns_rdataset_totext(&rds, name, | | 158 | result = dns_rdataset_totext(&rds, name, |
159 | ISC_FALSE, ISC_FALSE, &buf); | | 159 | ISC_FALSE, ISC_FALSE, &buf); |
160 | | | 160 | |
161 | /* | | 161 | /* |
162 | * We could use xfrout_log(), but that would produce | | 162 | * We could use xfrout_log(), but that would produce |
163 | * very long lines with a repetitive prefix. | | 163 | * very long lines with a repetitive prefix. |
164 | */ | | 164 | */ |
165 | if (result == ISC_R_SUCCESS) { | | 165 | if (result == ISC_R_SUCCESS) { |
166 | /* | | 166 | /* |
167 | * Get rid of final newline. | | 167 | * Get rid of final newline. |
168 | */ | | 168 | */ |
169 | INSIST(buf.used >= 1 && | | 169 | INSIST(buf.used >= 1 && |
170 | ((char *) buf.base)[buf.used - 1] == '\n'); | | 170 | ((char *) buf.base)[buf.used - 1] == '\n'); |
171 | buf.used--; | | 171 | buf.used--; |
172 | | | 172 | |
173 | isc_log_write(XFROUT_RR_LOGARGS, "%.*s", | | 173 | isc_log_write(XFROUT_RR_LOGARGS, "%.*s", |
174 | (int)isc_buffer_usedlength(&buf), | | 174 | (int)isc_buffer_usedlength(&buf), |
175 | (char *)isc_buffer_base(&buf)); | | 175 | (char *)isc_buffer_base(&buf)); |
176 | } else { | | 176 | } else { |
177 | isc_log_write(XFROUT_RR_LOGARGS, "<RR too large to print>"); | | 177 | isc_log_write(XFROUT_RR_LOGARGS, "<RR too large to print>"); |
178 | } | | 178 | } |
179 | } | | 179 | } |
180 | | | 180 | |
181 | /**************************************************************************/ | | 181 | /**************************************************************************/ |
182 | /* | | 182 | /* |
183 | * An 'rrstream_t' is a polymorphic iterator that returns | | 183 | * An 'rrstream_t' is a polymorphic iterator that returns |
184 | * a stream of resource records. There are multiple implementations, | | 184 | * a stream of resource records. There are multiple implementations, |
185 | * e.g. for generating AXFR and IXFR records streams. | | 185 | * e.g. for generating AXFR and IXFR records streams. |
186 | */ | | 186 | */ |
187 | | | 187 | |
188 | typedef struct rrstream_methods rrstream_methods_t; | | 188 | typedef struct rrstream_methods rrstream_methods_t; |
189 | | | 189 | |
190 | typedef struct rrstream { | | 190 | typedef struct rrstream { |
191 | isc_mem_t *mctx; | | 191 | isc_mem_t *mctx; |
192 | rrstream_methods_t *methods; | | 192 | rrstream_methods_t *methods; |
193 | } rrstream_t; | | 193 | } rrstream_t; |
194 | | | 194 | |
195 | struct rrstream_methods { | | 195 | struct rrstream_methods { |
196 | isc_result_t (*first)(rrstream_t *); | | 196 | isc_result_t (*first)(rrstream_t *); |
197 | isc_result_t (*next)(rrstream_t *); | | 197 | isc_result_t (*next)(rrstream_t *); |
198 | void (*current)(rrstream_t *, | | 198 | void (*current)(rrstream_t *, |
199 | dns_name_t **, | | 199 | dns_name_t **, |
200 | isc_uint32_t *, | | 200 | isc_uint32_t *, |
201 | dns_rdata_t **); | | 201 | dns_rdata_t **); |
202 | void (*pause)(rrstream_t *); | | 202 | void (*pause)(rrstream_t *); |
203 | void (*destroy)(rrstream_t **); | | 203 | void (*destroy)(rrstream_t **); |
204 | }; | | 204 | }; |
205 | | | 205 | |
206 | static void | | 206 | static void |
207 | rrstream_noop_pause(rrstream_t *rs) { | | 207 | rrstream_noop_pause(rrstream_t *rs) { |
208 | UNUSED(rs); | | 208 | UNUSED(rs); |
209 | } | | 209 | } |
210 | | | 210 | |
211 | /**************************************************************************/ | | 211 | /**************************************************************************/ |
212 | /* | | 212 | /* |
213 | * An 'ixfr_rrstream_t' is an 'rrstream_t' that returns | | 213 | * An 'ixfr_rrstream_t' is an 'rrstream_t' that returns |
214 | * an IXFR-like RR stream from a journal file. | | 214 | * an IXFR-like RR stream from a journal file. |
215 | * | | 215 | * |
216 | * The SOA at the beginning of each sequence of additions | | 216 | * The SOA at the beginning of each sequence of additions |
217 | * or deletions are included in the stream, but the extra | | 217 | * or deletions are included in the stream, but the extra |
218 | * SOAs at the beginning and end of the entire transfer are | | 218 | * SOAs at the beginning and end of the entire transfer are |
219 | * not included. | | 219 | * not included. |
220 | */ | | 220 | */ |
221 | | | 221 | |
222 | typedef struct ixfr_rrstream { | | 222 | typedef struct ixfr_rrstream { |
223 | rrstream_t common; | | 223 | rrstream_t common; |
224 | dns_journal_t *journal; | | 224 | dns_journal_t *journal; |
225 | } ixfr_rrstream_t; | | 225 | } ixfr_rrstream_t; |
226 | | | 226 | |
227 | /* Forward declarations. */ | | 227 | /* Forward declarations. */ |
228 | static void | | 228 | static void |
229 | ixfr_rrstream_destroy(rrstream_t **sp); | | 229 | ixfr_rrstream_destroy(rrstream_t **sp); |
230 | | | 230 | |
231 | static rrstream_methods_t ixfr_rrstream_methods; | | 231 | static rrstream_methods_t ixfr_rrstream_methods; |
232 | | | 232 | |
233 | /* | | 233 | /* |
234 | * Returns: anything dns_journal_open() or dns_journal_iter_init() | | 234 | * Returns: anything dns_journal_open() or dns_journal_iter_init() |
235 | * may return. | | 235 | * may return. |
236 | */ | | 236 | */ |
237 | | | 237 | |
238 | static isc_result_t | | 238 | static isc_result_t |
239 | ixfr_rrstream_create(isc_mem_t *mctx, | | 239 | ixfr_rrstream_create(isc_mem_t *mctx, |
240 | const char *journal_filename, | | 240 | const char *journal_filename, |
241 | isc_uint32_t begin_serial, | | 241 | isc_uint32_t begin_serial, |
242 | isc_uint32_t end_serial, | | 242 | isc_uint32_t end_serial, |
243 | rrstream_t **sp) | | 243 | rrstream_t **sp) |
244 | { | | 244 | { |
245 | ixfr_rrstream_t *s; | | 245 | ixfr_rrstream_t *s; |
246 | isc_result_t result; | | 246 | isc_result_t result; |
247 | | | 247 | |
248 | INSIST(sp != NULL && *sp == NULL); | | 248 | INSIST(sp != NULL && *sp == NULL); |
249 | | | 249 | |
250 | s = isc_mem_get(mctx, sizeof(*s)); | | 250 | s = isc_mem_get(mctx, sizeof(*s)); |
251 | if (s == NULL) | | 251 | if (s == NULL) |
252 | return (ISC_R_NOMEMORY); | | 252 | return (ISC_R_NOMEMORY); |
253 | s->common.mctx = NULL; | | 253 | s->common.mctx = NULL; |
254 | isc_mem_attach(mctx, &s->common.mctx); | | 254 | isc_mem_attach(mctx, &s->common.mctx); |
255 | s->common.methods = &ixfr_rrstream_methods; | | 255 | s->common.methods = &ixfr_rrstream_methods; |
256 | s->journal = NULL; | | 256 | s->journal = NULL; |
257 | | | 257 | |
258 | CHECK(dns_journal_open(mctx, journal_filename, | | 258 | CHECK(dns_journal_open(mctx, journal_filename, |
259 | DNS_JOURNAL_READ, &s->journal)); | | 259 | DNS_JOURNAL_READ, &s->journal)); |
260 | CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial)); | | 260 | CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial)); |
261 | | | 261 | |
262 | *sp = (rrstream_t *) s; | | 262 | *sp = (rrstream_t *) s; |
263 | return (ISC_R_SUCCESS); | | 263 | return (ISC_R_SUCCESS); |
264 | | | 264 | |
265 | failure: | | 265 | failure: |
266 | ixfr_rrstream_destroy((rrstream_t **) (void *)&s); | | 266 | ixfr_rrstream_destroy((rrstream_t **) (void *)&s); |
267 | return (result); | | 267 | return (result); |
268 | } | | 268 | } |
269 | | | 269 | |
270 | static isc_result_t | | 270 | static isc_result_t |
271 | ixfr_rrstream_first(rrstream_t *rs) { | | 271 | ixfr_rrstream_first(rrstream_t *rs) { |
272 | ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; | | 272 | ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; |
273 | return (dns_journal_first_rr(s->journal)); | | 273 | return (dns_journal_first_rr(s->journal)); |
274 | } | | 274 | } |
275 | | | 275 | |
276 | static isc_result_t | | 276 | static isc_result_t |
277 | ixfr_rrstream_next(rrstream_t *rs) { | | 277 | ixfr_rrstream_next(rrstream_t *rs) { |
278 | ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; | | 278 | ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; |
279 | return (dns_journal_next_rr(s->journal)); | | 279 | return (dns_journal_next_rr(s->journal)); |
280 | } | | 280 | } |
281 | | | 281 | |
282 | static void | | 282 | static void |
283 | ixfr_rrstream_current(rrstream_t *rs, | | 283 | ixfr_rrstream_current(rrstream_t *rs, |
284 | dns_name_t **name, isc_uint32_t *ttl, | | 284 | dns_name_t **name, isc_uint32_t *ttl, |
285 | dns_rdata_t **rdata) | | 285 | dns_rdata_t **rdata) |
286 | { | | 286 | { |
287 | ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; | | 287 | ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; |
288 | dns_journal_current_rr(s->journal, name, ttl, rdata); | | 288 | dns_journal_current_rr(s->journal, name, ttl, rdata); |
289 | } | | 289 | } |
290 | | | 290 | |
291 | static void | | 291 | static void |
292 | ixfr_rrstream_destroy(rrstream_t **rsp) { | | 292 | ixfr_rrstream_destroy(rrstream_t **rsp) { |
293 | ixfr_rrstream_t *s = (ixfr_rrstream_t *) *rsp; | | 293 | ixfr_rrstream_t *s = (ixfr_rrstream_t *) *rsp; |
294 | if (s->journal != 0) | | 294 | if (s->journal != 0) |
295 | dns_journal_destroy(&s->journal); | | 295 | dns_journal_destroy(&s->journal); |
296 | isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s)); | | 296 | isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s)); |
297 | } | | 297 | } |
298 | | | 298 | |
299 | static rrstream_methods_t ixfr_rrstream_methods = { | | 299 | static rrstream_methods_t ixfr_rrstream_methods = { |
300 | ixfr_rrstream_first, | | 300 | ixfr_rrstream_first, |
301 | ixfr_rrstream_next, | | 301 | ixfr_rrstream_next, |
302 | ixfr_rrstream_current, | | 302 | ixfr_rrstream_current, |
303 | rrstream_noop_pause, | | 303 | rrstream_noop_pause, |
304 | ixfr_rrstream_destroy | | 304 | ixfr_rrstream_destroy |
305 | }; | | 305 | }; |
306 | | | 306 | |
307 | /**************************************************************************/ | | 307 | /**************************************************************************/ |
308 | /* | | 308 | /* |
309 | * An 'axfr_rrstream_t' is an 'rrstream_t' that returns | | 309 | * An 'axfr_rrstream_t' is an 'rrstream_t' that returns |
310 | * an AXFR-like RR stream from a database. | | 310 | * an AXFR-like RR stream from a database. |
311 | * | | 311 | * |
312 | * The SOAs at the beginning and end of the transfer are | | 312 | * The SOAs at the beginning and end of the transfer are |
313 | * not included in the stream. | | 313 | * not included in the stream. |
314 | */ | | 314 | */ |
315 | | | 315 | |
316 | typedef struct axfr_rrstream { | | 316 | typedef struct axfr_rrstream { |
317 | rrstream_t common; | | 317 | rrstream_t common; |
318 | dns_rriterator_t it; | | 318 | dns_rriterator_t it; |
319 | isc_boolean_t it_valid; | | 319 | isc_boolean_t it_valid; |
320 | } axfr_rrstream_t; | | 320 | } axfr_rrstream_t; |
321 | | | 321 | |
322 | /* | | 322 | /* |
323 | * Forward declarations. | | 323 | * Forward declarations. |
324 | */ | | 324 | */ |
325 | static void | | 325 | static void |
326 | axfr_rrstream_destroy(rrstream_t **rsp); | | 326 | axfr_rrstream_destroy(rrstream_t **rsp); |
327 | | | 327 | |
328 | static rrstream_methods_t axfr_rrstream_methods; | | 328 | static rrstream_methods_t axfr_rrstream_methods; |
329 | | | 329 | |
330 | static isc_result_t | | 330 | static isc_result_t |
331 | axfr_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver, | | 331 | axfr_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver, |
332 | rrstream_t **sp) | | 332 | rrstream_t **sp) |
333 | { | | 333 | { |
334 | axfr_rrstream_t *s; | | 334 | axfr_rrstream_t *s; |
335 | isc_result_t result; | | 335 | isc_result_t result; |
336 | | | 336 | |
337 | INSIST(sp != NULL && *sp == NULL); | | 337 | INSIST(sp != NULL && *sp == NULL); |
338 | | | 338 | |
339 | s = isc_mem_get(mctx, sizeof(*s)); | | 339 | s = isc_mem_get(mctx, sizeof(*s)); |
340 | if (s == NULL) | | 340 | if (s == NULL) |
341 | return (ISC_R_NOMEMORY); | | 341 | return (ISC_R_NOMEMORY); |
342 | s->common.mctx = NULL; | | 342 | s->common.mctx = NULL; |
343 | isc_mem_attach(mctx, &s->common.mctx); | | 343 | isc_mem_attach(mctx, &s->common.mctx); |
344 | s->common.methods = &axfr_rrstream_methods; | | 344 | s->common.methods = &axfr_rrstream_methods; |
345 | s->it_valid = ISC_FALSE; | | 345 | s->it_valid = ISC_FALSE; |
346 | | | 346 | |
347 | CHECK(dns_rriterator_init(&s->it, db, ver, 0)); | | 347 | CHECK(dns_rriterator_init(&s->it, db, ver, 0)); |
348 | s->it_valid = ISC_TRUE; | | 348 | s->it_valid = ISC_TRUE; |
349 | | | 349 | |
350 | *sp = (rrstream_t *) s; | | 350 | *sp = (rrstream_t *) s; |
351 | return (ISC_R_SUCCESS); | | 351 | return (ISC_R_SUCCESS); |
352 | | | 352 | |
353 | failure: | | 353 | failure: |
354 | axfr_rrstream_destroy((rrstream_t **) (void *)&s); | | 354 | axfr_rrstream_destroy((rrstream_t **) (void *)&s); |
355 | return (result); | | 355 | return (result); |
356 | } | | 356 | } |
357 | | | 357 | |
358 | static isc_result_t | | 358 | static isc_result_t |
359 | axfr_rrstream_first(rrstream_t *rs) { | | 359 | axfr_rrstream_first(rrstream_t *rs) { |
360 | axfr_rrstream_t *s = (axfr_rrstream_t *) rs; | | 360 | axfr_rrstream_t *s = (axfr_rrstream_t *) rs; |
361 | isc_result_t result; | | 361 | isc_result_t result; |
362 | result = dns_rriterator_first(&s->it); | | 362 | result = dns_rriterator_first(&s->it); |
363 | if (result != ISC_R_SUCCESS) | | 363 | if (result != ISC_R_SUCCESS) |
364 | return (result); | | 364 | return (result); |
365 | /* Skip SOA records. */ | | 365 | /* Skip SOA records. */ |
366 | for (;;) { | | 366 | for (;;) { |
367 | dns_name_t *name_dummy = NULL; | | 367 | dns_name_t *name_dummy = NULL; |
368 | isc_uint32_t ttl_dummy; | | 368 | isc_uint32_t ttl_dummy; |
369 | dns_rdata_t *rdata = NULL; | | 369 | dns_rdata_t *rdata = NULL; |
370 | dns_rriterator_current(&s->it, &name_dummy, | | 370 | dns_rriterator_current(&s->it, &name_dummy, |
371 | &ttl_dummy, NULL, &rdata); | | 371 | &ttl_dummy, NULL, &rdata); |
372 | if (rdata->type != dns_rdatatype_soa) | | 372 | if (rdata->type != dns_rdatatype_soa) |
373 | break; | | 373 | break; |
374 | result = dns_rriterator_next(&s->it); | | 374 | result = dns_rriterator_next(&s->it); |
375 | if (result != ISC_R_SUCCESS) | | 375 | if (result != ISC_R_SUCCESS) |
376 | break; | | 376 | break; |
377 | } | | 377 | } |
378 | return (result); | | 378 | return (result); |
379 | } | | 379 | } |
380 | | | 380 | |
381 | static isc_result_t | | 381 | static isc_result_t |
382 | axfr_rrstream_next(rrstream_t *rs) { | | 382 | axfr_rrstream_next(rrstream_t *rs) { |
383 | axfr_rrstream_t *s = (axfr_rrstream_t *) rs; | | 383 | axfr_rrstream_t *s = (axfr_rrstream_t *) rs; |
384 | isc_result_t result; | | 384 | isc_result_t result; |
385 | | | 385 | |
386 | /* Skip SOA records. */ | | 386 | /* Skip SOA records. */ |
387 | for (;;) { | | 387 | for (;;) { |
388 | dns_name_t *name_dummy = NULL; | | 388 | dns_name_t *name_dummy = NULL; |
389 | isc_uint32_t ttl_dummy; | | 389 | isc_uint32_t ttl_dummy; |
390 | dns_rdata_t *rdata = NULL; | | 390 | dns_rdata_t *rdata = NULL; |
391 | result = dns_rriterator_next(&s->it); | | 391 | result = dns_rriterator_next(&s->it); |
392 | if (result != ISC_R_SUCCESS) | | 392 | if (result != ISC_R_SUCCESS) |
393 | break; | | 393 | break; |
394 | dns_rriterator_current(&s->it, &name_dummy, | | 394 | dns_rriterator_current(&s->it, &name_dummy, |
395 | &ttl_dummy, NULL, &rdata); | | 395 | &ttl_dummy, NULL, &rdata); |
396 | if (rdata->type != dns_rdatatype_soa) | | 396 | if (rdata->type != dns_rdatatype_soa) |
397 | break; | | 397 | break; |
398 | } | | 398 | } |
399 | return (result); | | 399 | return (result); |
400 | } | | 400 | } |
401 | | | 401 | |
402 | static void | | 402 | static void |
403 | axfr_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, | | 403 | axfr_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, |
404 | dns_rdata_t **rdata) | | 404 | dns_rdata_t **rdata) |
405 | { | | 405 | { |
406 | axfr_rrstream_t *s = (axfr_rrstream_t *) rs; | | 406 | axfr_rrstream_t *s = (axfr_rrstream_t *) rs; |
407 | dns_rriterator_current(&s->it, name, ttl, NULL, rdata); | | 407 | dns_rriterator_current(&s->it, name, ttl, NULL, rdata); |
408 | } | | 408 | } |
409 | | | 409 | |
410 | static void | | 410 | static void |
411 | axfr_rrstream_pause(rrstream_t *rs) { | | 411 | axfr_rrstream_pause(rrstream_t *rs) { |
412 | axfr_rrstream_t *s = (axfr_rrstream_t *) rs; | | 412 | axfr_rrstream_t *s = (axfr_rrstream_t *) rs; |
413 | dns_rriterator_pause(&s->it); | | 413 | dns_rriterator_pause(&s->it); |
414 | } | | 414 | } |
415 | | | 415 | |
416 | static void | | 416 | static void |
417 | axfr_rrstream_destroy(rrstream_t **rsp) { | | 417 | axfr_rrstream_destroy(rrstream_t **rsp) { |
418 | axfr_rrstream_t *s = (axfr_rrstream_t *) *rsp; | | 418 | axfr_rrstream_t *s = (axfr_rrstream_t *) *rsp; |
419 | if (s->it_valid) | | 419 | if (s->it_valid) |
420 | dns_rriterator_destroy(&s->it); | | 420 | dns_rriterator_destroy(&s->it); |
421 | isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s)); | | 421 | isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s)); |
422 | } | | 422 | } |
423 | | | 423 | |
424 | static rrstream_methods_t axfr_rrstream_methods = { | | 424 | static rrstream_methods_t axfr_rrstream_methods = { |
425 | axfr_rrstream_first, | | 425 | axfr_rrstream_first, |
426 | axfr_rrstream_next, | | 426 | axfr_rrstream_next, |
427 | axfr_rrstream_current, | | 427 | axfr_rrstream_current, |
428 | axfr_rrstream_pause, | | 428 | axfr_rrstream_pause, |
429 | axfr_rrstream_destroy | | 429 | axfr_rrstream_destroy |
430 | }; | | 430 | }; |
431 | | | 431 | |
432 | /**************************************************************************/ | | 432 | /**************************************************************************/ |
433 | /* | | 433 | /* |
434 | * An 'soa_rrstream_t' is a degenerate 'rrstream_t' that returns | | 434 | * An 'soa_rrstream_t' is a degenerate 'rrstream_t' that returns |
435 | * a single SOA record. | | 435 | * a single SOA record. |
436 | */ | | 436 | */ |
437 | | | 437 | |
438 | typedef struct soa_rrstream { | | 438 | typedef struct soa_rrstream { |
439 | rrstream_t common; | | 439 | rrstream_t common; |
440 | dns_difftuple_t *soa_tuple; | | 440 | dns_difftuple_t *soa_tuple; |
441 | } soa_rrstream_t; | | 441 | } soa_rrstream_t; |
442 | | | 442 | |
443 | /* | | 443 | /* |
444 | * Forward declarations. | | 444 | * Forward declarations. |
445 | */ | | 445 | */ |
446 | static void | | 446 | static void |
447 | soa_rrstream_destroy(rrstream_t **rsp); | | 447 | soa_rrstream_destroy(rrstream_t **rsp); |
448 | | | 448 | |
449 | static rrstream_methods_t soa_rrstream_methods; | | 449 | static rrstream_methods_t soa_rrstream_methods; |
450 | | | 450 | |
451 | static isc_result_t | | 451 | static isc_result_t |
452 | soa_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver, | | 452 | soa_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver, |
453 | rrstream_t **sp) | | 453 | rrstream_t **sp) |
454 | { | | 454 | { |
455 | soa_rrstream_t *s; | | 455 | soa_rrstream_t *s; |
456 | isc_result_t result; | | 456 | isc_result_t result; |
457 | | | 457 | |
458 | INSIST(sp != NULL && *sp == NULL); | | 458 | INSIST(sp != NULL && *sp == NULL); |
459 | | | 459 | |
460 | s = isc_mem_get(mctx, sizeof(*s)); | | 460 | s = isc_mem_get(mctx, sizeof(*s)); |
461 | if (s == NULL) | | 461 | if (s == NULL) |
462 | return (ISC_R_NOMEMORY); | | 462 | return (ISC_R_NOMEMORY); |
463 | s->common.mctx = NULL; | | 463 | s->common.mctx = NULL; |
464 | isc_mem_attach(mctx, &s->common.mctx); | | 464 | isc_mem_attach(mctx, &s->common.mctx); |
465 | s->common.methods = &soa_rrstream_methods; | | 465 | s->common.methods = &soa_rrstream_methods; |
466 | s->soa_tuple = NULL; | | 466 | s->soa_tuple = NULL; |
467 | | | 467 | |
468 | CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, | | 468 | CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, |
469 | &s->soa_tuple)); | | 469 | &s->soa_tuple)); |
470 | | | 470 | |
471 | *sp = (rrstream_t *) s; | | 471 | *sp = (rrstream_t *) s; |
472 | return (ISC_R_SUCCESS); | | 472 | return (ISC_R_SUCCESS); |
473 | | | 473 | |
474 | failure: | | 474 | failure: |
475 | soa_rrstream_destroy((rrstream_t **) (void *)&s); | | 475 | soa_rrstream_destroy((rrstream_t **) (void *)&s); |
476 | return (result); | | 476 | return (result); |
477 | } | | 477 | } |
478 | | | 478 | |
479 | static isc_result_t | | 479 | static isc_result_t |
480 | soa_rrstream_first(rrstream_t *rs) { | | 480 | soa_rrstream_first(rrstream_t *rs) { |
481 | UNUSED(rs); | | 481 | UNUSED(rs); |
482 | return (ISC_R_SUCCESS); | | 482 | return (ISC_R_SUCCESS); |
483 | } | | 483 | } |
484 | | | 484 | |
485 | static isc_result_t | | 485 | static isc_result_t |
486 | soa_rrstream_next(rrstream_t *rs) { | | 486 | soa_rrstream_next(rrstream_t *rs) { |
487 | UNUSED(rs); | | 487 | UNUSED(rs); |
488 | return (ISC_R_NOMORE); | | 488 | return (ISC_R_NOMORE); |
489 | } | | 489 | } |
490 | | | 490 | |
491 | static void | | 491 | static void |
492 | soa_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, | | 492 | soa_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, |
493 | dns_rdata_t **rdata) | | 493 | dns_rdata_t **rdata) |
494 | { | | 494 | { |
495 | soa_rrstream_t *s = (soa_rrstream_t *) rs; | | 495 | soa_rrstream_t *s = (soa_rrstream_t *) rs; |
496 | *name = &s->soa_tuple->name; | | 496 | *name = &s->soa_tuple->name; |
497 | *ttl = s->soa_tuple->ttl; | | 497 | *ttl = s->soa_tuple->ttl; |
498 | *rdata = &s->soa_tuple->rdata; | | 498 | *rdata = &s->soa_tuple->rdata; |
499 | } | | 499 | } |
500 | | | 500 | |
501 | static void | | 501 | static void |
502 | soa_rrstream_destroy(rrstream_t **rsp) { | | 502 | soa_rrstream_destroy(rrstream_t **rsp) { |
503 | soa_rrstream_t *s = (soa_rrstream_t *) *rsp; | | 503 | soa_rrstream_t *s = (soa_rrstream_t *) *rsp; |
504 | if (s->soa_tuple != NULL) | | 504 | if (s->soa_tuple != NULL) |
505 | dns_difftuple_free(&s->soa_tuple); | | 505 | dns_difftuple_free(&s->soa_tuple); |
506 | isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s)); | | 506 | isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s)); |
507 | } | | 507 | } |
508 | | | 508 | |
509 | static rrstream_methods_t soa_rrstream_methods = { | | 509 | static rrstream_methods_t soa_rrstream_methods = { |
510 | soa_rrstream_first, | | 510 | soa_rrstream_first, |
511 | soa_rrstream_next, | | 511 | soa_rrstream_next, |
512 | soa_rrstream_current, | | 512 | soa_rrstream_current, |
513 | rrstream_noop_pause, | | 513 | rrstream_noop_pause, |
514 | soa_rrstream_destroy | | 514 | soa_rrstream_destroy |
515 | }; | | 515 | }; |
516 | | | 516 | |
517 | /**************************************************************************/ | | 517 | /**************************************************************************/ |
518 | /* | | 518 | /* |
519 | * A 'compound_rrstream_t' objects owns a soa_rrstream | | 519 | * A 'compound_rrstream_t' objects owns a soa_rrstream |
520 | * and another rrstream, the "data stream". It returns | | 520 | * and another rrstream, the "data stream". It returns |
521 | * a concatenated stream consisting of the soa_rrstream, then | | 521 | * a concatenated stream consisting of the soa_rrstream, then |
522 | * the data stream, then the soa_rrstream again. | | 522 | * the data stream, then the soa_rrstream again. |
523 | * | | 523 | * |
524 | * The component streams are owned by the compound_rrstream_t | | 524 | * The component streams are owned by the compound_rrstream_t |
525 | * and are destroyed with it. | | 525 | * and are destroyed with it. |
526 | */ | | 526 | */ |
527 | | | 527 | |
528 | typedef struct compound_rrstream { | | 528 | typedef struct compound_rrstream { |
529 | rrstream_t common; | | 529 | rrstream_t common; |
530 | rrstream_t *components[3]; | | 530 | rrstream_t *components[3]; |
531 | int state; | | 531 | int state; |
532 | isc_result_t result; | | 532 | isc_result_t result; |
533 | } compound_rrstream_t; | | 533 | } compound_rrstream_t; |
534 | | | 534 | |
535 | /* | | 535 | /* |
536 | * Forward declarations. | | 536 | * Forward declarations. |
537 | */ | | 537 | */ |
538 | static void | | 538 | static void |
539 | compound_rrstream_destroy(rrstream_t **rsp); | | 539 | compound_rrstream_destroy(rrstream_t **rsp); |
540 | | | 540 | |
541 | static isc_result_t | | 541 | static isc_result_t |
542 | compound_rrstream_next(rrstream_t *rs); | | 542 | compound_rrstream_next(rrstream_t *rs); |
543 | | | 543 | |
544 | static rrstream_methods_t compound_rrstream_methods; | | 544 | static rrstream_methods_t compound_rrstream_methods; |
545 | | | 545 | |
546 | /* | | 546 | /* |
547 | * Requires: | | 547 | * Requires: |
548 | * soa_stream != NULL && *soa_stream != NULL | | 548 | * soa_stream != NULL && *soa_stream != NULL |
549 | * data_stream != NULL && *data_stream != NULL | | 549 | * data_stream != NULL && *data_stream != NULL |
550 | * sp != NULL && *sp == NULL | | 550 | * sp != NULL && *sp == NULL |
551 | * | | 551 | * |
552 | * Ensures: | | 552 | * Ensures: |
553 | * *soa_stream == NULL | | 553 | * *soa_stream == NULL |
554 | * *data_stream == NULL | | 554 | * *data_stream == NULL |
555 | * *sp points to a valid compound_rrstream_t | | 555 | * *sp points to a valid compound_rrstream_t |
556 | * The soa and data streams will be destroyed | | 556 | * The soa and data streams will be destroyed |
557 | * when the compound_rrstream_t is destroyed. | | 557 | * when the compound_rrstream_t is destroyed. |
558 | */ | | 558 | */ |
559 | static isc_result_t | | 559 | static isc_result_t |
560 | compound_rrstream_create(isc_mem_t *mctx, rrstream_t **soa_stream, | | 560 | compound_rrstream_create(isc_mem_t *mctx, rrstream_t **soa_stream, |
561 | rrstream_t **data_stream, rrstream_t **sp) | | 561 | rrstream_t **data_stream, rrstream_t **sp) |
562 | { | | 562 | { |
563 | compound_rrstream_t *s; | | 563 | compound_rrstream_t *s; |
564 | | | 564 | |
565 | INSIST(sp != NULL && *sp == NULL); | | 565 | INSIST(sp != NULL && *sp == NULL); |
566 | | | 566 | |
567 | s = isc_mem_get(mctx, sizeof(*s)); | | 567 | s = isc_mem_get(mctx, sizeof(*s)); |
568 | if (s == NULL) | | 568 | if (s == NULL) |
569 | return (ISC_R_NOMEMORY); | | 569 | return (ISC_R_NOMEMORY); |
570 | s->common.mctx = NULL; | | 570 | s->common.mctx = NULL; |
571 | isc_mem_attach(mctx, &s->common.mctx); | | 571 | isc_mem_attach(mctx, &s->common.mctx); |
572 | s->common.methods = &compound_rrstream_methods; | | 572 | s->common.methods = &compound_rrstream_methods; |
573 | s->components[0] = *soa_stream; | | 573 | s->components[0] = *soa_stream; |
574 | s->components[1] = *data_stream; | | 574 | s->components[1] = *data_stream; |
575 | s->components[2] = *soa_stream; | | 575 | s->components[2] = *soa_stream; |
576 | s->state = -1; | | 576 | s->state = -1; |
577 | s->result = ISC_R_FAILURE; | | 577 | s->result = ISC_R_FAILURE; |
578 | | | 578 | |
579 | *soa_stream = NULL; | | 579 | *soa_stream = NULL; |
580 | *data_stream = NULL; | | 580 | *data_stream = NULL; |
581 | *sp = (rrstream_t *) s; | | 581 | *sp = (rrstream_t *) s; |
582 | return (ISC_R_SUCCESS); | | 582 | return (ISC_R_SUCCESS); |
583 | } | | 583 | } |
584 | | | 584 | |
585 | static isc_result_t | | 585 | static isc_result_t |
586 | compound_rrstream_first(rrstream_t *rs) { | | 586 | compound_rrstream_first(rrstream_t *rs) { |
587 | compound_rrstream_t *s = (compound_rrstream_t *) rs; | | 587 | compound_rrstream_t *s = (compound_rrstream_t *) rs; |
588 | s->state = 0; | | 588 | s->state = 0; |
589 | do { | | 589 | do { |
590 | rrstream_t *curstream = s->components[s->state]; | | 590 | rrstream_t *curstream = s->components[s->state]; |
591 | s->result = curstream->methods->first(curstream); | | 591 | s->result = curstream->methods->first(curstream); |
592 | } while (s->result == ISC_R_NOMORE && s->state < 2); | | 592 | } while (s->result == ISC_R_NOMORE && s->state < 2); |
593 | return (s->result); | | 593 | return (s->result); |
594 | } | | 594 | } |
595 | | | 595 | |
596 | static isc_result_t | | 596 | static isc_result_t |
597 | compound_rrstream_next(rrstream_t *rs) { | | 597 | compound_rrstream_next(rrstream_t *rs) { |
598 | compound_rrstream_t *s = (compound_rrstream_t *) rs; | | 598 | compound_rrstream_t *s = (compound_rrstream_t *) rs; |
599 | rrstream_t *curstream = s->components[s->state]; | | 599 | rrstream_t *curstream = s->components[s->state]; |
600 | s->result = curstream->methods->next(curstream); | | 600 | s->result = curstream->methods->next(curstream); |
601 | while (s->result == ISC_R_NOMORE) { | | 601 | while (s->result == ISC_R_NOMORE) { |
602 | /* | | 602 | /* |
603 | * Make sure locks held by the current stream | | 603 | * Make sure locks held by the current stream |
604 | * are released before we switch streams. | | 604 | * are released before we switch streams. |
605 | */ | | 605 | */ |
606 | curstream->methods->pause(curstream); | | 606 | curstream->methods->pause(curstream); |
607 | if (s->state == 2) | | 607 | if (s->state == 2) |
608 | return (ISC_R_NOMORE); | | 608 | return (ISC_R_NOMORE); |
609 | s->state++; | | 609 | s->state++; |
610 | curstream = s->components[s->state]; | | 610 | curstream = s->components[s->state]; |
611 | s->result = curstream->methods->first(curstream); | | 611 | s->result = curstream->methods->first(curstream); |
612 | } | | 612 | } |
613 | return (s->result); | | 613 | return (s->result); |
614 | } | | 614 | } |
615 | | | 615 | |
616 | static void | | 616 | static void |
617 | compound_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, | | 617 | compound_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, |
618 | dns_rdata_t **rdata) | | 618 | dns_rdata_t **rdata) |
619 | { | | 619 | { |
620 | compound_rrstream_t *s = (compound_rrstream_t *) rs; | | 620 | compound_rrstream_t *s = (compound_rrstream_t *) rs; |
621 | rrstream_t *curstream; | | 621 | rrstream_t *curstream; |
622 | INSIST(0 <= s->state && s->state < 3); | | 622 | INSIST(0 <= s->state && s->state < 3); |
623 | INSIST(s->result == ISC_R_SUCCESS); | | 623 | INSIST(s->result == ISC_R_SUCCESS); |
624 | curstream = s->components[s->state]; | | 624 | curstream = s->components[s->state]; |
625 | curstream->methods->current(curstream, name, ttl, rdata); | | 625 | curstream->methods->current(curstream, name, ttl, rdata); |
626 | } | | 626 | } |
627 | | | 627 | |
628 | static void | | 628 | static void |
629 | compound_rrstream_pause(rrstream_t *rs) | | 629 | compound_rrstream_pause(rrstream_t *rs) |
630 | { | | 630 | { |
631 | compound_rrstream_t *s = (compound_rrstream_t *) rs; | | 631 | compound_rrstream_t *s = (compound_rrstream_t *) rs; |
632 | rrstream_t *curstream; | | 632 | rrstream_t *curstream; |
633 | INSIST(0 <= s->state && s->state < 3); | | 633 | INSIST(0 <= s->state && s->state < 3); |
634 | curstream = s->components[s->state]; | | 634 | curstream = s->components[s->state]; |
635 | curstream->methods->pause(curstream); | | 635 | curstream->methods->pause(curstream); |
636 | } | | 636 | } |
637 | | | 637 | |
638 | static void | | 638 | static void |
639 | compound_rrstream_destroy(rrstream_t **rsp) { | | 639 | compound_rrstream_destroy(rrstream_t **rsp) { |
640 | compound_rrstream_t *s = (compound_rrstream_t *) *rsp; | | 640 | compound_rrstream_t *s = (compound_rrstream_t *) *rsp; |
641 | s->components[0]->methods->destroy(&s->components[0]); | | 641 | s->components[0]->methods->destroy(&s->components[0]); |
642 | s->components[1]->methods->destroy(&s->components[1]); | | 642 | s->components[1]->methods->destroy(&s->components[1]); |
643 | s->components[2] = NULL; /* Copy of components[0]. */ | | 643 | s->components[2] = NULL; /* Copy of components[0]. */ |
644 | isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s)); | | 644 | isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s)); |
645 | } | | 645 | } |
646 | | | 646 | |
647 | static rrstream_methods_t compound_rrstream_methods = { | | 647 | static rrstream_methods_t compound_rrstream_methods = { |
648 | compound_rrstream_first, | | 648 | compound_rrstream_first, |
649 | compound_rrstream_next, | | 649 | compound_rrstream_next, |
650 | compound_rrstream_current, | | 650 | compound_rrstream_current, |
651 | compound_rrstream_pause, | | 651 | compound_rrstream_pause, |
652 | compound_rrstream_destroy | | 652 | compound_rrstream_destroy |
653 | }; | | 653 | }; |
654 | | | 654 | |
655 | /**************************************************************************/ | | 655 | /**************************************************************************/ |
656 | /* | | 656 | /* |
657 | * An 'xfrout_ctx_t' contains the state of an outgoing AXFR or IXFR | | 657 | * An 'xfrout_ctx_t' contains the state of an outgoing AXFR or IXFR |
658 | * in progress. | | 658 | * in progress. |
659 | */ | | 659 | */ |
660 | | | 660 | |
661 | typedef struct { | | 661 | typedef struct { |
662 | isc_mem_t *mctx; | | 662 | isc_mem_t *mctx; |
663 | ns_client_t *client; | | 663 | ns_client_t *client; |
664 | unsigned int id; /* ID of request */ | | 664 | unsigned int id; /* ID of request */ |
665 | dns_name_t *qname; /* Question name of request */ | | 665 | dns_name_t *qname; /* Question name of request */ |
666 | dns_rdatatype_t qtype; /* dns_rdatatype_{a,i}xfr */ | | 666 | dns_rdatatype_t qtype; /* dns_rdatatype_{a,i}xfr */ |
667 | dns_rdataclass_t qclass; | | 667 | dns_rdataclass_t qclass; |
668 | dns_zone_t *zone; /* (necessary for stats) */ | | 668 | dns_zone_t *zone; /* (necessary for stats) */ |
669 | dns_db_t *db; | | 669 | dns_db_t *db; |
670 | dns_dbversion_t *ver; | | 670 | dns_dbversion_t *ver; |
671 | isc_quota_t *quota; | | 671 | isc_quota_t *quota; |
672 | rrstream_t *stream; /* The XFR RR stream */ | | 672 | rrstream_t *stream; /* The XFR RR stream */ |
673 | isc_boolean_t end_of_stream; /* EOS has been reached */ | | 673 | isc_boolean_t end_of_stream; /* EOS has been reached */ |
674 | isc_buffer_t buf; /* Buffer for message owner | | 674 | isc_buffer_t buf; /* Buffer for message owner |
675 | names and rdatas */ | | 675 | names and rdatas */ |
676 | isc_buffer_t txlenbuf; /* Transmit length buffer */ | | 676 | isc_buffer_t txlenbuf; /* Transmit length buffer */ |
677 | isc_buffer_t txbuf; /* Transmit message buffer */ | | 677 | isc_buffer_t txbuf; /* Transmit message buffer */ |
678 | void *txmem; | | 678 | void *txmem; |
679 | unsigned int txmemlen; | | 679 | unsigned int txmemlen; |
680 | unsigned int nmsg; /* Number of messages sent */ | | 680 | unsigned int nmsg; /* Number of messages sent */ |
681 | dns_tsigkey_t *tsigkey; /* Key used to create TSIG */ | | 681 | dns_tsigkey_t *tsigkey; /* Key used to create TSIG */ |
682 | isc_buffer_t *lasttsig; /* the last TSIG */ | | 682 | isc_buffer_t *lasttsig; /* the last TSIG */ |
683 | isc_boolean_t many_answers; | | 683 | isc_boolean_t many_answers; |
684 | int sends; /* Send in progress */ | | 684 | int sends; /* Send in progress */ |
685 | isc_boolean_t shuttingdown; | | 685 | isc_boolean_t shuttingdown; |
686 | const char *mnemonic; /* Style of transfer */ | | 686 | const char *mnemonic; /* Style of transfer */ |
687 | } xfrout_ctx_t; | | 687 | } xfrout_ctx_t; |
688 | | | 688 | |
689 | static isc_result_t | | 689 | static isc_result_t |
690 | xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, | | 690 | xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, |
691 | unsigned int id, dns_name_t *qname, dns_rdatatype_t qtype, | | 691 | unsigned int id, dns_name_t *qname, dns_rdatatype_t qtype, |
692 | dns_rdataclass_t qclass, dns_zone_t *zone, | | 692 | dns_rdataclass_t qclass, dns_zone_t *zone, |
693 | dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, | | 693 | dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, |
694 | rrstream_t *stream, dns_tsigkey_t *tsigkey, | | 694 | rrstream_t *stream, dns_tsigkey_t *tsigkey, |
695 | isc_buffer_t *lasttsig, | | 695 | isc_buffer_t *lasttsig, |
696 | unsigned int maxtime, | | 696 | unsigned int maxtime, |
697 | unsigned int idletime, | | 697 | unsigned int idletime, |
698 | isc_boolean_t many_answers, | | 698 | isc_boolean_t many_answers, |
699 | xfrout_ctx_t **xfrp); | | 699 | xfrout_ctx_t **xfrp); |
700 | | | 700 | |
701 | static void | | 701 | static void |
702 | sendstream(xfrout_ctx_t *xfr); | | 702 | sendstream(xfrout_ctx_t *xfr); |
703 | | | 703 | |
704 | static void | | 704 | static void |
705 | xfrout_senddone(isc_task_t *task, isc_event_t *event); | | 705 | xfrout_senddone(isc_task_t *task, isc_event_t *event); |
706 | | | 706 | |
707 | static void | | 707 | static void |
708 | xfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg); | | 708 | xfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg); |
709 | | | 709 | |
710 | static void | | 710 | static void |
711 | xfrout_maybe_destroy(xfrout_ctx_t *xfr); | | 711 | xfrout_maybe_destroy(xfrout_ctx_t *xfr); |
712 | | | 712 | |
713 | static void | | 713 | static void |
714 | xfrout_ctx_destroy(xfrout_ctx_t **xfrp); | | 714 | xfrout_ctx_destroy(xfrout_ctx_t **xfrp); |
715 | | | 715 | |
716 | static void | | 716 | static void |
717 | xfrout_client_shutdown(void *arg, isc_result_t result); | | 717 | xfrout_client_shutdown(void *arg, isc_result_t result); |
718 | | | 718 | |
719 | static void | | 719 | static void |
720 | xfrout_log1(ns_client_t *client, dns_name_t *zonename, | | 720 | xfrout_log1(ns_client_t *client, dns_name_t *zonename, |
721 | dns_rdataclass_t rdclass, int level, | | 721 | dns_rdataclass_t rdclass, int level, |
722 | const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6); | | 722 | const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6); |
723 | | | 723 | |
724 | static void | | 724 | static void |
725 | xfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...) | | 725 | xfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...) |
726 | ISC_FORMAT_PRINTF(3, 4); | | 726 | ISC_FORMAT_PRINTF(3, 4); |
727 | | | 727 | |
728 | /**************************************************************************/ | | 728 | /**************************************************************************/ |
729 | | | 729 | |
730 | void | | 730 | void |
731 | ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { | | 731 | ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { |
732 | isc_result_t result; | | 732 | isc_result_t result; |
733 | dns_name_t *question_name; | | 733 | dns_name_t *question_name; |
734 | dns_rdataset_t *question_rdataset; | | 734 | dns_rdataset_t *question_rdataset; |
735 | dns_zone_t *zone = NULL, *raw = NULL, *mayberaw; | | 735 | dns_zone_t *zone = NULL, *raw = NULL, *mayberaw; |
736 | dns_db_t *db = NULL; | | 736 | dns_db_t *db = NULL; |
737 | dns_dbversion_t *ver = NULL; | | 737 | dns_dbversion_t *ver = NULL; |
738 | dns_rdataclass_t question_class; | | 738 | dns_rdataclass_t question_class; |
739 | rrstream_t *soa_stream = NULL; | | 739 | rrstream_t *soa_stream = NULL; |
740 | rrstream_t *data_stream = NULL; | | 740 | rrstream_t *data_stream = NULL; |
741 | rrstream_t *stream = NULL; | | 741 | rrstream_t *stream = NULL; |
742 | dns_difftuple_t *current_soa_tuple = NULL; | | 742 | dns_difftuple_t *current_soa_tuple = NULL; |
743 | dns_name_t *soa_name; | | 743 | dns_name_t *soa_name; |
744 | dns_rdataset_t *soa_rdataset; | | 744 | dns_rdataset_t *soa_rdataset; |
745 | dns_rdata_t soa_rdata = DNS_RDATA_INIT; | | 745 | dns_rdata_t soa_rdata = DNS_RDATA_INIT; |
746 | isc_boolean_t have_soa = ISC_FALSE; | | 746 | isc_boolean_t have_soa = ISC_FALSE; |
747 | const char *mnemonic = NULL; | | 747 | const char *mnemonic = NULL; |
748 | isc_mem_t *mctx = client->mctx; | | 748 | isc_mem_t *mctx = client->mctx; |
749 | dns_message_t *request = client->message; | | 749 | dns_message_t *request = client->message; |
750 | xfrout_ctx_t *xfr = NULL; | | 750 | xfrout_ctx_t *xfr = NULL; |
751 | isc_quota_t *quota = NULL; | | 751 | isc_quota_t *quota = NULL; |
752 | dns_transfer_format_t format = client->view->transfer_format; | | 752 | dns_transfer_format_t format = client->view->transfer_format; |
753 | isc_netaddr_t na; | | 753 | isc_netaddr_t na; |
754 | dns_peer_t *peer = NULL; | | 754 | dns_peer_t *peer = NULL; |
755 | isc_buffer_t *tsigbuf = NULL; | | 755 | isc_buffer_t *tsigbuf = NULL; |
756 | char *journalfile; | | 756 | char *journalfile; |
757 | char msg[NS_CLIENT_ACLMSGSIZE("zone transfer")]; | | 757 | char msg[NS_CLIENT_ACLMSGSIZE("zone transfer")]; |
758 | char keyname[DNS_NAME_FORMATSIZE]; | | 758 | char keyname[DNS_NAME_FORMATSIZE]; |
759 | isc_boolean_t is_poll = ISC_FALSE; | | 759 | isc_boolean_t is_poll = ISC_FALSE; |
760 | isc_boolean_t is_dlz = ISC_FALSE; | | 760 | isc_boolean_t is_dlz = ISC_FALSE; |
761 | isc_boolean_t is_ixfr = ISC_FALSE; | | 761 | isc_boolean_t is_ixfr = ISC_FALSE; |
762 | isc_uint32_t begin_serial = 0, current_serial; | | 762 | isc_uint32_t begin_serial = 0, current_serial; |
763 | | | 763 | |
764 | switch (reqtype) { | | 764 | switch (reqtype) { |
765 | case dns_rdatatype_axfr: | | 765 | case dns_rdatatype_axfr: |
766 | mnemonic = "AXFR"; | | 766 | mnemonic = "AXFR"; |
767 | break; | | 767 | break; |
768 | case dns_rdatatype_ixfr: | | 768 | case dns_rdatatype_ixfr: |
769 | mnemonic = "IXFR"; | | 769 | mnemonic = "IXFR"; |
770 | break; | | 770 | break; |
771 | default: | | 771 | default: |
772 | INSIST(0); | | 772 | INSIST(0); |
773 | break; | | 773 | break; |
774 | } | | 774 | } |
775 | | | 775 | |
776 | ns_client_log(client, | | 776 | ns_client_log(client, |
777 | DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT, | | 777 | DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT, |
778 | ISC_LOG_DEBUG(6), "%s request", mnemonic); | | 778 | ISC_LOG_DEBUG(6), "%s request", mnemonic); |
779 | /* | | 779 | /* |
780 | * Apply quota. | | 780 | * Apply quota. |
781 | */ | | 781 | */ |
782 | result = isc_quota_attach(&ns_g_server->xfroutquota, "a); | | 782 | result = isc_quota_attach(&ns_g_server->xfroutquota, "a); |
783 | if (result != ISC_R_SUCCESS) { | | 783 | if (result != ISC_R_SUCCESS) { |
784 | isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING, | | 784 | isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING, |
785 | "%s request denied: %s", mnemonic, | | 785 | "%s request denied: %s", mnemonic, |
786 | isc_result_totext(result)); | | 786 | isc_result_totext(result)); |
787 | goto failure; | | 787 | goto failure; |
788 | } | | 788 | } |
789 | | | 789 | |
790 | /* | | 790 | /* |
791 | * Interpret the question section. | | 791 | * Interpret the question section. |
792 | */ | | 792 | */ |
793 | result = dns_message_firstname(request, DNS_SECTION_QUESTION); | | 793 | result = dns_message_firstname(request, DNS_SECTION_QUESTION); |
794 | INSIST(result == ISC_R_SUCCESS); | | 794 | INSIST(result == ISC_R_SUCCESS); |
795 | | | 795 | |
796 | /* | | 796 | /* |
797 | * The question section must contain exactly one question, and | | 797 | * The question section must contain exactly one question, and |
798 | * it must be for AXFR/IXFR as appropriate. | | 798 | * it must be for AXFR/IXFR as appropriate. |
799 | */ | | 799 | */ |
800 | question_name = NULL; | | 800 | question_name = NULL; |
801 | dns_message_currentname(request, DNS_SECTION_QUESTION, &question_name); | | 801 | dns_message_currentname(request, DNS_SECTION_QUESTION, &question_name); |
802 | question_rdataset = ISC_LIST_HEAD(question_name->list); | | 802 | question_rdataset = ISC_LIST_HEAD(question_name->list); |
803 | question_class = question_rdataset->rdclass; | | 803 | question_class = question_rdataset->rdclass; |
804 | INSIST(question_rdataset->type == reqtype); | | 804 | INSIST(question_rdataset->type == reqtype); |
805 | if (ISC_LIST_NEXT(question_rdataset, link) != NULL) | | 805 | if (ISC_LIST_NEXT(question_rdataset, link) != NULL) |
806 | FAILC(DNS_R_FORMERR, "multiple questions"); | | 806 | FAILC(DNS_R_FORMERR, "multiple questions"); |
807 | result = dns_message_nextname(request, DNS_SECTION_QUESTION); | | 807 | result = dns_message_nextname(request, DNS_SECTION_QUESTION); |
808 | if (result != ISC_R_NOMORE) | | 808 | if (result != ISC_R_NOMORE) |
809 | FAILC(DNS_R_FORMERR, "multiple questions"); | | 809 | FAILC(DNS_R_FORMERR, "multiple questions"); |
810 | | | 810 | |
811 | result = dns_zt_find(client->view->zonetable, question_name, 0, NULL, | | 811 | result = dns_zt_find(client->view->zonetable, question_name, 0, NULL, |
812 | &zone); | | 812 | &zone); |
813 | | | 813 | |
814 | if (result != ISC_R_SUCCESS) { | | 814 | if (result != ISC_R_SUCCESS) { |
815 | /* | | 815 | /* |
816 | * Normal zone table does not have a match. | | 816 | * Normal zone table does not have a match. |
817 | * Try the DLZ database | | 817 | * Try the DLZ database |
818 | */ | | 818 | */ |
819 | // Temporary: only searching the first DLZ database | | 819 | // Temporary: only searching the first DLZ database |
820 | if (! ISC_LIST_EMPTY(client->view->dlz_searched)) { | | 820 | if (! ISC_LIST_EMPTY(client->view->dlz_searched)) { |
821 | result = dns_dlzallowzonexfr(client->view, | | 821 | result = dns_dlzallowzonexfr(client->view, |
822 | question_name, | | 822 | question_name, |
823 | &client->peeraddr, | | 823 | &client->peeraddr, |
824 | &db); | | 824 | &db); |
825 | | | 825 | |
826 | pfilter_notify(result, client, "zonexfr"); | | 826 | pfilter_notify(result, client, "zonexfr"); |
827 | if (result == ISC_R_NOPERM) { | | 827 | if (result == ISC_R_NOPERM) { |
828 | char _buf1[DNS_NAME_FORMATSIZE]; | | 828 | char _buf1[DNS_NAME_FORMATSIZE]; |
829 | char _buf2[DNS_RDATACLASS_FORMATSIZE]; | | 829 | char _buf2[DNS_RDATACLASS_FORMATSIZE]; |
830 | | | 830 | |
831 | result = DNS_R_REFUSED; | | 831 | result = DNS_R_REFUSED; |
832 | dns_name_format(question_name, _buf1, | | 832 | dns_name_format(question_name, _buf1, |
833 | sizeof(_buf1)); | | 833 | sizeof(_buf1)); |
834 | dns_rdataclass_format(question_class, | | 834 | dns_rdataclass_format(question_class, |
835 | _buf2, sizeof(_buf2)); | | 835 | _buf2, sizeof(_buf2)); |
836 | ns_client_log(client, DNS_LOGCATEGORY_SECURITY, | | 836 | ns_client_log(client, DNS_LOGCATEGORY_SECURITY, |
837 | NS_LOGMODULE_XFER_OUT, | | 837 | NS_LOGMODULE_XFER_OUT, |
838 | ISC_LOG_ERROR, | | 838 | ISC_LOG_ERROR, |
839 | "zone transfer '%s/%s' denied", | | 839 | "zone transfer '%s/%s' denied", |
840 | _buf1, _buf2); | | 840 | _buf1, _buf2); |
841 | goto failure; | | 841 | goto failure; |
842 | } | | 842 | } |
843 | if (result != ISC_R_SUCCESS) | | 843 | if (result != ISC_R_SUCCESS) |
844 | FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", | | 844 | FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", |
845 | question_name, question_class); | | 845 | question_name, question_class); |
846 | is_dlz = ISC_TRUE; | | 846 | is_dlz = ISC_TRUE; |
847 | } else { | | 847 | } else { |
848 | /* | | 848 | /* |
849 | * not DLZ and not in normal zone table, we are | | 849 | * not DLZ and not in normal zone table, we are |
850 | * not authoritative | | 850 | * not authoritative |
851 | */ | | 851 | */ |
852 | FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", | | 852 | FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", |
853 | question_name, question_class); | | 853 | question_name, question_class); |
854 | } | | 854 | } |
855 | } else { | | 855 | } else { |
856 | /* zone table has a match */ | | 856 | /* zone table has a match */ |
857 | switch(dns_zone_gettype(zone)) { | | 857 | switch(dns_zone_gettype(zone)) { |
858 | /* Master and slave zones are OK for transfer. */ | | 858 | /* Master and slave zones are OK for transfer. */ |
859 | case dns_zone_master: | | 859 | case dns_zone_master: |
860 | case dns_zone_slave: | | 860 | case dns_zone_slave: |
861 | case dns_zone_dlz: | | 861 | case dns_zone_dlz: |
862 | break; | | 862 | break; |
863 | default: | | 863 | default: |
864 | FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", | | 864 | FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", |
865 | question_name, question_class); | | 865 | question_name, question_class); |
866 | } | | 866 | } |
867 | CHECK(dns_zone_getdb(zone, &db)); | | 867 | CHECK(dns_zone_getdb(zone, &db)); |
868 | dns_db_currentversion(db, &ver); | | 868 | dns_db_currentversion(db, &ver); |
869 | } | | 869 | } |
870 | | | 870 | |
871 | xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), | | 871 | xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), |
872 | "%s question section OK", mnemonic); | | 872 | "%s question section OK", mnemonic); |
873 | | | 873 | |
874 | /* | | 874 | /* |
875 | * Check the authority section. Look for a SOA record with | | 875 | * Check the authority section. Look for a SOA record with |
876 | * the same name and class as the question. | | 876 | * the same name and class as the question. |
877 | */ | | 877 | */ |
878 | for (result = dns_message_firstname(request, DNS_SECTION_AUTHORITY); | | 878 | for (result = dns_message_firstname(request, DNS_SECTION_AUTHORITY); |
879 | result == ISC_R_SUCCESS; | | 879 | result == ISC_R_SUCCESS; |
880 | result = dns_message_nextname(request, DNS_SECTION_AUTHORITY)) | | 880 | result = dns_message_nextname(request, DNS_SECTION_AUTHORITY)) |
881 | { | | 881 | { |
882 | soa_name = NULL; | | 882 | soa_name = NULL; |
883 | dns_message_currentname(request, DNS_SECTION_AUTHORITY, | | 883 | dns_message_currentname(request, DNS_SECTION_AUTHORITY, |
884 | &soa_name); | | 884 | &soa_name); |
885 | | | 885 | |
886 | /* | | 886 | /* |
887 | * Ignore data whose owner name is not the zone apex. | | 887 | * Ignore data whose owner name is not the zone apex. |
888 | */ | | 888 | */ |
889 | if (! dns_name_equal(soa_name, question_name)) | | 889 | if (! dns_name_equal(soa_name, question_name)) |
890 | continue; | | 890 | continue; |
891 | | | 891 | |
892 | for (soa_rdataset = ISC_LIST_HEAD(soa_name->list); | | 892 | for (soa_rdataset = ISC_LIST_HEAD(soa_name->list); |
893 | soa_rdataset != NULL; | | 893 | soa_rdataset != NULL; |
894 | soa_rdataset = ISC_LIST_NEXT(soa_rdataset, link)) | | 894 | soa_rdataset = ISC_LIST_NEXT(soa_rdataset, link)) |
895 | { | | 895 | { |
896 | /* | | 896 | /* |
897 | * Ignore non-SOA data. | | 897 | * Ignore non-SOA data. |
898 | */ | | 898 | */ |
899 | if (soa_rdataset->type != dns_rdatatype_soa) | | 899 | if (soa_rdataset->type != dns_rdatatype_soa) |
900 | continue; | | 900 | continue; |
901 | if (soa_rdataset->rdclass != question_class) | | 901 | if (soa_rdataset->rdclass != question_class) |
902 | continue; | | 902 | continue; |
903 | | | 903 | |
904 | CHECK(dns_rdataset_first(soa_rdataset)); | | 904 | CHECK(dns_rdataset_first(soa_rdataset)); |
905 | dns_rdataset_current(soa_rdataset, &soa_rdata); | | 905 | dns_rdataset_current(soa_rdataset, &soa_rdata); |
906 | result = dns_rdataset_next(soa_rdataset); | | 906 | result = dns_rdataset_next(soa_rdataset); |
907 | if (result == ISC_R_SUCCESS) | | 907 | if (result == ISC_R_SUCCESS) |
908 | FAILC(DNS_R_FORMERR, | | 908 | FAILC(DNS_R_FORMERR, |
909 | "IXFR authority section " | | 909 | "IXFR authority section " |
910 | "has multiple SOAs"); | | 910 | "has multiple SOAs"); |
911 | have_soa = ISC_TRUE; | | 911 | have_soa = ISC_TRUE; |
912 | goto got_soa; | | 912 | goto got_soa; |
913 | } | | 913 | } |
914 | } | | 914 | } |
915 | got_soa: | | 915 | got_soa: |
916 | if (result != ISC_R_NOMORE) | | 916 | if (result != ISC_R_NOMORE) |
917 | CHECK(result); | | 917 | CHECK(result); |
918 | | | 918 | |
919 | xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), | | 919 | xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), |
920 | "%s authority section OK", mnemonic); | | 920 | "%s authority section OK", mnemonic); |
921 | | | 921 | |
922 | /* | | 922 | /* |
923 | * If not a DLZ zone, decide whether to allow this transfer. | | 923 | * If not a DLZ zone, decide whether to allow this transfer. |
924 | */ | | 924 | */ |
925 | if (!is_dlz) { | | 925 | if (!is_dlz) { |
926 | ns_client_aclmsg("zone transfer", question_name, reqtype, | | 926 | ns_client_aclmsg("zone transfer", question_name, reqtype, |
927 | client->view->rdclass, msg, sizeof(msg)); | | 927 | client->view->rdclass, msg, sizeof(msg)); |
928 | CHECK(ns_client_checkacl(client, NULL, msg, | | 928 | CHECK(ns_client_checkacl(client, NULL, msg, |
929 | dns_zone_getxfracl(zone), | | 929 | dns_zone_getxfracl(zone), |
930 | ISC_TRUE, ISC_LOG_ERROR)); | | 930 | ISC_TRUE, ISC_LOG_ERROR)); |
931 | } | | 931 | } |
932 | | | 932 | |
933 | /* | | 933 | /* |
934 | * AXFR over UDP is not possible. | | 934 | * AXFR over UDP is not possible. |
935 | */ | | 935 | */ |
936 | if (reqtype == dns_rdatatype_axfr && | | 936 | if (reqtype == dns_rdatatype_axfr && |
937 | (client->attributes & NS_CLIENTATTR_TCP) == 0) | | 937 | (client->attributes & NS_CLIENTATTR_TCP) == 0) |
938 | FAILC(DNS_R_FORMERR, "attempted AXFR over UDP"); | | 938 | FAILC(DNS_R_FORMERR, "attempted AXFR over UDP"); |
939 | | | 939 | |
940 | /* | | 940 | /* |
941 | * Look up the requesting server in the peer table. | | 941 | * Look up the requesting server in the peer table. |
942 | */ | | 942 | */ |
943 | isc_netaddr_fromsockaddr(&na, &client->peeraddr); | | 943 | isc_netaddr_fromsockaddr(&na, &client->peeraddr); |
944 | (void)dns_peerlist_peerbyaddr(client->view->peers, &na, &peer); | | 944 | (void)dns_peerlist_peerbyaddr(client->view->peers, &na, &peer); |
945 | | | 945 | |
946 | /* | | 946 | /* |
947 | * Decide on the transfer format (one-answer or many-answers). | | 947 | * Decide on the transfer format (one-answer or many-answers). |
948 | */ | | 948 | */ |
949 | if (peer != NULL) | | 949 | if (peer != NULL) |
950 | (void)dns_peer_gettransferformat(peer, &format); | | 950 | (void)dns_peer_gettransferformat(peer, &format); |
951 | | | 951 | |
952 | /* | | 952 | /* |
953 | * Get a dynamically allocated copy of the current SOA. | | 953 | * Get a dynamically allocated copy of the current SOA. |
954 | */ | | 954 | */ |
955 | if (is_dlz) | | 955 | if (is_dlz) |
956 | dns_db_currentversion(db, &ver); | | 956 | dns_db_currentversion(db, &ver); |
957 | | | 957 | |
958 | CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, | | 958 | CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, |
959 | ¤t_soa_tuple)); | | 959 | ¤t_soa_tuple)); |
960 | | | 960 | |
961 | current_serial = dns_soa_getserial(¤t_soa_tuple->rdata); | | 961 | current_serial = dns_soa_getserial(¤t_soa_tuple->rdata); |
962 | if (reqtype == dns_rdatatype_ixfr) { | | 962 | if (reqtype == dns_rdatatype_ixfr) { |
963 | isc_boolean_t provide_ixfr; | | 963 | isc_boolean_t provide_ixfr; |
964 | | | 964 | |
965 | /* | | 965 | /* |
966 | * Outgoing IXFR may have been disabled for this peer | | 966 | * Outgoing IXFR may have been disabled for this peer |
967 | * or globally. | | 967 | * or globally. |
968 | */ | | 968 | */ |
969 | provide_ixfr = client->view->provideixfr; | | 969 | provide_ixfr = client->view->provideixfr; |
970 | if (peer != NULL) | | 970 | if (peer != NULL) |
971 | (void) dns_peer_getprovideixfr(peer, &provide_ixfr); | | 971 | (void) dns_peer_getprovideixfr(peer, &provide_ixfr); |
972 | if (provide_ixfr == ISC_FALSE) | | 972 | if (provide_ixfr == ISC_FALSE) |
973 | goto axfr_fallback; | | 973 | goto axfr_fallback; |
974 | | | 974 | |
975 | if (! have_soa) | | 975 | if (! have_soa) |
976 | FAILC(DNS_R_FORMERR, | | 976 | FAILC(DNS_R_FORMERR, |
977 | "IXFR request missing SOA"); | | 977 | "IXFR request missing SOA"); |
978 | | | 978 | |
979 | begin_serial = dns_soa_getserial(&soa_rdata); | | 979 | begin_serial = dns_soa_getserial(&soa_rdata); |
980 | | | 980 | |
981 | /* | | 981 | /* |
982 | * RFC1995 says "If an IXFR query with the same or | | 982 | * RFC1995 says "If an IXFR query with the same or |
983 | * newer version number than that of the server | | 983 | * newer version number than that of the server |
984 | * is received, it is replied to with a single SOA | | 984 | * is received, it is replied to with a single SOA |
985 | * record of the server's current version, just as | | 985 | * record of the server's current version, just as |
986 | * in AXFR". The claim about AXFR is incorrect, | | 986 | * in AXFR". The claim about AXFR is incorrect, |
987 | * but other than that, we do as the RFC says. | | 987 | * but other than that, we do as the RFC says. |
988 | * | | 988 | * |
989 | * Sending a single SOA record is also how we refuse | | 989 | * Sending a single SOA record is also how we refuse |
990 | * IXFR over UDP (currently, we always do). | | 990 | * IXFR over UDP (currently, we always do). |
991 | */ | | 991 | */ |
992 | if (DNS_SERIAL_GE(begin_serial, current_serial) || | | 992 | if (DNS_SERIAL_GE(begin_serial, current_serial) || |
993 | (client->attributes & NS_CLIENTATTR_TCP) == 0) | | 993 | (client->attributes & NS_CLIENTATTR_TCP) == 0) |
994 | { | | 994 | { |
995 | CHECK(soa_rrstream_create(mctx, db, ver, &stream)); | | 995 | CHECK(soa_rrstream_create(mctx, db, ver, &stream)); |
996 | is_poll = ISC_TRUE; | | 996 | is_poll = ISC_TRUE; |
997 | goto have_stream; | | 997 | goto have_stream; |
998 | } | | 998 | } |
999 | journalfile = is_dlz ? NULL : dns_zone_getjournal(zone); | | 999 | journalfile = is_dlz ? NULL : dns_zone_getjournal(zone); |
1000 | if (journalfile != NULL) | | 1000 | if (journalfile != NULL) |
1001 | result = ixfr_rrstream_create(mctx, | | 1001 | result = ixfr_rrstream_create(mctx, |
1002 | journalfile, | | 1002 | journalfile, |
1003 | begin_serial, | | 1003 | begin_serial, |
1004 | current_serial, | | 1004 | current_serial, |
1005 | &data_stream); | | 1005 | &data_stream); |
1006 | else | | 1006 | else |
1007 | result = ISC_R_NOTFOUND; | | 1007 | result = ISC_R_NOTFOUND; |
1008 | if (result == ISC_R_NOTFOUND || | | 1008 | if (result == ISC_R_NOTFOUND || |
1009 | result == ISC_R_RANGE) { | | 1009 | result == ISC_R_RANGE) { |
1010 | xfrout_log1(client, question_name, question_class, | | 1010 | xfrout_log1(client, question_name, question_class, |
1011 | ISC_LOG_DEBUG(4), | | 1011 | ISC_LOG_DEBUG(4), |
1012 | "IXFR version not in journal, " | | 1012 | "IXFR version not in journal, " |
1013 | "falling back to AXFR"); | | 1013 | "falling back to AXFR"); |
1014 | mnemonic = "AXFR-style IXFR"; | | 1014 | mnemonic = "AXFR-style IXFR"; |
1015 | goto axfr_fallback; | | 1015 | goto axfr_fallback; |
1016 | } | | 1016 | } |
1017 | CHECK(result); | | 1017 | CHECK(result); |
1018 | is_ixfr = ISC_TRUE; | | 1018 | is_ixfr = ISC_TRUE; |
1019 | } else { | | 1019 | } else { |
1020 | axfr_fallback: | | 1020 | axfr_fallback: |
1021 | CHECK(axfr_rrstream_create(mctx, db, ver, &data_stream)); | | 1021 | CHECK(axfr_rrstream_create(mctx, db, ver, &data_stream)); |
1022 | } | | 1022 | } |
1023 | | | 1023 | |
1024 | /* | | 1024 | /* |
1025 | * Bracket the data stream with SOAs. | | 1025 | * Bracket the data stream with SOAs. |
1026 | */ | | 1026 | */ |
1027 | CHECK(soa_rrstream_create(mctx, db, ver, &soa_stream)); | | 1027 | CHECK(soa_rrstream_create(mctx, db, ver, &soa_stream)); |
1028 | CHECK(compound_rrstream_create(mctx, &soa_stream, &data_stream, | | 1028 | CHECK(compound_rrstream_create(mctx, &soa_stream, &data_stream, |
1029 | &stream)); | | 1029 | &stream)); |
1030 | soa_stream = NULL; | | 1030 | soa_stream = NULL; |
1031 | data_stream = NULL; | | 1031 | data_stream = NULL; |
1032 | | | 1032 | |
1033 | have_stream: | | 1033 | have_stream: |
1034 | CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf)); | | 1034 | CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf)); |
1035 | /* | | 1035 | /* |
1036 | * Create the xfrout context object. This transfers the ownership | | 1036 | * Create the xfrout context object. This transfers the ownership |
1037 | * of "stream", "db", "ver", and "quota" to the xfrout context object. | | 1037 | * of "stream", "db", "ver", and "quota" to the xfrout context object. |
1038 | */ | | 1038 | */ |
1039 | | | 1039 | |
1040 | | | 1040 | |
1041 | | | 1041 | |
1042 | if (is_dlz) | | 1042 | if (is_dlz) |
1043 | CHECK(xfrout_ctx_create(mctx, client, request->id, | | 1043 | CHECK(xfrout_ctx_create(mctx, client, request->id, |
1044 | question_name, reqtype, question_class, | | 1044 | question_name, reqtype, question_class, |
1045 | zone, db, ver, quota, stream, | | 1045 | zone, db, ver, quota, stream, |
1046 | dns_message_gettsigkey(request), | | 1046 | dns_message_gettsigkey(request), |
1047 | tsigbuf, | | 1047 | tsigbuf, |
1048 | 3600, | | 1048 | 3600, |
1049 | 3600, | | 1049 | 3600, |
1050 | (format == dns_many_answers) ? | | 1050 | (format == dns_many_answers) ? |
1051 | ISC_TRUE : ISC_FALSE, | | 1051 | ISC_TRUE : ISC_FALSE, |
1052 | &xfr)); | | 1052 | &xfr)); |
1053 | else | | 1053 | else |
1054 | CHECK(xfrout_ctx_create(mctx, client, request->id, | | 1054 | CHECK(xfrout_ctx_create(mctx, client, request->id, |
1055 | question_name, reqtype, question_class, | | 1055 | question_name, reqtype, question_class, |
1056 | zone, db, ver, quota, stream, | | 1056 | zone, db, ver, quota, stream, |
1057 | dns_message_gettsigkey(request), | | 1057 | dns_message_gettsigkey(request), |
1058 | tsigbuf, | | 1058 | tsigbuf, |
1059 | dns_zone_getmaxxfrout(zone), | | 1059 | dns_zone_getmaxxfrout(zone), |
1060 | dns_zone_getidleout(zone), | | 1060 | dns_zone_getidleout(zone), |
1061 | (format == dns_many_answers) ? | | 1061 | (format == dns_many_answers) ? |
1062 | ISC_TRUE : ISC_FALSE, | | 1062 | ISC_TRUE : ISC_FALSE, |
1063 | &xfr)); | | 1063 | &xfr)); |
1064 | | | 1064 | |
1065 | xfr->mnemonic = mnemonic; | | 1065 | xfr->mnemonic = mnemonic; |
1066 | stream = NULL; | | 1066 | stream = NULL; |
1067 | quota = NULL; | | 1067 | quota = NULL; |
1068 | | | 1068 | |
1069 | CHECK(xfr->stream->methods->first(xfr->stream)); | | 1069 | CHECK(xfr->stream->methods->first(xfr->stream)); |
1070 | | | 1070 | |
1071 | if (xfr->tsigkey != NULL) | | 1071 | if (xfr->tsigkey != NULL) |
1072 | dns_name_format(&xfr->tsigkey->name, keyname, sizeof(keyname)); | | 1072 | dns_name_format(&xfr->tsigkey->name, keyname, sizeof(keyname)); |
1073 | else | | 1073 | else |
1074 | keyname[0] = '\0'; | | 1074 | keyname[0] = '\0'; |
1075 | if (is_poll) | | 1075 | if (is_poll) |
1076 | xfrout_log1(client, question_name, question_class, | | 1076 | xfrout_log1(client, question_name, question_class, |
1077 | ISC_LOG_DEBUG(1), "IXFR poll up to date%s%s", | | 1077 | ISC_LOG_DEBUG(1), "IXFR poll up to date%s%s", |
1078 | (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); | | 1078 | (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); |
1079 | else if (is_ixfr) | | 1079 | else if (is_ixfr) |
1080 | xfrout_log1(client, question_name, question_class, | | 1080 | xfrout_log1(client, question_name, question_class, |
1081 | ISC_LOG_INFO, "%s started%s%s (serial %u -> %u)", | | 1081 | ISC_LOG_INFO, "%s started%s%s (serial %u -> %u)", |
1082 | mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "", | | 1082 | mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "", |
1083 | keyname, begin_serial, current_serial); | | 1083 | keyname, begin_serial, current_serial); |
1084 | else | | 1084 | else |
1085 | xfrout_log1(client, question_name, question_class, | | 1085 | xfrout_log1(client, question_name, question_class, |
1086 | ISC_LOG_INFO, "%s started%s%s (serial %u)", | | 1086 | ISC_LOG_INFO, "%s started%s%s (serial %u)", |
1087 | mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "", | | 1087 | mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "", |
1088 | keyname, current_serial); | | 1088 | keyname, current_serial); |
1089 | | | 1089 | |
1090 | | | 1090 | |
1091 | if (zone != NULL) { | | 1091 | if (zone != NULL) { |
1092 | dns_zone_getraw(zone, &raw); | | 1092 | dns_zone_getraw(zone, &raw); |
1093 | mayberaw = (raw != NULL) ? raw : zone; | | 1093 | mayberaw = (raw != NULL) ? raw : zone; |
1094 | if ((client->attributes & NS_CLIENTATTR_WANTEXPIRE) != 0 && | | 1094 | if ((client->attributes & NS_CLIENTATTR_WANTEXPIRE) != 0 && |
1095 | dns_zone_gettype(mayberaw) == dns_zone_slave) { | | 1095 | dns_zone_gettype(mayberaw) == dns_zone_slave) { |
1096 | isc_time_t expiretime; | | 1096 | isc_time_t expiretime; |
1097 | isc_uint32_t secs; | | 1097 | isc_uint32_t secs; |
1098 | dns_zone_getexpiretime(zone, &expiretime); | | 1098 | dns_zone_getexpiretime(zone, &expiretime); |
1099 | secs = isc_time_seconds(&expiretime); | | 1099 | secs = isc_time_seconds(&expiretime); |
1100 | if (secs >= client->now && result == ISC_R_SUCCESS) { | | 1100 | if (secs >= client->now && result == ISC_R_SUCCESS) { |
1101 | client->attributes |= NS_CLIENTATTR_HAVEEXPIRE; | | 1101 | client->attributes |= NS_CLIENTATTR_HAVEEXPIRE; |
1102 | client->expire = secs - client->now; | | 1102 | client->expire = secs - client->now; |
1103 | } | | 1103 | } |
1104 | } | | 1104 | } |
1105 | if (raw != NULL) | | 1105 | if (raw != NULL) |
1106 | dns_zone_detach(&raw); | | 1106 | dns_zone_detach(&raw); |
1107 | } | | 1107 | } |
1108 | | | 1108 | |
1109 | /* | | 1109 | /* |
1110 | * Hand the context over to sendstream(). Set xfr to NULL; | | 1110 | * Hand the context over to sendstream(). Set xfr to NULL; |
1111 | * sendstream() is responsible for either passing the | | 1111 | * sendstream() is responsible for either passing the |
1112 | * context on to a later event handler or destroying it. | | 1112 | * context on to a later event handler or destroying it. |
1113 | */ | | 1113 | */ |
1114 | sendstream(xfr); | | 1114 | sendstream(xfr); |
1115 | xfr = NULL; | | 1115 | xfr = NULL; |
1116 | | | 1116 | |
1117 | result = ISC_R_SUCCESS; | | 1117 | result = ISC_R_SUCCESS; |
1118 | | | 1118 | |
1119 | failure: | | 1119 | failure: |
1120 | if (result == DNS_R_REFUSED) | | 1120 | if (result == DNS_R_REFUSED) |
1121 | inc_stats(zone, dns_nsstatscounter_xfrrej); | | 1121 | inc_stats(zone, dns_nsstatscounter_xfrrej); |
1122 | if (quota != NULL) | | 1122 | if (quota != NULL) |
1123 | isc_quota_detach("a); | | 1123 | isc_quota_detach("a); |
1124 | if (current_soa_tuple != NULL) | | 1124 | if (current_soa_tuple != NULL) |
1125 | dns_difftuple_free(¤t_soa_tuple); | | 1125 | dns_difftuple_free(¤t_soa_tuple); |
1126 | if (stream != NULL) | | 1126 | if (stream != NULL) |
1127 | stream->methods->destroy(&stream); | | 1127 | stream->methods->destroy(&stream); |
1128 | if (soa_stream != NULL) | | 1128 | if (soa_stream != NULL) |
1129 | soa_stream->methods->destroy(&soa_stream); | | 1129 | soa_stream->methods->destroy(&soa_stream); |
1130 | if (data_stream != NULL) | | 1130 | if (data_stream != NULL) |
1131 | data_stream->methods->destroy(&data_stream); | | 1131 | data_stream->methods->destroy(&data_stream); |
1132 | if (ver != NULL) | | 1132 | if (ver != NULL) |
1133 | dns_db_closeversion(db, &ver, ISC_FALSE); | | 1133 | dns_db_closeversion(db, &ver, ISC_FALSE); |
1134 | if (db != NULL) | | 1134 | if (db != NULL) |
1135 | dns_db_detach(&db); | | 1135 | dns_db_detach(&db); |
1136 | if (zone != NULL) | | 1136 | if (zone != NULL) |
1137 | dns_zone_detach(&zone); | | 1137 | dns_zone_detach(&zone); |
1138 | /* XXX kludge */ | | 1138 | /* XXX kludge */ |
1139 | if (xfr != NULL) { | | 1139 | if (xfr != NULL) { |
1140 | xfrout_fail(xfr, result, "setting up zone transfer"); | | 1140 | xfrout_fail(xfr, result, "setting up zone transfer"); |
1141 | } else if (result != ISC_R_SUCCESS) { | | 1141 | } else if (result != ISC_R_SUCCESS) { |
1142 | ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, | | 1142 | ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, |
1143 | NS_LOGMODULE_XFER_OUT, | | 1143 | NS_LOGMODULE_XFER_OUT, |
1144 | ISC_LOG_DEBUG(3), "zone transfer setup failed"); | | 1144 | ISC_LOG_DEBUG(3), "zone transfer setup failed"); |
1145 | ns_client_error(client, result); | | 1145 | ns_client_error(client, result); |
1146 | } | | 1146 | } |
1147 | } | | 1147 | } |
1148 | | | 1148 | |
1149 | static isc_result_t | | 1149 | static isc_result_t |
1150 | xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, | | 1150 | xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, |
1151 | dns_name_t *qname, dns_rdatatype_t qtype, | | 1151 | dns_name_t *qname, dns_rdatatype_t qtype, |
1152 | dns_rdataclass_t qclass, dns_zone_t *zone, | | 1152 | dns_rdataclass_t qclass, dns_zone_t *zone, |
1153 | dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, | | 1153 | dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, |
1154 | rrstream_t *stream, dns_tsigkey_t *tsigkey, | | 1154 | rrstream_t *stream, dns_tsigkey_t *tsigkey, |
1155 | isc_buffer_t *lasttsig, unsigned int maxtime, | | 1155 | isc_buffer_t *lasttsig, unsigned int maxtime, |
1156 | unsigned int idletime, isc_boolean_t many_answers, | | 1156 | unsigned int idletime, isc_boolean_t many_answers, |
1157 | xfrout_ctx_t **xfrp) | | 1157 | xfrout_ctx_t **xfrp) |
1158 | { | | 1158 | { |
1159 | xfrout_ctx_t *xfr; | | 1159 | xfrout_ctx_t *xfr; |
1160 | isc_result_t result; | | 1160 | isc_result_t result; |
1161 | unsigned int len; | | 1161 | unsigned int len; |
1162 | void *mem; | | 1162 | void *mem; |
1163 | | | 1163 | |
1164 | INSIST(xfrp != NULL && *xfrp == NULL); | | 1164 | INSIST(xfrp != NULL && *xfrp == NULL); |
1165 | xfr = isc_mem_get(mctx, sizeof(*xfr)); | | 1165 | xfr = isc_mem_get(mctx, sizeof(*xfr)); |
1166 | if (xfr == NULL) | | 1166 | if (xfr == NULL) |
1167 | return (ISC_R_NOMEMORY); | | 1167 | return (ISC_R_NOMEMORY); |
1168 | xfr->mctx = NULL; | | 1168 | xfr->mctx = NULL; |
1169 | isc_mem_attach(mctx, &xfr->mctx); | | 1169 | isc_mem_attach(mctx, &xfr->mctx); |
1170 | xfr->client = NULL; | | 1170 | xfr->client = NULL; |
1171 | ns_client_attach(client, &xfr->client); | | 1171 | ns_client_attach(client, &xfr->client); |
1172 | xfr->id = id; | | 1172 | xfr->id = id; |
1173 | xfr->qname = qname; | | 1173 | xfr->qname = qname; |
1174 | xfr->qtype = qtype; | | 1174 | xfr->qtype = qtype; |
1175 | xfr->qclass = qclass; | | 1175 | xfr->qclass = qclass; |
1176 | xfr->zone = NULL; | | 1176 | xfr->zone = NULL; |
1177 | xfr->db = NULL; | | 1177 | xfr->db = NULL; |
1178 | xfr->ver = NULL; | | 1178 | xfr->ver = NULL; |
1179 | if (zone != NULL) /* zone will be NULL if it's DLZ */ | | 1179 | if (zone != NULL) /* zone will be NULL if it's DLZ */ |
1180 | dns_zone_attach(zone, &xfr->zone); | | 1180 | dns_zone_attach(zone, &xfr->zone); |
1181 | dns_db_attach(db, &xfr->db); | | 1181 | dns_db_attach(db, &xfr->db); |
1182 | dns_db_attachversion(db, ver, &xfr->ver); | | 1182 | dns_db_attachversion(db, ver, &xfr->ver); |
1183 | xfr->end_of_stream = ISC_FALSE; | | 1183 | xfr->end_of_stream = ISC_FALSE; |
1184 | xfr->tsigkey = tsigkey; | | 1184 | xfr->tsigkey = tsigkey; |
1185 | xfr->lasttsig = lasttsig; | | 1185 | xfr->lasttsig = lasttsig; |
1186 | xfr->txmem = NULL; | | 1186 | xfr->txmem = NULL; |
1187 | xfr->txmemlen = 0; | | 1187 | xfr->txmemlen = 0; |
1188 | xfr->nmsg = 0; | | 1188 | xfr->nmsg = 0; |
1189 | xfr->many_answers = many_answers, | | 1189 | xfr->many_answers = many_answers; |
1190 | xfr->sends = 0; | | 1190 | xfr->sends = 0; |
1191 | xfr->shuttingdown = ISC_FALSE; | | 1191 | xfr->shuttingdown = ISC_FALSE; |
1192 | xfr->mnemonic = NULL; | | 1192 | xfr->mnemonic = NULL; |
1193 | xfr->buf.base = NULL; | | 1193 | xfr->buf.base = NULL; |
1194 | xfr->buf.length = 0; | | 1194 | xfr->buf.length = 0; |
1195 | xfr->txmem = NULL; | | 1195 | xfr->txmem = NULL; |
1196 | xfr->txmemlen = 0; | | 1196 | xfr->txmemlen = 0; |
1197 | xfr->stream = NULL; | | 1197 | xfr->stream = NULL; |
1198 | xfr->quota = NULL; | | 1198 | xfr->quota = NULL; |
1199 | | | 1199 | |
1200 | /* | | 1200 | /* |
1201 | * Allocate a temporary buffer for the uncompressed response | | 1201 | * Allocate a temporary buffer for the uncompressed response |
1202 | * message data. The size should be no more than 65535 bytes | | 1202 | * message data. The size should be no more than 65535 bytes |
1203 | * so that the compressed data will fit in a TCP message, | | 1203 | * so that the compressed data will fit in a TCP message, |
1204 | * and no less than 65535 bytes so that an almost maximum-sized | | 1204 | * and no less than 65535 bytes so that an almost maximum-sized |
1205 | * RR will fit. Note that although 65535-byte RRs are allowed | | 1205 | * RR will fit. Note that although 65535-byte RRs are allowed |
1206 | * in principle, they cannot be zone-transferred (at least not | | 1206 | * in principle, they cannot be zone-transferred (at least not |
1207 | * if uncompressible), because the message and RR headers would | | 1207 | * if uncompressible), because the message and RR headers would |
1208 | * push the size of the TCP message over the 65536 byte limit. | | 1208 | * push the size of the TCP message over the 65536 byte limit. |
1209 | */ | | 1209 | */ |
1210 | len = 65535; | | 1210 | len = 65535; |
1211 | mem = isc_mem_get(mctx, len); | | 1211 | mem = isc_mem_get(mctx, len); |
1212 | if (mem == NULL) { | | 1212 | if (mem == NULL) { |
1213 | result = ISC_R_NOMEMORY; | | 1213 | result = ISC_R_NOMEMORY; |
1214 | goto failure; | | 1214 | goto failure; |
1215 | } | | 1215 | } |
1216 | isc_buffer_init(&xfr->buf, mem, len); | | 1216 | isc_buffer_init(&xfr->buf, mem, len); |
1217 | | | 1217 | |
1218 | /* | | 1218 | /* |
1219 | * Allocate another temporary buffer for the compressed | | 1219 | * Allocate another temporary buffer for the compressed |
1220 | * response message and its TCP length prefix. | | 1220 | * response message and its TCP length prefix. |
1221 | */ | | 1221 | */ |
1222 | len = 2 + 65535; | | 1222 | len = 2 + 65535; |
1223 | mem = isc_mem_get(mctx, len); | | 1223 | mem = isc_mem_get(mctx, len); |
1224 | if (mem == NULL) { | | 1224 | if (mem == NULL) { |
1225 | result = ISC_R_NOMEMORY; | | 1225 | result = ISC_R_NOMEMORY; |
1226 | goto failure; | | 1226 | goto failure; |
1227 | } | | 1227 | } |
1228 | isc_buffer_init(&xfr->txlenbuf, mem, 2); | | 1228 | isc_buffer_init(&xfr->txlenbuf, mem, 2); |
1229 | isc_buffer_init(&xfr->txbuf, (char *) mem + 2, len - 2); | | 1229 | isc_buffer_init(&xfr->txbuf, (char *) mem + 2, len - 2); |
1230 | xfr->txmem = mem; | | 1230 | xfr->txmem = mem; |
1231 | xfr->txmemlen = len; | | 1231 | xfr->txmemlen = len; |
1232 | | | 1232 | |
1233 | CHECK(dns_timer_setidle(xfr->client->timer, | | 1233 | CHECK(dns_timer_setidle(xfr->client->timer, |
1234 | maxtime, idletime, ISC_FALSE)); | | 1234 | maxtime, idletime, ISC_FALSE)); |
1235 | | | 1235 | |
1236 | /* | | 1236 | /* |
1237 | * Register a shutdown callback with the client, so that we | | 1237 | * Register a shutdown callback with the client, so that we |
1238 | * can stop the transfer immediately when the client task | | 1238 | * can stop the transfer immediately when the client task |
1239 | * gets a shutdown event. | | 1239 | * gets a shutdown event. |
1240 | */ | | 1240 | */ |
1241 | xfr->client->shutdown = xfrout_client_shutdown; | | 1241 | xfr->client->shutdown = xfrout_client_shutdown; |
1242 | xfr->client->shutdown_arg = xfr; | | 1242 | xfr->client->shutdown_arg = xfr; |
1243 | /* | | 1243 | /* |
1244 | * These MUST be after the last "goto failure;" / CHECK to | | 1244 | * These MUST be after the last "goto failure;" / CHECK to |
1245 | * prevent a double free by the caller. | | 1245 | * prevent a double free by the caller. |
1246 | */ | | 1246 | */ |
1247 | xfr->quota = quota; | | 1247 | xfr->quota = quota; |
1248 | xfr->stream = stream; | | 1248 | xfr->stream = stream; |
1249 | | | 1249 | |
1250 | *xfrp = xfr; | | 1250 | *xfrp = xfr; |
1251 | return (ISC_R_SUCCESS); | | 1251 | return (ISC_R_SUCCESS); |
1252 | | | 1252 | |
1253 | failure: | | 1253 | failure: |
1254 | xfrout_ctx_destroy(&xfr); | | 1254 | xfrout_ctx_destroy(&xfr); |
1255 | return (result); | | 1255 | return (result); |
1256 | } | | 1256 | } |
1257 | | | 1257 | |
1258 | | | 1258 | |
1259 | /* | | 1259 | /* |
1260 | * Arrange to send as much as we can of "stream" without blocking. | | 1260 | * Arrange to send as much as we can of "stream" without blocking. |
1261 | * | | 1261 | * |
1262 | * Requires: | | 1262 | * Requires: |
1263 | * The stream iterator is initialized and points at an RR, | | 1263 | * The stream iterator is initialized and points at an RR, |
1264 | * or possibly at the end of the stream (that is, the | | 1264 | * or possibly at the end of the stream (that is, the |
1265 | * _first method of the iterator has been called). | | 1265 | * _first method of the iterator has been called). |
1266 | */ | | 1266 | */ |
1267 | static void | | 1267 | static void |
1268 | sendstream(xfrout_ctx_t *xfr) { | | 1268 | sendstream(xfrout_ctx_t *xfr) { |
1269 | dns_message_t *tcpmsg = NULL; | | 1269 | dns_message_t *tcpmsg = NULL; |
1270 | dns_message_t *msg = NULL; /* Client message if UDP, tcpmsg if TCP */ | | 1270 | dns_message_t *msg = NULL; /* Client message if UDP, tcpmsg if TCP */ |
1271 | isc_result_t result; | | 1271 | isc_result_t result; |
1272 | isc_region_t used; | | 1272 | isc_region_t used; |
1273 | isc_region_t region; | | 1273 | isc_region_t region; |
1274 | dns_rdataset_t *qrdataset; | | 1274 | dns_rdataset_t *qrdataset; |
1275 | dns_name_t *msgname = NULL; | | 1275 | dns_name_t *msgname = NULL; |
1276 | dns_rdata_t *msgrdata = NULL; | | 1276 | dns_rdata_t *msgrdata = NULL; |
1277 | dns_rdatalist_t *msgrdl = NULL; | | 1277 | dns_rdatalist_t *msgrdl = NULL; |
1278 | dns_rdataset_t *msgrds = NULL; | | 1278 | dns_rdataset_t *msgrds = NULL; |
1279 | dns_compress_t cctx; | | 1279 | dns_compress_t cctx; |
1280 | isc_boolean_t cleanup_cctx = ISC_FALSE; | | 1280 | isc_boolean_t cleanup_cctx = ISC_FALSE; |
1281 | isc_boolean_t is_tcp; | | 1281 | isc_boolean_t is_tcp; |
1282 | | | 1282 | |
1283 | int n_rrs; | | 1283 | int n_rrs; |
1284 | | | 1284 | |
1285 | isc_buffer_clear(&xfr->buf); | | 1285 | isc_buffer_clear(&xfr->buf); |
1286 | isc_buffer_clear(&xfr->txlenbuf); | | 1286 | isc_buffer_clear(&xfr->txlenbuf); |
1287 | isc_buffer_clear(&xfr->txbuf); | | 1287 | isc_buffer_clear(&xfr->txbuf); |
1288 | | | 1288 | |
1289 | is_tcp = ISC_TF((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0); | | 1289 | is_tcp = ISC_TF((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0); |
1290 | if (!is_tcp) { | | 1290 | if (!is_tcp) { |
1291 | /* | | 1291 | /* |
1292 | * In the UDP case, we put the response data directly into | | 1292 | * In the UDP case, we put the response data directly into |
1293 | * the client message. | | 1293 | * the client message. |
1294 | */ | | 1294 | */ |
1295 | msg = xfr->client->message; | | 1295 | msg = xfr->client->message; |
1296 | CHECK(dns_message_reply(msg, ISC_TRUE)); | | 1296 | CHECK(dns_message_reply(msg, ISC_TRUE)); |
1297 | } else { | | 1297 | } else { |
1298 | /* | | 1298 | /* |
1299 | * TCP. Build a response dns_message_t, temporarily storing | | 1299 | * TCP. Build a response dns_message_t, temporarily storing |
1300 | * the raw, uncompressed owner names and RR data contiguously | | 1300 | * the raw, uncompressed owner names and RR data contiguously |
1301 | * in xfr->buf. We know that if the uncompressed data fits | | 1301 | * in xfr->buf. We know that if the uncompressed data fits |
1302 | * in xfr->buf, the compressed data will surely fit in a TCP | | 1302 | * in xfr->buf, the compressed data will surely fit in a TCP |
1303 | * message. | | 1303 | * message. |
1304 | */ | | 1304 | */ |
1305 | | | 1305 | |
1306 | CHECK(dns_message_create(xfr->mctx, | | 1306 | CHECK(dns_message_create(xfr->mctx, |
1307 | DNS_MESSAGE_INTENTRENDER, &tcpmsg)); | | 1307 | DNS_MESSAGE_INTENTRENDER, &tcpmsg)); |
1308 | msg = tcpmsg; | | 1308 | msg = tcpmsg; |
1309 | | | 1309 | |
1310 | msg->id = xfr->id; | | 1310 | msg->id = xfr->id; |
1311 | msg->rcode = dns_rcode_noerror; | | 1311 | msg->rcode = dns_rcode_noerror; |
1312 | msg->flags = DNS_MESSAGEFLAG_QR | DNS_MESSAGEFLAG_AA; | | 1312 | msg->flags = DNS_MESSAGEFLAG_QR | DNS_MESSAGEFLAG_AA; |
1313 | if ((xfr->client->attributes & NS_CLIENTATTR_RA) != 0) | | 1313 | if ((xfr->client->attributes & NS_CLIENTATTR_RA) != 0) |
1314 | msg->flags |= DNS_MESSAGEFLAG_RA; | | 1314 | msg->flags |= DNS_MESSAGEFLAG_RA; |
1315 | CHECK(dns_message_settsigkey(msg, xfr->tsigkey)); | | 1315 | CHECK(dns_message_settsigkey(msg, xfr->tsigkey)); |
1316 | CHECK(dns_message_setquerytsig(msg, xfr->lasttsig)); | | 1316 | CHECK(dns_message_setquerytsig(msg, xfr->lasttsig)); |
1317 | if (xfr->lasttsig != NULL) | | 1317 | if (xfr->lasttsig != NULL) |
1318 | isc_buffer_free(&xfr->lasttsig); | | 1318 | isc_buffer_free(&xfr->lasttsig); |
1319 | | | 1319 | |
1320 | /* | | 1320 | /* |
1321 | * Add a EDNS option to the message? | | 1321 | * Add a EDNS option to the message? |
1322 | */ | | 1322 | */ |
1323 | if ((xfr->client->attributes & NS_CLIENTATTR_WANTOPT) != 0) { | | 1323 | if ((xfr->client->attributes & NS_CLIENTATTR_WANTOPT) != 0) { |
1324 | dns_rdataset_t *opt = NULL; | | 1324 | dns_rdataset_t *opt = NULL; |
1325 | | | 1325 | |
1326 | CHECK(ns_client_addopt(xfr->client, msg, &opt)); | | 1326 | CHECK(ns_client_addopt(xfr->client, msg, &opt)); |
1327 | CHECK(dns_message_setopt(msg, opt)); | | 1327 | CHECK(dns_message_setopt(msg, opt)); |
1328 | /* | | 1328 | /* |
1329 | * Add to first message only. | | 1329 | * Add to first message only. |
1330 | */ | | 1330 | */ |
1331 | xfr->client->attributes &= ~NS_CLIENTATTR_WANTNSID; | | 1331 | xfr->client->attributes &= ~NS_CLIENTATTR_WANTNSID; |
1332 | xfr->client->attributes &= ~NS_CLIENTATTR_HAVEEXPIRE; | | 1332 | xfr->client->attributes &= ~NS_CLIENTATTR_HAVEEXPIRE; |
1333 | } | | 1333 | } |
1334 | | | 1334 | |
1335 | /* | | 1335 | /* |
1336 | * Account for reserved space. | | 1336 | * Account for reserved space. |
1337 | */ | | 1337 | */ |
1338 | if (xfr->tsigkey != NULL) | | 1338 | if (xfr->tsigkey != NULL) |
1339 | INSIST(msg->reserved != 0U); | | 1339 | INSIST(msg->reserved != 0U); |
1340 | isc_buffer_add(&xfr->buf, msg->reserved); | | 1340 | isc_buffer_add(&xfr->buf, msg->reserved); |
1341 | | | 1341 | |
1342 | /* | | 1342 | /* |
1343 | * Include a question section in the first message only. | | 1343 | * Include a question section in the first message only. |
1344 | * BIND 8.2.1 will not recognize an IXFR if it does not | | 1344 | * BIND 8.2.1 will not recognize an IXFR if it does not |
1345 | * have a question section. | | 1345 | * have a question section. |
1346 | */ | | 1346 | */ |
1347 | if (xfr->nmsg == 0) { | | 1347 | if (xfr->nmsg == 0) { |
1348 | dns_name_t *qname = NULL; | | 1348 | dns_name_t *qname = NULL; |
1349 | isc_region_t r; | | 1349 | isc_region_t r; |
1350 | | | 1350 | |
1351 | /* | | 1351 | /* |
1352 | * Reserve space for the 12-byte message header | | 1352 | * Reserve space for the 12-byte message header |
1353 | * and 4 bytes of question. | | 1353 | * and 4 bytes of question. |
1354 | */ | | 1354 | */ |
1355 | isc_buffer_add(&xfr->buf, 12 + 4); | | 1355 | isc_buffer_add(&xfr->buf, 12 + 4); |
1356 | | | 1356 | |
1357 | qrdataset = NULL; | | 1357 | qrdataset = NULL; |
1358 | result = dns_message_gettemprdataset(msg, &qrdataset); | | 1358 | result = dns_message_gettemprdataset(msg, &qrdataset); |
1359 | if (result != ISC_R_SUCCESS) | | 1359 | if (result != ISC_R_SUCCESS) |
1360 | goto failure; | | 1360 | goto failure; |
1361 | dns_rdataset_makequestion(qrdataset, | | 1361 | dns_rdataset_makequestion(qrdataset, |
1362 | xfr->client->message->rdclass, | | 1362 | xfr->client->message->rdclass, |
1363 | xfr->qtype); | | 1363 | xfr->qtype); |
1364 | | | 1364 | |
1365 | result = dns_message_gettempname(msg, &qname); | | 1365 | result = dns_message_gettempname(msg, &qname); |
1366 | if (result != ISC_R_SUCCESS) | | 1366 | if (result != ISC_R_SUCCESS) |
1367 | goto failure; | | 1367 | goto failure; |
1368 | dns_name_init(qname, NULL); | | 1368 | dns_name_init(qname, NULL); |
1369 | isc_buffer_availableregion(&xfr->buf, &r); | | 1369 | isc_buffer_availableregion(&xfr->buf, &r); |
1370 | INSIST(r.length >= xfr->qname->length); | | 1370 | INSIST(r.length >= xfr->qname->length); |
1371 | r.length = xfr->qname->length; | | 1371 | r.length = xfr->qname->length; |
1372 | isc_buffer_putmem(&xfr->buf, xfr->qname->ndata, | | 1372 | isc_buffer_putmem(&xfr->buf, xfr->qname->ndata, |
1373 | xfr->qname->length); | | 1373 | xfr->qname->length); |
1374 | dns_name_fromregion(qname, &r); | | 1374 | dns_name_fromregion(qname, &r); |
1375 | ISC_LIST_INIT(qname->list); | | 1375 | ISC_LIST_INIT(qname->list); |
1376 | ISC_LIST_APPEND(qname->list, qrdataset, link); | | 1376 | ISC_LIST_APPEND(qname->list, qrdataset, link); |
1377 | | | 1377 | |
1378 | dns_message_addname(msg, qname, DNS_SECTION_QUESTION); | | 1378 | dns_message_addname(msg, qname, DNS_SECTION_QUESTION); |
1379 | } else { | | 1379 | } else { |
1380 | /* | | 1380 | /* |
1381 | * Reserve space for the 12-byte message header | | 1381 | * Reserve space for the 12-byte message header |
1382 | */ | | 1382 | */ |
1383 | isc_buffer_add(&xfr->buf, 12); | | 1383 | isc_buffer_add(&xfr->buf, 12); |
1384 | msg->tcp_continuation = 1; | | 1384 | msg->tcp_continuation = 1; |
1385 | } | | 1385 | } |
1386 | } | | 1386 | } |
1387 | | | 1387 | |
1388 | /* | | 1388 | /* |
1389 | * Try to fit in as many RRs as possible, unless "one-answer" | | 1389 | * Try to fit in as many RRs as possible, unless "one-answer" |
1390 | * format has been requested. | | 1390 | * format has been requested. |
1391 | */ | | 1391 | */ |
1392 | for (n_rrs = 0; ; n_rrs++) { | | 1392 | for (n_rrs = 0; ; n_rrs++) { |
1393 | dns_name_t *name = NULL; | | 1393 | dns_name_t *name = NULL; |
1394 | isc_uint32_t ttl; | | 1394 | isc_uint32_t ttl; |
1395 | dns_rdata_t *rdata = NULL; | | 1395 | dns_rdata_t *rdata = NULL; |
1396 | | | 1396 | |
1397 | unsigned int size; | | 1397 | unsigned int size; |
1398 | isc_region_t r; | | 1398 | isc_region_t r; |
1399 | | | 1399 | |
1400 | msgname = NULL; | | 1400 | msgname = NULL; |
1401 | msgrdata = NULL; | | 1401 | msgrdata = NULL; |
1402 | msgrdl = NULL; | | 1402 | msgrdl = NULL; |
1403 | msgrds = NULL; | | 1403 | msgrds = NULL; |
1404 | | | 1404 | |
1405 | xfr->stream->methods->current(xfr->stream, | | 1405 | xfr->stream->methods->current(xfr->stream, |
1406 | &name, &ttl, &rdata); | | 1406 | &name, &ttl, &rdata); |
1407 | size = name->length + 10 + rdata->length; | | 1407 | size = name->length + 10 + rdata->length; |
1408 | isc_buffer_availableregion(&xfr->buf, &r); | | 1408 | isc_buffer_availableregion(&xfr->buf, &r); |
1409 | if (size >= r.length) { | | 1409 | if (size >= r.length) { |
1410 | /* | | 1410 | /* |
1411 | * RR would not fit. If there are other RRs in the | | 1411 | * RR would not fit. If there are other RRs in the |
1412 | * buffer, send them now and leave this RR to the | | 1412 | * buffer, send them now and leave this RR to the |
1413 | * next message. If this RR overflows the buffer | | 1413 | * next message. If this RR overflows the buffer |
1414 | * all by itself, fail. | | 1414 | * all by itself, fail. |
1415 | * | | 1415 | * |
1416 | * In theory some RRs might fit in a TCP message | | 1416 | * In theory some RRs might fit in a TCP message |
1417 | * when compressed even if they do not fit when | | 1417 | * when compressed even if they do not fit when |
1418 | * uncompressed, but surely we don't want | | 1418 | * uncompressed, but surely we don't want |
1419 | * to send such monstrosities to an unsuspecting | | 1419 | * to send such monstrosities to an unsuspecting |
1420 | * slave. | | 1420 | * slave. |
1421 | */ | | 1421 | */ |
1422 | if (n_rrs == 0) { | | 1422 | if (n_rrs == 0) { |
1423 | xfrout_log(xfr, ISC_LOG_WARNING, | | 1423 | xfrout_log(xfr, ISC_LOG_WARNING, |
1424 | "RR too large for zone transfer " | | 1424 | "RR too large for zone transfer " |
1425 | "(%d bytes)", size); | | 1425 | "(%d bytes)", size); |
1426 | /* XXX DNS_R_RRTOOLARGE? */ | | 1426 | /* XXX DNS_R_RRTOOLARGE? */ |
1427 | result = ISC_R_NOSPACE; | | 1427 | result = ISC_R_NOSPACE; |
1428 | goto failure; | | 1428 | goto failure; |
1429 | } | | 1429 | } |
1430 | break; | | 1430 | break; |
1431 | } | | 1431 | } |
1432 | | | 1432 | |
1433 | if (isc_log_wouldlog(ns_g_lctx, XFROUT_RR_LOGLEVEL)) | | 1433 | if (isc_log_wouldlog(ns_g_lctx, XFROUT_RR_LOGLEVEL)) |
1434 | log_rr(name, rdata, ttl); /* XXX */ | | 1434 | log_rr(name, rdata, ttl); /* XXX */ |
1435 | | | 1435 | |
1436 | result = dns_message_gettempname(msg, &msgname); | | 1436 | result = dns_message_gettempname(msg, &msgname); |
1437 | if (result != ISC_R_SUCCESS) | | 1437 | if (result != ISC_R_SUCCESS) |
1438 | goto failure; | | 1438 | goto failure; |
1439 | dns_name_init(msgname, NULL); | | 1439 | dns_name_init(msgname, NULL); |
1440 | isc_buffer_availableregion(&xfr->buf, &r); | | 1440 | isc_buffer_availableregion(&xfr->buf, &r); |
1441 | INSIST(r.length >= name->length); | | 1441 | INSIST(r.length >= name->length); |
1442 | r.length = name->length; | | 1442 | r.length = name->length; |
1443 | isc_buffer_putmem(&xfr->buf, name->ndata, name->length); | | 1443 | isc_buffer_putmem(&xfr->buf, name->ndata, name->length); |
1444 | dns_name_fromregion(msgname, &r); | | 1444 | dns_name_fromregion(msgname, &r); |
1445 | | | 1445 | |
1446 | /* Reserve space for RR header. */ | | 1446 | /* Reserve space for RR header. */ |
1447 | isc_buffer_add(&xfr->buf, 10); | | 1447 | isc_buffer_add(&xfr->buf, 10); |
1448 | | | 1448 | |
1449 | result = dns_message_gettemprdata(msg, &msgrdata); | | 1449 | result = dns_message_gettemprdata(msg, &msgrdata); |
1450 | if (result != ISC_R_SUCCESS) | | 1450 | if (result != ISC_R_SUCCESS) |
1451 | goto failure; | | 1451 | goto failure; |
1452 | isc_buffer_availableregion(&xfr->buf, &r); | | 1452 | isc_buffer_availableregion(&xfr->buf, &r); |
1453 | r.length = rdata->length; | | 1453 | r.length = rdata->length; |
1454 | isc_buffer_putmem(&xfr->buf, rdata->data, rdata->length); | | 1454 | isc_buffer_putmem(&xfr->buf, rdata->data, rdata->length); |
1455 | dns_rdata_init(msgrdata); | | 1455 | dns_rdata_init(msgrdata); |
1456 | dns_rdata_fromregion(msgrdata, | | 1456 | dns_rdata_fromregion(msgrdata, |
1457 | rdata->rdclass, rdata->type, &r); | | 1457 | rdata->rdclass, rdata->type, &r); |
1458 | | | 1458 | |
1459 | result = dns_message_gettemprdatalist(msg, &msgrdl); | | 1459 | result = dns_message_gettemprdatalist(msg, &msgrdl); |
1460 | if (result != ISC_R_SUCCESS) | | 1460 | if (result != ISC_R_SUCCESS) |
1461 | goto failure; | | 1461 | goto failure; |
1462 | msgrdl->type = rdata->type; | | 1462 | msgrdl->type = rdata->type; |
1463 | msgrdl->rdclass = rdata->rdclass; | | 1463 | msgrdl->rdclass = rdata->rdclass; |
1464 | msgrdl->ttl = ttl; | | 1464 | msgrdl->ttl = ttl; |
1465 | if (rdata->type == dns_rdatatype_sig || | | 1465 | if (rdata->type == dns_rdatatype_sig || |
1466 | rdata->type == dns_rdatatype_rrsig) | | 1466 | rdata->type == dns_rdatatype_rrsig) |
1467 | msgrdl->covers = dns_rdata_covers(rdata); | | 1467 | msgrdl->covers = dns_rdata_covers(rdata); |
1468 | else | | 1468 | else |
1469 | msgrdl->covers = dns_rdatatype_none; | | 1469 | msgrdl->covers = dns_rdatatype_none; |
1470 | ISC_LIST_APPEND(msgrdl->rdata, msgrdata, link); | | 1470 | ISC_LIST_APPEND(msgrdl->rdata, msgrdata, link); |
1471 | | | 1471 | |
1472 | result = dns_message_gettemprdataset(msg, &msgrds); | | 1472 | result = dns_message_gettemprdataset(msg, &msgrds); |
1473 | if (result != ISC_R_SUCCESS) | | 1473 | if (result != ISC_R_SUCCESS) |
1474 | goto failure; | | 1474 | goto failure; |
1475 | result = dns_rdatalist_tordataset(msgrdl, msgrds); | | 1475 | result = dns_rdatalist_tordataset(msgrdl, msgrds); |
1476 | INSIST(result == ISC_R_SUCCESS); | | 1476 | INSIST(result == ISC_R_SUCCESS); |
1477 | | | 1477 | |
1478 | ISC_LIST_APPEND(msgname->list, msgrds, link); | | 1478 | ISC_LIST_APPEND(msgname->list, msgrds, link); |
1479 | | | 1479 | |
1480 | dns_message_addname(msg, msgname, DNS_SECTION_ANSWER); | | 1480 | dns_message_addname(msg, msgname, DNS_SECTION_ANSWER); |
1481 | msgname = NULL; | | 1481 | msgname = NULL; |
1482 | | | 1482 | |
1483 | result = xfr->stream->methods->next(xfr->stream); | | 1483 | result = xfr->stream->methods->next(xfr->stream); |
1484 | if (result == ISC_R_NOMORE) { | | 1484 | if (result == ISC_R_NOMORE) { |
1485 | xfr->end_of_stream = ISC_TRUE; | | 1485 | xfr->end_of_stream = ISC_TRUE; |
1486 | break; | | 1486 | break; |
1487 | } | | 1487 | } |
1488 | CHECK(result); | | 1488 | CHECK(result); |
1489 | | | 1489 | |
1490 | if (! xfr->many_answers) | | 1490 | if (! xfr->many_answers) |
1491 | break; | | 1491 | break; |
1492 | /* | | 1492 | /* |
1493 | * At this stage, at least 1 RR has been rendered into | | 1493 | * At this stage, at least 1 RR has been rendered into |
1494 | * the message. Check if we want to clamp this message | | 1494 | * the message. Check if we want to clamp this message |
1495 | * here (TCP only). 20480 was set as an upper limit to | | 1495 | * here (TCP only). 20480 was set as an upper limit to |
1496 | * improve message compression. | | 1496 | * improve message compression. |
1497 | */ | | 1497 | */ |
1498 | if ((isc_buffer_usedlength(&xfr->buf) >= 20480) && is_tcp) | | 1498 | if ((isc_buffer_usedlength(&xfr->buf) >= 20480) && is_tcp) |
1499 | break; | | 1499 | break; |
1500 | } | | 1500 | } |
1501 | | | 1501 | |
1502 | if (is_tcp) { | | 1502 | if (is_tcp) { |
1503 | CHECK(dns_compress_init(&cctx, -1, xfr->mctx)); | | 1503 | CHECK(dns_compress_init(&cctx, -1, xfr->mctx)); |
1504 | dns_compress_setsensitive(&cctx, ISC_TRUE); | | 1504 | dns_compress_setsensitive(&cctx, ISC_TRUE); |
1505 | cleanup_cctx = ISC_TRUE; | | 1505 | cleanup_cctx = ISC_TRUE; |
1506 | CHECK(dns_message_renderbegin(msg, &cctx, &xfr->txbuf)); | | 1506 | CHECK(dns_message_renderbegin(msg, &cctx, &xfr->txbuf)); |
1507 | CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0)); | | 1507 | CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0)); |
1508 | CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0)); | | 1508 | CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0)); |
1509 | CHECK(dns_message_renderend(msg)); | | 1509 | CHECK(dns_message_renderend(msg)); |
1510 | dns_compress_invalidate(&cctx); | | 1510 | dns_compress_invalidate(&cctx); |
1511 | cleanup_cctx = ISC_FALSE; | | 1511 | cleanup_cctx = ISC_FALSE; |
1512 | | | 1512 | |
1513 | isc_buffer_usedregion(&xfr->txbuf, &used); | | 1513 | isc_buffer_usedregion(&xfr->txbuf, &used); |
1514 | isc_buffer_putuint16(&xfr->txlenbuf, | | 1514 | isc_buffer_putuint16(&xfr->txlenbuf, |
1515 | (isc_uint16_t)used.length); | | 1515 | (isc_uint16_t)used.length); |
1516 | region.base = xfr->txlenbuf.base; | | 1516 | region.base = xfr->txlenbuf.base; |
1517 | region.length = 2 + used.length; | | 1517 | region.length = 2 + used.length; |
1518 | xfrout_log(xfr, ISC_LOG_DEBUG(8), | | 1518 | xfrout_log(xfr, ISC_LOG_DEBUG(8), |
1519 | "sending TCP message of %d bytes", | | 1519 | "sending TCP message of %d bytes", |
1520 | used.length); | | 1520 | used.length); |
1521 | CHECK(isc_socket_send(xfr->client->tcpsocket, /* XXX */ | | 1521 | CHECK(isc_socket_send(xfr->client->tcpsocket, /* XXX */ |
1522 | ®ion, xfr->client->task, | | 1522 | ®ion, xfr->client->task, |
1523 | xfrout_senddone, | | 1523 | xfrout_senddone, |
1524 | xfr)); | | 1524 | xfr)); |
1525 | xfr->sends++; | | 1525 | xfr->sends++; |
1526 | } else { | | 1526 | } else { |
1527 | xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response"); | | 1527 | xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response"); |
1528 | ns_client_send(xfr->client); | | 1528 | ns_client_send(xfr->client); |
1529 | xfr->stream->methods->pause(xfr->stream); | | 1529 | xfr->stream->methods->pause(xfr->stream); |
1530 | xfrout_ctx_destroy(&xfr); | | 1530 | xfrout_ctx_destroy(&xfr); |
1531 | return; | | 1531 | return; |
1532 | } | | 1532 | } |
1533 | | | 1533 | |
1534 | /* Advance lasttsig to be the last TSIG generated */ | | 1534 | /* Advance lasttsig to be the last TSIG generated */ |
1535 | CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig)); | | 1535 | CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig)); |
1536 | | | 1536 | |
1537 | xfr->nmsg++; | | 1537 | xfr->nmsg++; |
1538 | | | 1538 | |
1539 | failure: | | 1539 | failure: |
1540 | if (msgname != NULL) { | | 1540 | if (msgname != NULL) { |
1541 | if (msgrds != NULL) { | | 1541 | if (msgrds != NULL) { |
1542 | if (dns_rdataset_isassociated(msgrds)) | | 1542 | if (dns_rdataset_isassociated(msgrds)) |
1543 | dns_rdataset_disassociate(msgrds); | | 1543 | dns_rdataset_disassociate(msgrds); |
1544 | dns_message_puttemprdataset(msg, &msgrds); | | 1544 | dns_message_puttemprdataset(msg, &msgrds); |
1545 | } | | 1545 | } |
1546 | if (msgrdl != NULL) { | | 1546 | if (msgrdl != NULL) { |
1547 | ISC_LIST_UNLINK(msgrdl->rdata, msgrdata, link); | | 1547 | ISC_LIST_UNLINK(msgrdl->rdata, msgrdata, link); |
1548 | dns_message_puttemprdatalist(msg, &msgrdl); | | 1548 | dns_message_puttemprdatalist(msg, &msgrdl); |
1549 | } | | 1549 | } |
1550 | if (msgrdata != NULL) | | 1550 | if (msgrdata != NULL) |
1551 | dns_message_puttemprdata(msg, &msgrdata); | | 1551 | dns_message_puttemprdata(msg, &msgrdata); |
1552 | dns_message_puttempname(msg, &msgname); | | 1552 | dns_message_puttempname(msg, &msgname); |
1553 | } | | 1553 | } |
1554 | | | 1554 | |
1555 | if (tcpmsg != NULL) | | 1555 | if (tcpmsg != NULL) |
1556 | dns_message_destroy(&tcpmsg); | | 1556 | dns_message_destroy(&tcpmsg); |
1557 | | | 1557 | |
1558 | if (cleanup_cctx) | | 1558 | if (cleanup_cctx) |
1559 | dns_compress_invalidate(&cctx); | | 1559 | dns_compress_invalidate(&cctx); |
1560 | /* | | 1560 | /* |
1561 | * Make sure to release any locks held by database | | 1561 | * Make sure to release any locks held by database |
1562 | * iterators before returning from the event handler. | | 1562 | * iterators before returning from the event handler. |
1563 | */ | | 1563 | */ |
1564 | xfr->stream->methods->pause(xfr->stream); | | 1564 | xfr->stream->methods->pause(xfr->stream); |
1565 | | | 1565 | |
1566 | if (result == ISC_R_SUCCESS) | | 1566 | if (result == ISC_R_SUCCESS) |
1567 | return; | | 1567 | return; |
1568 | | | 1568 | |
1569 | xfrout_fail(xfr, result, "sending zone data"); | | 1569 | xfrout_fail(xfr, result, "sending zone data"); |
1570 | } | | 1570 | } |
1571 | | | 1571 | |
1572 | static void | | 1572 | static void |
1573 | xfrout_ctx_destroy(xfrout_ctx_t **xfrp) { | | 1573 | xfrout_ctx_destroy(xfrout_ctx_t **xfrp) { |
1574 | xfrout_ctx_t *xfr = *xfrp; | | 1574 | xfrout_ctx_t *xfr = *xfrp; |
1575 | ns_client_t *client = NULL; | | 1575 | ns_client_t *client = NULL; |
1576 | | | 1576 | |
1577 | INSIST(xfr->sends == 0); | | 1577 | INSIST(xfr->sends == 0); |
1578 | | | 1578 | |
1579 | xfr->client->shutdown = NULL; | | 1579 | xfr->client->shutdown = NULL; |
1580 | xfr->client->shutdown_arg = NULL; | | 1580 | xfr->client->shutdown_arg = NULL; |
1581 | | | 1581 | |
1582 | if (xfr->stream != NULL) | | 1582 | if (xfr->stream != NULL) |
1583 | xfr->stream->methods->destroy(&xfr->stream); | | 1583 | xfr->stream->methods->destroy(&xfr->stream); |
1584 | if (xfr->buf.base != NULL) | | 1584 | if (xfr->buf.base != NULL) |
1585 | isc_mem_put(xfr->mctx, xfr->buf.base, xfr->buf.length); | | 1585 | isc_mem_put(xfr->mctx, xfr->buf.base, xfr->buf.length); |
1586 | if (xfr->txmem != NULL) | | 1586 | if (xfr->txmem != NULL) |
1587 | isc_mem_put(xfr->mctx, xfr->txmem, xfr->txmemlen); | | 1587 | isc_mem_put(xfr->mctx, xfr->txmem, xfr->txmemlen); |
1588 | if (xfr->lasttsig != NULL) | | 1588 | if (xfr->lasttsig != NULL) |
1589 | isc_buffer_free(&xfr->lasttsig); | | 1589 | isc_buffer_free(&xfr->lasttsig); |
1590 | if (xfr->quota != NULL) | | 1590 | if (xfr->quota != NULL) |
1591 | isc_quota_detach(&xfr->quota); | | 1591 | isc_quota_detach(&xfr->quota); |
1592 | if (xfr->ver != NULL) | | 1592 | if (xfr->ver != NULL) |
1593 | dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE); | | 1593 | dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE); |
1594 | if (xfr->zone != NULL) | | 1594 | if (xfr->zone != NULL) |
1595 | dns_zone_detach(&xfr->zone); | | 1595 | dns_zone_detach(&xfr->zone); |
1596 | if (xfr->db != NULL) | | 1596 | if (xfr->db != NULL) |
1597 | dns_db_detach(&xfr->db); | | 1597 | dns_db_detach(&xfr->db); |
1598 | | | 1598 | |
1599 | /* | | 1599 | /* |
1600 | * We want to detch the client after we have released the memory | | 1600 | * We want to detch the client after we have released the memory |
1601 | * context as ns_client_detach checks the memory reference count. | | 1601 | * context as ns_client_detach checks the memory reference count. |
1602 | */ | | 1602 | */ |
1603 | ns_client_attach(xfr->client, &client); | | 1603 | ns_client_attach(xfr->client, &client); |
1604 | ns_client_detach(&xfr->client); | | 1604 | ns_client_detach(&xfr->client); |
1605 | isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr)); | | 1605 | isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr)); |
1606 | ns_client_detach(&client); | | 1606 | ns_client_detach(&client); |
1607 | | | 1607 | |
1608 | *xfrp = NULL; | | 1608 | *xfrp = NULL; |
1609 | } | | 1609 | } |
1610 | | | 1610 | |
1611 | static void | | 1611 | static void |
1612 | xfrout_senddone(isc_task_t *task, isc_event_t *event) { | | 1612 | xfrout_senddone(isc_task_t *task, isc_event_t *event) { |
1613 | isc_socketevent_t *sev = (isc_socketevent_t *)event; | | 1613 | isc_socketevent_t *sev = (isc_socketevent_t *)event; |
1614 | xfrout_ctx_t *xfr = (xfrout_ctx_t *)event->ev_arg; | | 1614 | xfrout_ctx_t *xfr = (xfrout_ctx_t *)event->ev_arg; |
1615 | isc_result_t evresult = sev->result; | | 1615 | isc_result_t evresult = sev->result; |
1616 | | | 1616 | |
1617 | UNUSED(task); | | 1617 | UNUSED(task); |
1618 | | | 1618 | |
1619 | INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE); | | 1619 | INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE); |
1620 | | | 1620 | |
1621 | isc_event_free(&event); | | 1621 | isc_event_free(&event); |
1622 | xfr->sends--; | | 1622 | xfr->sends--; |
1623 | INSIST(xfr->sends == 0); | | 1623 | INSIST(xfr->sends == 0); |
1624 | | | 1624 | |
1625 | (void)isc_timer_touch(xfr->client->timer); | | 1625 | (void)isc_timer_touch(xfr->client->timer); |
1626 | if (xfr->shuttingdown == ISC_TRUE) { | | 1626 | if (xfr->shuttingdown == ISC_TRUE) { |
1627 | xfrout_maybe_destroy(xfr); | | 1627 | xfrout_maybe_destroy(xfr); |
1628 | } else if (evresult != ISC_R_SUCCESS) { | | 1628 | } else if (evresult != ISC_R_SUCCESS) { |
1629 | xfrout_fail(xfr, evresult, "send"); | | 1629 | xfrout_fail(xfr, evresult, "send"); |
1630 | } else if (xfr->end_of_stream == ISC_FALSE) { | | 1630 | } else if (xfr->end_of_stream == ISC_FALSE) { |
1631 | sendstream(xfr); | | 1631 | sendstream(xfr); |
1632 | } else { | | 1632 | } else { |
1633 | /* End of zone transfer stream. */ | | 1633 | /* End of zone transfer stream. */ |
1634 | inc_stats(xfr->zone, dns_nsstatscounter_xfrdone); | | 1634 | inc_stats(xfr->zone, dns_nsstatscounter_xfrdone); |
1635 | xfrout_log(xfr, ISC_LOG_INFO, "%s ended", xfr->mnemonic); | | 1635 | xfrout_log(xfr, ISC_LOG_INFO, "%s ended", xfr->mnemonic); |
1636 | ns_client_next(xfr->client, ISC_R_SUCCESS); | | 1636 | ns_client_next(xfr->client, ISC_R_SUCCESS); |
1637 | xfrout_ctx_destroy(&xfr); | | 1637 | xfrout_ctx_destroy(&xfr); |
1638 | } | | 1638 | } |
1639 | } | | 1639 | } |
1640 | | | 1640 | |
1641 | static void | | 1641 | static void |
1642 | xfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg) { | | 1642 | xfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg) { |
1643 | xfr->shuttingdown = ISC_TRUE; | | 1643 | xfr->shuttingdown = ISC_TRUE; |
1644 | xfrout_log(xfr, ISC_LOG_ERROR, "%s: %s", | | 1644 | xfrout_log(xfr, ISC_LOG_ERROR, "%s: %s", |
1645 | msg, isc_result_totext(result)); | | 1645 | msg, isc_result_totext(result)); |
1646 | xfrout_maybe_destroy(xfr); | | 1646 | xfrout_maybe_destroy(xfr); |
1647 | } | | 1647 | } |
1648 | | | 1648 | |
1649 | static void | | 1649 | static void |
1650 | xfrout_maybe_destroy(xfrout_ctx_t *xfr) { | | 1650 | xfrout_maybe_destroy(xfrout_ctx_t *xfr) { |
1651 | INSIST(xfr->shuttingdown == ISC_TRUE); | | 1651 | INSIST(xfr->shuttingdown == ISC_TRUE); |
1652 | if (xfr->sends > 0) { | | 1652 | if (xfr->sends > 0) { |
1653 | /* | | 1653 | /* |
1654 | * If we are currently sending, cancel it and wait for | | 1654 | * If we are currently sending, cancel it and wait for |
1655 | * cancel event before destroying the context. | | 1655 | * cancel event before destroying the context. |
1656 | */ | | 1656 | */ |
1657 | isc_socket_cancel(xfr->client->tcpsocket, xfr->client->task, | | 1657 | isc_socket_cancel(xfr->client->tcpsocket, xfr->client->task, |
1658 | ISC_SOCKCANCEL_SEND); | | 1658 | ISC_SOCKCANCEL_SEND); |
1659 | } else { | | 1659 | } else { |
1660 | ns_client_next(xfr->client, ISC_R_CANCELED); | | 1660 | ns_client_next(xfr->client, ISC_R_CANCELED); |
1661 | xfrout_ctx_destroy(&xfr); | | 1661 | xfrout_ctx_destroy(&xfr); |
1662 | } | | 1662 | } |
1663 | } | | 1663 | } |
1664 | | | 1664 | |
1665 | static void | | 1665 | static void |
1666 | xfrout_client_shutdown(void *arg, isc_result_t result) { | | 1666 | xfrout_client_shutdown(void *arg, isc_result_t result) { |
1667 | xfrout_ctx_t *xfr = (xfrout_ctx_t *) arg; | | 1667 | xfrout_ctx_t *xfr = (xfrout_ctx_t *) arg; |
1668 | xfrout_fail(xfr, result, "aborted"); | | 1668 | xfrout_fail(xfr, result, "aborted"); |
1669 | } | | 1669 | } |
1670 | | | 1670 | |
1671 | /* | | 1671 | /* |
1672 | * Log outgoing zone transfer messages in a format like | | 1672 | * Log outgoing zone transfer messages in a format like |
1673 | * <client>: transfer of <zone>: <message> | | 1673 | * <client>: transfer of <zone>: <message> |
1674 | */ | | 1674 | */ |
1675 | | | 1675 | |
1676 | static void | | 1676 | static void |
1677 | xfrout_logv(ns_client_t *client, dns_name_t *zonename, | | 1677 | xfrout_logv(ns_client_t *client, dns_name_t *zonename, |
1678 | dns_rdataclass_t rdclass, int level, const char *fmt, va_list ap) | | 1678 | dns_rdataclass_t rdclass, int level, const char *fmt, va_list ap) |
1679 | ISC_FORMAT_PRINTF(5, 0); | | 1679 | ISC_FORMAT_PRINTF(5, 0); |
1680 | | | 1680 | |
1681 | static void | | 1681 | static void |
1682 | xfrout_logv(ns_client_t *client, dns_name_t *zonename, | | 1682 | xfrout_logv(ns_client_t *client, dns_name_t *zonename, |
1683 | dns_rdataclass_t rdclass, int level, const char *fmt, va_list ap) | | 1683 | dns_rdataclass_t rdclass, int level, const char *fmt, va_list ap) |
1684 | { | | 1684 | { |
1685 | char msgbuf[2048]; | | 1685 | char msgbuf[2048]; |
1686 | char namebuf[DNS_NAME_FORMATSIZE]; | | 1686 | char namebuf[DNS_NAME_FORMATSIZE]; |
1687 | char classbuf[DNS_RDATACLASS_FORMATSIZE]; | | 1687 | char classbuf[DNS_RDATACLASS_FORMATSIZE]; |
1688 | | | 1688 | |
1689 | dns_name_format(zonename, namebuf, sizeof(namebuf)); | | 1689 | dns_name_format(zonename, namebuf, sizeof(namebuf)); |
1690 | dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf)); | | 1690 | dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf)); |
1691 | vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); | | 1691 | vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); |
1692 | ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, | | 1692 | ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, |
1693 | NS_LOGMODULE_XFER_OUT, level, | | 1693 | NS_LOGMODULE_XFER_OUT, level, |
1694 | "transfer of '%s/%s': %s", namebuf, classbuf, msgbuf); | | 1694 | "transfer of '%s/%s': %s", namebuf, classbuf, msgbuf); |
1695 | } | | 1695 | } |
1696 | | | 1696 | |
1697 | /* | | 1697 | /* |
1698 | * Logging function for use when a xfrout_ctx_t has not yet been created. | | 1698 | * Logging function for use when a xfrout_ctx_t has not yet been created. |
1699 | */ | | 1699 | */ |
1700 | static void | | 1700 | static void |
1701 | xfrout_log1(ns_client_t *client, dns_name_t *zonename, | | 1701 | xfrout_log1(ns_client_t *client, dns_name_t *zonename, |
1702 | dns_rdataclass_t rdclass, int level, const char *fmt, ...) { | | 1702 | dns_rdataclass_t rdclass, int level, const char *fmt, ...) { |
1703 | va_list ap; | | 1703 | va_list ap; |
1704 | va_start(ap, fmt); | | 1704 | va_start(ap, fmt); |
1705 | xfrout_logv(client, zonename, rdclass, level, fmt, ap); | | 1705 | xfrout_logv(client, zonename, rdclass, level, fmt, ap); |
1706 | va_end(ap); | | 1706 | va_end(ap); |
1707 | } | | 1707 | } |
1708 | | | 1708 | |
1709 | /* | | 1709 | /* |
1710 | * Logging function for use when there is a xfrout_ctx_t. | | 1710 | * Logging function for use when there is a xfrout_ctx_t. |
1711 | */ | | 1711 | */ |
1712 | static void | | 1712 | static void |
1713 | xfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...) { | | 1713 | xfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...) { |
1714 | va_list ap; | | 1714 | va_list ap; |
1715 | va_start(ap, fmt); | | 1715 | va_start(ap, fmt); |
1716 | xfrout_logv(xfr->client, xfr->qname, xfr->qclass, level, fmt, ap); | | 1716 | xfrout_logv(xfr->client, xfr->qname, xfr->qclass, level, fmt, ap); |
1717 | va_end(ap); | | 1717 | va_end(ap); |
1718 | } | | 1718 | } |