~tritone-team/tritone/eucalyptus

« back to all changes in this revision

Viewing changes to clc/modules/dns/src/main/java/com/eucalyptus/cloud/ws/ConnectionHandler.java

  • Committer: Bazaar Package Importer
  • Author(s): Dustin Kirkland
  • Date: 2009-12-01 21:09:28 UTC
  • mto: This revision was merged to the branch mainline in revision 75.
  • Revision ID: james.westby@ubuntu.com-20091201210928-o2dvg0ubljhb0ft6
Tags: upstream-1.6.1~bzr1083
ImportĀ upstreamĀ versionĀ 1.6.1~bzr1083

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*******************************************************************************
2
 
*Copyright (c) 2009  Eucalyptus Systems, Inc.
3
 
4
 
*  This program is free software: you can redistribute it and/or modify
5
 
*  it under the terms of the GNU General Public License as published by
6
 
*  the Free Software Foundation, only version 3 of the License.
7
 
8
 
9
 
*  This file is distributed in the hope that it will be useful, but WITHOUT
10
 
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 
*  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
 
*  for more details.
13
 
14
 
*  You should have received a copy of the GNU General Public License along
15
 
*  with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
 
*  Please contact Eucalyptus Systems, Inc., 130 Castilian
18
 
*  Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/>
19
 
*  if you need additional information or have any questions.
20
 
21
 
*  This file may incorporate work covered under the following copyright and
22
 
*  permission notice:
23
 
24
 
*    Software License Agreement (BSD License)
25
 
26
 
*    Copyright (c) 2008, Regents of the University of California
27
 
*    All rights reserved.
28
 
29
 
*    Redistribution and use of this software in source and binary forms, with
30
 
*    or without modification, are permitted provided that the following
31
 
*    conditions are met:
32
 
33
 
*      Redistributions of source code must retain the above copyright notice,
34
 
*      this list of conditions and the following disclaimer.
35
 
36
 
*      Redistributions in binary form must reproduce the above copyright
37
 
*      notice, this list of conditions and the following disclaimer in the
38
 
*      documentation and/or other materials provided with the distribution.
39
 
40
 
*    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
41
 
*    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
42
 
*    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
43
 
*    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
44
 
*    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45
 
*    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
46
 
*    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
47
 
*    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
48
 
*    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
49
 
*    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50
 
*    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
51
 
*    THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
52
 
*    LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
53
 
*    SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
54
 
*    IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
55
 
*    BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
56
 
*    THE REGENTSā€™ DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
57
 
*    OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
58
 
*    WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
59
 
*    ANY SUCH LICENSES OR RIGHTS.
60
 
*******************************************************************************/
 
2
 *Copyright (c) 2009  Eucalyptus Systems, Inc.
 
3
 * 
 
4
 *  This program is free software: you can redistribute it and/or modify
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation, only version 3 of the License.
 
7
 * 
 
8
 * 
 
9
 *  This file is distributed in the hope that it will be useful, but WITHOUT
 
10
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
11
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
12
 *  for more details.
 
13
 * 
 
14
 *  You should have received a copy of the GNU General Public License along
 
15
 *  with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
 * 
 
17
 *  Please contact Eucalyptus Systems, Inc., 130 Castilian
 
18
 *  Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/>
 
19
 *  if you need additional information or have any questions.
 
20
 * 
 
21
 *  This file may incorporate work covered under the following copyright and
 
22
 *  permission notice:
 
23
 * 
 
24
 *    Software License Agreement (BSD License)
 
25
 * 
 
26
 *    Copyright (c) 2008, Regents of the University of California
 
27
 *    All rights reserved.
 
28
 * 
 
29
 *    Redistribution and use of this software in source and binary forms, with
 
30
 *    or without modification, are permitted provided that the following
 
31
 *    conditions are met:
 
32
 * 
 
33
 *      Redistributions of source code must retain the above copyright notice,
 
34
 *      this list of conditions and the following disclaimer.
 
35
 * 
 
36
 *      Redistributions in binary form must reproduce the above copyright
 
37
 *      notice, this list of conditions and the following disclaimer in the
 
38
 *      documentation and/or other materials provided with the distribution.
 
39
 * 
 
40
 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 
41
 *    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 
42
 *    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 
43
 *    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 
44
 *    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
45
 *    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
46
 *    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
47
 *    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 
48
 *    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
49
 *    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
50
 *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
 
51
 *    THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
 
52
 *    LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
 
53
 *    SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
 
