lib/query.jsView |
---|
98 | 98 … | Pull.filter()); |
99 | 99 … | }; |
100 | 100 … | |
101 | 101 … | function expandName(name, wildcard) { |
102 | | - var names = {}; |
| 102 … | + var names = {'': true}; |
| 103 … | + names[name] = true; |
103 | 104 … | for (var labels = name.split(/\./); labels.length; labels.shift()) { |
104 | 105 … | if (wildcard) labels[0] = wildcard; |
105 | 106 … | names[labels.join('.')] = true; |
106 | 107 … | } |
107 | 108 … | return names; |
108 | 109 … | } |
109 | 110 … | |
| 111 … | +function Records() { |
| 112 … | + this.recs = []; |
| 113 … | +} |
| 114 … | + |
| 115 … | +Records.prototype.addRecord = function (record) { |
| 116 … | + this.recs.push(record); |
| 117 … | +}; |
| 118 … | + |
| 119 … | +Records.prototype.getRecords = function () { |
| 120 … | + return this.recs; |
| 121 … | +}; |
| 122 … | + |
110 | 123 … | function Wildcards() { |
111 | 124 … | this.lengths = []; |
112 | 125 … | this.recordsByLength = {}; |
113 | 126 … | } |
134 | 147 … | function ZoneSerials() { |
135 | 148 … | this.serials = {}; |
136 | 149 … | } |
137 | 150 … | |
138 | | -ZoneSerials.prototype.addRecord = function (record) { |
139 | | - for (var zone in expandName(record.name)) { |
| 151 … | +ZoneSerials.prototype.addRecord = function (zones) { |
| 152 … | + for (var zone in zones) { |
140 | 153 … | this.serials[zone] = (+this.serials[zone] || 0) + 1; |
141 | 154 … | } |
142 | 155 … | }; |
143 | 156 … | |
178 | 191 … | } |
179 | 192 … | |
180 | 193 … | |
181 | 194 … | Query.queryRecursive = function (sbot, question, stack, cb) { |
| 195 … | + var isTransfer = question.type === 'AXFR' |
| 196 … | + |
182 | 197 … | var result = { |
183 | 198 … | answers: [], |
184 | 199 … | authorities: [], |
185 | 200 … | additionals: [], |
| 201 … | + questions: [], |
186 | 202 … | expires: Date.now() + 60*60e3, |
187 | 203 … | }; |
188 | 204 … | |
189 | 205 … | |
201 | 217 … | |
202 | 218 … | merge(result.additionals, res.additionals); |
203 | 219 … | merge(result.answers, res.answers); |
204 | 220 … | merge(result.authorities, res.authorities); |
| 221 … | + merge(result.questions, res.questions); |
205 | 222 … | if (res.expires < result.expires) result.expires = res.expires; |
206 | 223 … | |
207 | 224 … | |
208 | | - if (question.type !== 'CNAME') { |
| 225 … | + if (!isTransfer && question.type !== 'CNAME') { |
209 | 226 … | var stack2 = stack.concat(question) |
210 | 227 … | res.answers.filter(function (answer) { |
211 | 228 … | return answer.type === 'CNAME'; |
212 | 229 … | }).map(function (record) { |
229 | 246 … | |
230 | 247 … | |
231 | 248 … | var authorityDomains = expandName(question.name); |
232 | 249 … | var wildcardDomains = expandName(question.name, '*'); |
| 250 … | + var isTransfer = question.type === 'AXFR' |
233 | 251 … | var authorities = new Wildcards(); |
234 | | - var answers = new Wildcards(); |
| 252 … | + var answers = isTransfer ? new Records() : new Wildcards(); |
235 | 253 … | var zoneSerials = new ZoneSerials(); |
236 | 254 … | var result = {}; |
237 | 255 … | Pull(Query.all(sbot), |
238 | 256 … | Pull.filter(function (record) { |
239 | | - zoneSerials.addRecord(record); |
240 | | - var nameMatches = record.name == question.name |
241 | | - || record.name in wildcardDomains |
| 257 … | + var recordDomains = expandName(record.name); |
| 258 … | + zoneSerials.addRecord(recordDomains); |
| 259 … | + var nameMatches = isTransfer |
| 260 … | + ? question.name in recordDomains |
| 261 … | + : record.name in wildcardDomains; |
242 | 262 … | if (nameMatches) { |
243 | 263 … | result.domainExists = true; |
244 | 264 … | } |
245 | 265 … | if (record.type === 'SOA') { |
246 | | - return record.name in authorityDomains |
| 266 … | + return record.name in authorityDomains; |
247 | 267 … | } |
248 | 268 … | return nameMatches |
249 | | - && (record.type == question.type || record.type === 'CNAME') |
250 | | - && record.class == question.class; |
| 269 … | + && (isTransfer |
| 270 … | + || question.type === record.type |
| 271 … | + || question.type === '*' |
| 272 … | + || 'CNAME' === record.type) |
| 273 … | + && (question.class === record.class |
| 274 … | + || question.class === '*'); |
251 | 275 … | }), |
252 | 276 … | Query.drainSet(function (record) { |
253 | 277 … | if (record.type === 'SOA') { |
254 | 278 … | result.authoritative = true; |
255 | | - if (question.type === 'SOA' |
256 | | - && question.class === record.class |
257 | | - && (question.name === record.name |
258 | | - || record.name in wildcardDomains)) { |
| 279 … | + if (question.class === record.class |
| 280 … | + && question.type === 'SOA' |
| 281 … | + && record.name in wildcardDomains) { |
259 | 282 … | answers.addRecord(record); |
260 | 283 … | } else { |
261 | 284 … | authorities.addRecord(record); |
| 285 … | + if (isTransfer) { |
| 286 … | + answers.addRecord(record); |
| 287 … | + } |
262 | 288 … | } |
263 | 289 … | } else { |
264 | 290 … | answers.addRecord(record); |
265 | 291 … | } |
282 | 308 … | } |
283 | 309 … | }); |
284 | 310 … | result.expires = Date.now() + ttl * 60e3; |
285 | 311 … | result.additionals = []; |
| 312 … | + result.questions = []; |
| 313 … | + |
| 314 … | + if (isTransfer) { |
| 315 … | + |
| 316 … | + result.questions.push(question); |
| 317 … | + |
| 318 … | + var soa = result.authorities.splice(0)[0]; |
| 319 … | + result.answers = [soa].concat(result.answers.filter(function (r) { |
| 320 … | + return r !== soa; |
| 321 … | + }), [soa]); |
| 322 … | + } |
286 | 323 … | cb(null, result); |
287 | 324 … | })); |
288 | 325 … | }; |