54
 *    IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
 
55
 *    BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
 
56
 *    THE REGENTSā€™ DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
 
57
 *    OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
 
58
 *    WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
 
59
 *    ANY SUCH LICENSES OR RIGHTS.
 
60
 *******************************************************************************/
61
61
/*
62
62
 *
63
63
 * Author: Neil Soman neil@eucalyptus.com
103
103
 
104
104
public class ConnectionHandler extends Thread {
105
105
 
106
 
    static final int FLAG_DNSSECOK = 1;
107
 
    static final int FLAG_SIGONLY = 2;
108
 
 
109
 
    Map caches = new ConcurrentHashMap();
110
 
    //Map TSIGs;
111
 
 
112
 
    byte []
113
 
    generateReply(Message query, byte [] in, int length, Socket s)
114
 
            throws IOException
115
 
    {
116
 
        Header header;
117
 
        boolean badversion;
118
 
        int maxLength;
119
 
        boolean sigonly;
120
 
        SetResponse sr;
121
 
        int flags = 0;
122
 
 
123
 
        header = query.getHeader();
124
 
        if (header.getFlag(Flags.QR))
125
 
            return null;
126
 
        if (header.getRcode() != Rcode.NOERROR)
127
 
            return errorMessage(query, Rcode.FORMERR);
128
 
        if (header.getOpcode() != Opcode.QUERY)
129
 
            return errorMessage(query, Rcode.NOTIMP);
130
 
 
131
 
        Record queryRecord = query.getQuestion();
132
 
 
133
 
        TSIGRecord queryTSIG = query.getTSIG();
134
 
        TSIG tsig = null;
135
 
        /*  if (queryTSIG != null) {
 
106
        static final int FLAG_DNSSECOK = 1;
 
107
        static final int FLAG_SIGONLY = 2;
 
108
 
 
109
        Map caches = new ConcurrentHashMap();
 
110
        //Map TSIGs;
 
111
 
 
112
        byte []
 
113
              generateReply(Message query, byte [] in, int length, Socket s)
 
114
        throws IOException
 
115
        {
 
116
                Header header;
 
117
                boolean badversion;
 
118
                int maxLength;
 
119
                boolean sigonly;
 
120
                SetResponse sr;
 
121
                int flags = 0;
 
122
 
 
123
                header = query.getHeader();
 
124
                if (header.getFlag(Flags.QR))
 
125
                        return null;
 
126
                if (header.getRcode() != Rcode.NOERROR)
 
127
                        return errorMessage(query, Rcode.FORMERR);
 
128
                if (header.getOpcode() != Opcode.QUERY)
 
129
                        return errorMessage(query, Rcode.NOTIMP);
 
130
 
 
131
                Record queryRecord = query.getQuestion();
 
132
 
 
133
                TSIGRecord queryTSIG = query.getTSIG();
 
134
                TSIG tsig = null;
 
135
                /*  if (queryTSIG != null) {
136
136
            tsig = (TSIG) TSIGs.get(queryTSIG.getName());
137
137
            if (tsig == null ||
138
138
                    tsig.verify(query, in, length, null) != Rcode.NOERROR)
139
139
                return formerrMessage(in);
140
140
        }*/
141
141
 
142
 
        OPTRecord queryOPT = query.getOPT();
143
 
        if (queryOPT != null && queryOPT.getVersion() > 0)
144
 
            badversion = true;
145
 
 
146
 
        if (s != null)
147
 
            maxLength = 65535;
148
 
        else if (queryOPT != null)
149
 
            maxLength = Math.max(queryOPT.getPayloadSize(), 512);
150
 
        else
151
 
            maxLength = 512;
152
 
 
153
 
        if (queryOPT != null && (queryOPT.getFlags() & ExtendedFlags.DO) != 0)
154
 
            flags = FLAG_DNSSECOK;
155
 
 
156
 
        Message response = new Message(query.getHeader().getID());
157
 
        response.getHeader().setFlag(Flags.QR);
158
 
        if (query.getHeader().getFlag(Flags.RD))
159
 
            response.getHeader().setFlag(Flags.RD);
160
 
        response.addRecord(queryRecord, Section.QUESTION);
161
 
 
162
 
        Name name = queryRecord.getName();
163
 
        int type = queryRecord.getType();
164
 
        int dclass = queryRecord.getDClass();
165
 
/*        if (type == Type.AXFR && s != null)
 
142
                OPTRecord queryOPT = query.getOPT();
 
143
                if (queryOPT != null && queryOPT.getVersion() > 0)
 
144
                        badversion = true;
 
145
 
 
146
                if (s != null)
 
147
                        maxLength = 65535;
 
148
                else if (queryOPT != null)
 
149
                        maxLength = Math.max(queryOPT.getPayloadSize(), 512);
 
150
                else
 
151
                        maxLength = 512;
 
152
 
 
153
                if (queryOPT != null && (queryOPT.getFlags() & ExtendedFlags.DO) != 0)
 
154
                        flags = FLAG_DNSSECOK;
 
155
 
 
156
                Message response = new Message(query.getHeader().getID());
 
157
                response.getHeader().setFlag(Flags.QR);
 
158
                if (query.getHeader().getFlag(Flags.RD))
 
159
                        response.getHeader().setFlag(Flags.RD);
 
160
                if(queryRecord != null) {
 
161
                        response.addRecord(queryRecord, Section.QUESTION);
 
162
 
 
163
                        Name name = queryRecord.getName();
 
164
                        int type = queryRecord.getType();
 
165
                        int dclass = queryRecord.getDClass();
 
166
 
 
167
                        /*        if (type == Type.AXFR && s != null)
166
168
            return doAXFR(name, query, tsig, queryTSIG, s);
167
 
  */    if (!Type.isRR(type) && type != Type.ANY)
168
 
        return errorMessage(query, Rcode.NOTIMP);
169
 
 
170
 
        byte rcode = addAnswer(response, name, type, dclass, 0, flags);
171
 
        if (rcode != Rcode.NOERROR && rcode != Rcode.NXDOMAIN)
172
 
            return errorMessage(query, rcode);
173
 
 
174
 
        addAdditional(response, flags);
175
 
 
176
 
        if (queryOPT != null) {
177
 
            int optflags = (flags == FLAG_DNSSECOK) ? ExtendedFlags.DO : 0;
178
 
            OPTRecord opt = new OPTRecord((short)4096, rcode, (byte)0,
179
 
                    optflags);
180
 
            response.addRecord(opt, Section.ADDITIONAL);
181
 
        }
182
 
 
183
 
        response.setTSIG(tsig, Rcode.NOERROR, queryTSIG);
184
 
        return response.toWire(maxLength);
185
 
    }
186
 
 
187
 
    public Zone
188
 
    findBestZone(Name name) {
189
 
        Zone foundzone = null;
190
 
        foundzone = (Zone) ZoneManager.getZone(name);
191
 
        if (foundzone != null)
192
 
            return foundzone;
193
 
        int labels = name.labels();
194
 
        for (int i = 1; i < labels; i++) {
195
 
            Name tname = new Name(name, i);
196
 
            foundzone = (Zone) ZoneManager.getZone(tname);
197
 
            if (foundzone != null)
198
 
                return foundzone;
199
 
        }
200
 
        return null;
201
 
    }
202
 
 
203
 
    public RRset
204
 
    findExactMatch(Name name, int type, int dclass, boolean glue) {
205
 
        Zone zone = findBestZone(name);
206
 
        if (zone != null)
207
 
            return zone.findExactMatch(name, type);
208
 
        else {
209
 
            RRset [] rrsets;
210
 
            Cache cache = getCache(dclass);
211
 
            if (glue)
212
 
                rrsets = cache.findAnyRecords(name, type);
213
 
            else
214
 
                rrsets = cache.findRecords(name, type);
215
 
            if (rrsets == null)
216
 
                return null;
217
 
            else
218
 
                return rrsets[0]; /* not quite right */
219
 
        }
220
 
    }
221
 
 
222
 
    private void
223
 
    addGlue(Message response, Name name, int flags) {
224
 
        RRset a = findExactMatch(name, Type.A, DClass.IN, true);
225
 
        if (a == null)
226
 
            return;
227
 
        addRRset(name, response, a, Section.ADDITIONAL, flags);
228
 
    }
229
 
 
230
 
    private void
231
 
    addAdditional2(Message response, int section, int flags) {
232
 
        Record [] records = response.getSectionArray(section);
233
 
        for (int i = 0; i < records.length; i++) {
234
 
            Record r = records[i];
235
 
            Name glueName = r.getAdditionalName();
236
 
            if (glueName != null)
237
 
                addGlue(response, glueName, flags);
238
 
        }
239
 
    }
240
 
 
241
 
    private final void
242
 
    addAdditional(Message response, int flags) {
243
 
        addAdditional2(response, Section.ANSWER, flags);
244
 
        addAdditional2(response, Section.AUTHORITY, flags);
245
 
    }
246
 
 
247
 
    byte
248
 
    addAnswer(Message response, Name name, int type, int dclass,
249
 
              int iterations, int flags)
250
 
    {
251
 
        SetResponse sr;
252
 
        byte rcode = Rcode.NOERROR;
253
 
 
254
 
        if (iterations > 6)
255
 
            return Rcode.NOERROR;
256
 
 
257
 
        if (type == Type.SIG || type == Type.RRSIG) {
258
 
            type = Type.ANY;
259
 
            flags |= FLAG_SIGONLY;
260
 
        }
261
 
 
262
 
        Zone zone = findBestZone(name);
263
 
        if (zone != null)
264
 
            sr = zone.findRecords(name, type);
265
 
        else {
266
 
            Cache cache = getCache(dclass);
267
 
            sr = cache.lookupRecords(name, type, Credibility.NORMAL);
268
 
        }
269
 
 
270
 
        if (sr.isUnknown()) {
271
 
            addCacheNS(response, getCache(dclass), name);
272
 
        }
273
 
        if (sr.isNXDOMAIN()) {
274
 
            response.getHeader().setRcode(Rcode.NXDOMAIN);
275
 
            if (zone != null) {
276
 
                addSOA(response, zone);
277
 
                if (iterations == 0)
278
 
                    response.getHeader().setFlag(Flags.AA);
279
 
            }
280
 
            rcode = Rcode.NXDOMAIN;
281
 
        }
282
 
        else if (sr.isNXRRSET()) {
283
 
            if (zone != null) {
284
 
                addSOA(response, zone);
285
 
                if (iterations == 0)
286
 
                    response.getHeader().setFlag(Flags.AA);
287
 
            }
288
 
        }
289
 
        else if (sr.isDelegation()) {
290
 
            RRset nsRecords = sr.getNS();
291
 
            addRRset(nsRecords.getName(), response, nsRecords,
292
 
                    Section.AUTHORITY, flags);
293
 
        }
294
 
        else if (sr.isCNAME()) {
295
 
            CNAMERecord cname = sr.getCNAME();
296
 
            RRset rrset = new RRset(cname);
297
 
            addRRset(name, response, rrset, Section.ANSWER, flags);
298
 
            if (zone != null && iterations == 0)
299
 
                response.getHeader().setFlag(Flags.AA);
300
 
            rcode = addAnswer(response, cname.getTarget(),
301
 
                    type, dclass, iterations + 1, flags);
302
 
        }
303
 
        else if (sr.isDNAME()) {
304
 
            DNAMERecord dname = sr.getDNAME();
305
 
            RRset rrset = new RRset(dname);
306
 
            addRRset(name, response, rrset, Section.ANSWER, flags);
307
 
            Name newname;
308
 
            try {
309
 
                newname = name.fromDNAME(dname);
310
 
            }
311
 
            catch (NameTooLongException e) {
312
 
                return Rcode.YXDOMAIN;
313
 
            }
314
 
            rrset = new RRset(new CNAMERecord(name, dclass, 0, newname));
315
 
            addRRset(name, response, rrset, Section.ANSWER, flags);
316
 
            if (zone != null && iterations == 0)
317
 
                response.getHeader().setFlag(Flags.AA);
318
 
            rcode = addAnswer(response, newname, type, dclass,
319
 
                    iterations + 1, flags);
320
 
        }
321
 
        else if (sr.isSuccessful()) {
322
 
            RRset [] rrsets = sr.answers();
323
 
            for (int i = 0; i < rrsets.length; i++)
324
 
                addRRset(name, response, rrsets[i],
325
 
                        Section.ANSWER, flags);
326
 
            if (zone != null) {
327
 
                addNS(response, zone, flags);
328
 
                if (iterations == 0)
329
 
                    response.getHeader().setFlag(Flags.AA);
330
 
            }
331
 
            else
332
 
                addCacheNS(response, getCache(dclass), name);
333
 
        }
334
 
        return rcode;
335
 
    }
336
 
 
337
 
 
338
 
    private final void
339
 
    addSOA(Message response, Zone zone) {
340
 
        response.addRecord(zone.getSOA(), Section.AUTHORITY);
341
 
    }
342
 
 
343
 
    private final void
344
 
    addNS(Message response, Zone zone, int flags) {
345
 
        RRset nsRecords = zone.getNS();
346
 
        addRRset(nsRecords.getName(), response, nsRecords,
347
 
                Section.AUTHORITY, flags);
348
 
    }
349
 
 
350
 
    private final void
351
 
    addCacheNS(Message response, Cache cache, Name name) {
352
 
        SetResponse sr = cache.lookupRecords(name, Type.NS, Credibility.HINT);
353
 
        if (!sr.isDelegation())
354
 
            return;
355
 
        RRset nsRecords = sr.getNS();
356
 
        Iterator it = nsRecords.rrs();
357
 
        while (it.hasNext()) {
358
 
            Record r = (Record) it.next();
359
 
            response.addRecord(r, Section.AUTHORITY);
360
 
        }
361
 
    }
362
 
 
363
 
 
364
 
    byte []
365
 
    doAXFR(Name name, Message query, TSIG tsig, TSIGRecord qtsig, Socket s) {
366
 
        Zone zone = (Zone) ZoneManager.getZone(name);
367
 
        boolean first = true;
368
 
        if (zone == null)
369
 
            return errorMessage(query, Rcode.REFUSED);
370
 
        Iterator it = zone.AXFR();
371
 
        try {
372
 
            DataOutputStream dataOut;
373
 
            dataOut = new DataOutputStream(s.getOutputStream());
374
 
            int id = query.getHeader().getID();
375
 
            while (it.hasNext()) {
376
 
                RRset rrset = (RRset) it.next();
377
 
                Message response = new Message(id);
378
 
                Header header = response.getHeader();
379
 
                header.setFlag(Flags.QR);
380
 
                header.setFlag(Flags.AA);
381
 
                addRRset(rrset.getName(), response, rrset,
382
 
                        Section.ANSWER, FLAG_DNSSECOK);
383
 
                if (tsig != null) {
384
 
                    tsig.applyStream(response, qtsig, first);
385
 
                    qtsig = response.getTSIG();
386
 
                }
387
 
                first = false;
388
 
                byte [] out = response.toWire();
389
 
                dataOut.writeShort(out.length);
390
 
                dataOut.write(out);
391
 
            }
392
 
        }
393
 
        catch (IOException ex) {
394
 
            System.out.println("AXFR failed");
395
 
        }
396
 
        try {
397
 
            s.close();
398
 
        }
399
 
        catch (IOException ex) {
400
 
        }
401
 
        return null;
402
 
    }
403
 
 
404
 
    void
405
 
    addRRset(Name name, Message response, RRset rrset, int section, int flags) {
406
 
        for (int s = 1; s <= section; s++)
407
 
            if (response.findRRset(name, rrset.getType(), s))
408
 
                return;
409
 
        if ((flags & FLAG_SIGONLY) == 0) {
410
 
            Iterator it = rrset.rrs();
411
 
            while (it.hasNext()) {
412
 
                Record r = (Record) it.next();
413
 
                if (r.getName().isWild() && !name.isWild())
414
 
                    r = r.withName(name);
415
 
                response.addRecord(r, section);
416
 
            }
417
 
        }
418
 
        if ((flags & (FLAG_SIGONLY | FLAG_DNSSECOK)) != 0) {
419
 
            Iterator it = rrset.sigs();
420
 
            while (it.hasNext()) {
421
 
                Record r = (Record) it.next();
422
 
                if (r.getName().isWild() && !name.isWild())
423
 
                    r = r.withName(name);
424
 
                response.addRecord(r, section);
425
 
            }
426
 
        }
427
 
    }
428
 
 
429
 
    byte []
430
 
    buildErrorMessage(Header header, int rcode, Record question) {
431
 
        Message response = new Message();
432
 
        response.setHeader(header);
433
 
        for (int i = 0; i < 4; i++)
434
 
            response.removeAllRecords(i);
435
 
        if (rcode == Rcode.SERVFAIL)
436
 
            response.addRecord(question, Section.QUESTION);
437
 
        header.setRcode(rcode);
438
 
        return response.toWire();
439
 
    }
440
 
 
441
 
    public byte []
442
 
    errorMessage(Message query, int rcode) {
443
 
        return buildErrorMessage(query.getHeader(), rcode,
444
 
                query.getQuestion());
445
 
    }
446
 
 
447
 
    public byte []
448
 
    formerrMessage(byte [] in) {
449
 
        Header header;
450
 
        try {
451
 
            header = new Header(in);
452
 
        }
453
 
        catch (IOException e) {
454
 
            return null;
455
 
        }
456
 
        return buildErrorMessage(header, Rcode.FORMERR, null);
457
 
    }
458
 
 
459
 
    public Cache
460
 
    getCache(int dclass) {
461
 
        Cache c = (Cache) caches.get(new Integer(dclass));
462
 
        if (c == null) {
463
 
            c = new Cache(dclass);
464
 
            caches.put(new Integer(dclass), c);
465
 
        }
466
 
        return c;
467
 
    }
 
169
                         */    if (!Type.isRR(type) && type != Type.ANY)
 
170
                                 return errorMessage(query, Rcode.NOTIMP);
 
171
 
 
172
                         byte rcode = addAnswer(response, name, type, dclass, 0, flags);
 
173
                         if (rcode != Rcode.NOERROR && rcode != Rcode.NXDOMAIN)
 
174
                                 return errorMessage(query, rcode);
 
175
 
 
176
                         addAdditional(response, flags);
 
177
 
 
178
                         if (queryOPT != null) {
 
179
                                 int optflags = (flags == FLAG_DNSSECOK) ? ExtendedFlags.DO : 0;
 
180
                                 OPTRecord opt = new OPTRecord((short)4096, rcode, (byte)0,
 
181
                                                 optflags);
 
182
                                 response.addRecord(opt, Section.ADDITIONAL);
 
183
                         }
 
184
                }
 
185
                response.setTSIG(tsig, Rcode.NOERROR, queryTSIG);
 
186
                return response.toWire(maxLength);
 
187
        }
 
188
 
 
189
        public Zone
 
190
        findBestZone(Name name) {
 
191
                Zone foundzone = null;
 
192
                foundzone = (Zone) ZoneManager.getZone(name);
 
193
                if (foundzone != null)
 
194
                        return foundzone;
 
195
                int labels = name.labels();
 
196
                for (int i = 1; i < labels; i++) {
 
197
                        Name tname = new Name(name, i);
 
198
                        foundzone = (Zone) ZoneManager.getZone(tname);
 
199
                        if (foundzone != null)
 
200
                                return foundzone;
 
201
                }
 
202
                return null;
 
203
        }
 
204
 
 
205
        public RRset
 
206
        findExactMatch(Name name, int type, int dclass, boolean glue) {
 
207
                Zone zone = findBestZone(name);
 
208
                if (zone != null)
 
209
                        return zone.findExactMatch(name, type);
 
210
                else {
 
211
                        RRset [] rrsets;
 
212
                        Cache cache = getCache(dclass);
 
213
                        if (glue)
 
214
                                rrsets = cache.findAnyRecords(name, type);
 
215
                        else
 
216
                                rrsets = cache.findRecords(name, type);
 
217
                        if (rrsets == null)
 
218
                                return null;
 
219
                        else
 
220
                                return rrsets[0]; /* not quite right */
 
221
                }
 
222
        }
 
223
 
 
224
        private void
 
225
        addGlue(Message response, Name name, int flags) {
 
226
                RRset a = findExactMatch(name, Type.A, DClass.IN, true);
 
227
                if (a == null)
 
228
                        return;
 
229
                addRRset(name, response, a, Section.ADDITIONAL, flags);
 
230
        }
 
231
 
 
232
        private void
 
233
        addAdditional2(Message response, int section, int flags) {
 
234
                Record [] records = response.getSectionArray(section);
 
235
                for (int i = 0; i < records.length; i++) {
 
236
                        Record r = records[i];
 
237
                        Name glueName = r.getAdditionalName();
 
238
                        if (glueName != null)
 
239
                                addGlue(response, glueName, flags);
 
240
                }
 
241
        }
 
242
 
 
243
        private final void
 
244
        addAdditional(Message response, int flags) {
 
245
                addAdditional2(response, Section.ANSWER, flags);
 
246
                addAdditional2(response, Section.AUTHORITY, flags);
 
247
        }
 
248
 
 
249
        byte
 
250
        addAnswer(Message response, Name name, int type, int dclass,
 
251
                        int iterations, int flags)
 
252
        {
 
253
                SetResponse sr;
 
254
                byte rcode = Rcode.NOERROR;
 
255
 
 
256
                if (iterations > 6)
 
257
                        return Rcode.NOERROR;
 
258
 
 
259
                if (type == Type.SIG || type == Type.RRSIG) {
 
260
                        type = Type.ANY;
 
261
                        flags |= FLAG_SIGONLY;
 
262
                }
 
263
 
 
264
                Zone zone = findBestZone(name);
 
265
                if (zone != null)
 
266
                        sr = zone.findRecords(name, type);
 
267
                else {
 
268
                        Cache cache = getCache(dclass);
 
269
                        sr = cache.lookupRecords(name, type, Credibility.NORMAL);
 
270
                }
 
271
 
 
272
                if (sr.isUnknown()) {
 
273
                        addCacheNS(response, getCache(dclass), name);
 
274
                }
 
275
                if (sr.isNXDOMAIN()) {
 
276
                        response.getHeader().setRcode(Rcode.NXDOMAIN);
 
277
                        if (zone != null) {
 
278
                                addSOA(response, zone);
 
279
                                if (iterations == 0)
 
280
                                        response.getHeader().setFlag(Flags.AA);
 
281
                        }
 
282
                        rcode = Rcode.NXDOMAIN;
 
283
                }
 
284
                else if (sr.isNXRRSET()) {
 
285
                        if (zone != null) {
 
286
                                addSOA(response, zone);
 
287
                                if (iterations == 0)
 
288
                                        response.getHeader().setFlag(Flags.AA);
 
289
                        }
 
290
                }
 
291
                else if (sr.isDelegation()) {
 
292
                        RRset nsRecords = sr.getNS();
 
293
                        addRRset(nsRecords.getName(), response, nsRecords,
 
294
                                        Section.AUTHORITY, flags);
 
295
                }
 
296
                else if (sr.isCNAME()) {
 
297
                        CNAMERecord cname = sr.getCNAME();
 
298
                        RRset rrset = new RRset(cname);
 
299
                        addRRset(name, response, rrset, Section.ANSWER, flags);
 
300
                        if (zone != null && iterations == 0)
 
301
                                response.getHeader().setFlag(Flags.AA);
 
302
                        rcode = addAnswer(response, cname.getTarget(),
 
303
                                        type, dclass, iterations + 1, flags);
 
304
                }
 
305
                else if (sr.isDNAME()) {
 
306
                        DNAMERecord dname = sr.getDNAME();
 
307
                        RRset rrset = new RRset(dname);
 
308
                        addRRset(name, response, rrset, Section.ANSWER, flags);
 
309
                        Name newname;
 
310
                        try {
 
311
                                newname = name.fromDNAME(dname);
 
312
                        }
 
313
                        catch (NameTooLongException e) {
 
314
                                return Rcode.YXDOMAIN;
 
315
                        }
 
316
                        if(newname != null) {
 
317
                                rrset = new RRset(new CNAMERecord(name, dclass, 0, newname));
 
318
                                addRRset(name, response, rrset, Section.ANSWER, flags);
 
319
                                if (zone != null && iterations == 0)
 
320
                                        response.getHeader().setFlag(Flags.AA);
 
321
                                rcode = addAnswer(response, newname, type, dclass,
 
322
                                                iterations + 1, flags);
 
323
                        }
 
324
                }
 
325
                else if (sr.isSuccessful()) {
 
326
                        RRset [] rrsets = sr.answers();
 
327
                        if(rrsets != null) {
 
328
                                for (int i = 0; i < rrsets.length; i++)
 
329
                                        addRRset(name, response, rrsets[i],
 
330
                                                        Section.ANSWER, flags);
 
331
                        }
 
332
                        if (zone != null) {
 
333
                                addNS(response, zone, flags);
 
334
                                if (iterations == 0)
 
335
                                        response.getHeader().setFlag(Flags.AA);
 
336
                        }
 
337
                        else
 
338
                                addCacheNS(response, getCache(dclass), name);
 
339
                }
 
340
                return rcode;
 
341
        }
 
342
 
 
343
 
 
344
        private final void
 
345
        addSOA(Message response, Zone zone) {
 
346
                response.addRecord(zone.getSOA(), Section.AUTHORITY);
 
347
        }
 
348
 
 
349
        private final void
 
350
        addNS(Message response, Zone zone, int flags) {
 
351
                RRset nsRecords = zone.getNS();
 
352
                addRRset(nsRecords.getName(), response, nsRecords,
 
353
                                Section.AUTHORITY, flags);
 
354
        }
 
355
 
 
356
        private final void
 
357
        addCacheNS(Message response, Cache cache, Name name) {
 
358
                SetResponse sr = cache.lookupRecords(name, Type.NS, Credibility.HINT);
 
359
                if (!sr.isDelegation())
 
360
                        return;
 
361
                RRset nsRecords = sr.getNS();
 
362
                Iterator it = nsRecords.rrs();
 
363
                while (it.hasNext()) {
 
364
                        Record r = (Record) it.next();
 
365
                        response.addRecord(r, Section.AUTHORITY);
 
366
                }
 
367
        }
 
368
 
 
369
 
 
370
        byte []
 
371
              doAXFR(Name name, Message query, TSIG tsig, TSIGRecord qtsig, Socket s) {
 
372
                Zone zone = (Zone) ZoneManager.getZone(name);
 
373
                boolean first = true;
 
374
                if (zone == null)
 
375
                        return errorMessage(query, Rcode.REFUSED);
 
376
                Iterator it = zone.AXFR();
 
377
                try {
 
378
                        DataOutputStream dataOut;
 
379
                        dataOut = new DataOutputStream(s.getOutputStream());
 
380
                        int id = query.getHeader().getID();
 
381
                        while (it.hasNext()) {
 
382
                                RRset rrset = (RRset) it.next();
 
383
                                Message response = new Message(id);
 
384
                                Header header = response.getHeader();
 
385
                                header.setFlag(Flags.QR);
 
386
                                header.setFlag(Flags.AA);
 
387
                                addRRset(rrset.getName(), response, rrset,
 
388
                                                Section.ANSWER, FLAG_DNSSECOK);
 
389
                                if (tsig != null) {
 
390
                                        tsig.applyStream(response, qtsig, first);
 
391
                                        qtsig = response.getTSIG();
 
392
                                }
 
393
                                first = false;
 
394
                                byte [] out = response.toWire();
 
395
                                dataOut.writeShort(out.length);
 
396
                                dataOut.write(out);
 
397
                        }
 
398
                }
 
399
                catch (IOException ex) {
 
400
                        System.out.println("AXFR failed");
 
401
                }
 
402
                try {
 
403
                        s.close();
 
404
                }
 
405
                catch (IOException ex) {
 
406
                }
 
407
                return null;
 
408
        }
 
409
 
 
410
        void
 
411
        addRRset(Name name, Message response, RRset rrset, int section, int flags) {
 
412
                for (int s = 1; s <= section; s++)
 
413
                        if (response.findRRset(name, rrset.getType(), s))
 
414
                                return;
 
415
                if ((flags & FLAG_SIGONLY) == 0) {
 
416
                        Iterator it = rrset.rrs();
 
417
                        while (it.hasNext()) {
 
418
                                Record r = (Record) it.next();
 
419
                                if (r.getName().isWild() && !name.isWild())
 
420
                                        r = r.withName(name);
 
421
                                response.addRecord(r, section);
 
422
                        }
 
423
                }
 
424
                if ((flags & (FLAG_SIGONLY | FLAG_DNSSECOK)) != 0) {
 
425
                        Iterator it = rrset.sigs();
 
426
                        while (it.hasNext()) {
 
427
                                Record r = (Record) it.next();
 
428
                                if (r.getName().isWild() && !name.isWild())
 
429
                                        r = r.withName(name);
 
430
                                response.addRecord(r, section);
 
431
                        }
 
432
                }
 
433
        }
 
434
 
 
435
        byte []
 
436
              buildErrorMessage(Header header, int rcode, Record question) {
 
437
                Message response = new Message();
 
438
                response.setHeader(header);
 
439
                for (int i = 0; i < 4; i++)
 
440
                        response.removeAllRecords(i);
 
441
                if (rcode == Rcode.SERVFAIL)
 
442
                        response.addRecord(question, Section.QUESTION);
 
443
                header.setRcode(rcode);
 
444
                return response.toWire();
 
445
        }
 
446
 
 
447
        public byte []
 
448
                     errorMessage(Message query, int rcode) {
 
449
                return buildErrorMessage(query.getHeader(), rcode,
 
450
                                query.getQuestion());
 
451
        }
 
452
 
 
453
        public byte []
 
454
                     formerrMessage(byte [] in) {
 
455
                Header header;
 
456
                try {
 
457
                        header = new Header(in);
 
458
                }
 
459
                catch (IOException e) {
 
460
                        return null;
 
461
                }
 
462
                return buildErrorMessage(header, Rcode.FORMERR, null);
 
463
        }
 
464
 
 
465
        public Cache
 
466
        getCache(int dclass) {
 
467
                Cache c = (Cache) caches.get(new Integer(dclass));
 
468
                if (c == null) {
 
469
                        c = new Cache(dclass);
 
470
                        caches.put(new Integer(dclass), c);
 
471
                }
 
472
                return c;
 
473
        }
468
474
}