4 * Copyright (c) 2005 VeriSign. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer. 2. Redistributions in
11 * binary form must reproduce the above copyright notice, this list of
12 * conditions and the following disclaimer in the documentation and/or other
13 * materials provided with the distribution. 3. The name of the author may not
14 * be used to endorse or promote products derived from this software without
15 * specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
20 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 package com.versign.tat.dnssec;
34 import org.xbill.DNS.*;
37 * This class represents a DNS message with resolver/validator state.
41 private Header mHeader;
43 private Record mQuestion;
44 private OPTRecord mOPTRecord;
45 private List[] mSection;
46 private SecurityStatus mSecurityStatus;
48 private static SRRset[] empty_srrset_array = new SRRset[0];
50 public SMessage(Header h)
52 mSection = new List[3];
54 mSecurityStatus = new SecurityStatus();
57 public SMessage(int id)
67 public SMessage(Message m)
70 mQuestion = m.getQuestion();
71 mOPTRecord = m.getOPT();
73 for (int i = Section.ANSWER; i <= Section.ADDITIONAL; i++)
75 RRset[] rrsets = m.getSectionRRsets(i);
77 for (int j = 0; j < rrsets.length; j++)
79 addRRset(rrsets[j], i);
84 public Header getHeader()
89 public void setHeader(Header h)
94 public void setQuestion(Record r)
99 public Record getQuestion()
104 public Name getQName() {
105 return getQuestion().getName();
108 public int getQType() {
109 return getQuestion().getType();
112 public int getQClass() {
113 return getQuestion().getDClass();
116 public void setOPT(OPTRecord r)
121 public OPTRecord getOPT()
126 public List getSectionList(int section)
128 if (section <= Section.QUESTION || section > Section.ADDITIONAL)
129 throw new IllegalArgumentException("Invalid section.");
131 if (mSection[section - 1] == null)
133 mSection[section - 1] = new LinkedList();
136 return mSection[section - 1];
139 public void addRRset(SRRset srrset, int section)
141 if (section <= Section.QUESTION || section > Section.ADDITIONAL)
142 throw new IllegalArgumentException("Invalid section");
144 if (srrset.getType() == Type.OPT)
146 mOPTRecord = (OPTRecord) srrset.first();
150 List sectionList = getSectionList(section);
151 sectionList.add(srrset);
154 public void addRRset(RRset rrset, int section)
156 if (rrset instanceof SRRset)
158 addRRset((SRRset) rrset, section);
162 SRRset srrset = new SRRset(rrset);
163 addRRset(srrset, section);
166 public void prependRRsets(List rrsets, int section)
168 if (section <= Section.QUESTION || section > Section.ADDITIONAL)
169 throw new IllegalArgumentException("Invalid section");
171 List sectionList = getSectionList(section);
172 sectionList.addAll(0, rrsets);
175 public SRRset[] getSectionRRsets(int section)
177 List slist = getSectionList(section);
179 return (SRRset[]) slist.toArray(empty_srrset_array);
182 public SRRset[] getSectionRRsets(int section, int qtype)
184 List slist = getSectionList(section);
186 if (slist.size() == 0) return new SRRset[0];
188 ArrayList result = new ArrayList(slist.size());
189 for (Iterator i = slist.iterator(); i.hasNext();)
191 SRRset rrset = (SRRset) i.next();
192 if (rrset.getType() == qtype) result.add(rrset);
195 return (SRRset[]) result.toArray(empty_srrset_array);
198 public void deleteRRset(SRRset rrset, int section)
200 List slist = getSectionList(section);
202 if (slist.size() == 0) return;
207 public void clear(int section)
209 if (section < Section.QUESTION || section > Section.ADDITIONAL)
210 throw new IllegalArgumentException("Invalid section.");
212 if (section == Section.QUESTION)
217 if (section == Section.ADDITIONAL)
222 mSection[section - 1] = null;
227 for (int s = Section.QUESTION; s <= Section.ADDITIONAL; s++)
233 public int getRcode()
235 // FIXME: might want to do what Message does and handle extended rcodes.
236 return mHeader.getRcode();
239 public int getStatus()
241 return mSecurityStatus.getStatus();
244 public void setStatus(byte status)
246 mSecurityStatus.setStatus(status);
249 public SecurityStatus getSecurityStatus()
251 return mSecurityStatus;
253 public void setSecurityStatus(SecurityStatus s)
255 if (s == null) return;
259 public Message getMessage()
261 // Generate our new message.
262 Message m = new Message(mHeader.getID());
264 // Convert the header
265 // We do this for two reasons: 1) setCount() is package scope, so we can't
266 // do that, and 2) setting the header on a message after creating the
267 // message frequently gets stuff out of sync, leading to malformed wire
269 Header h = m.getHeader();
270 h.setOpcode(mHeader.getOpcode());
271 h.setRcode(mHeader.getRcode());
272 for (int i = 0; i < 16; i++)
274 if (Flags.isFlag(i)) {
275 if (mHeader.getFlag(i)) {
283 // Add all the records. -- this will set the counts correctly in the
286 if (mQuestion != null)
288 m.addRecord(mQuestion, Section.QUESTION);
291 for (int sec = Section.ANSWER; sec <= Section.ADDITIONAL; sec++)
293 List slist = getSectionList(sec);
294 for (Iterator i = slist.iterator(); i.hasNext();)
296 SRRset rrset = (SRRset) i.next();
297 for (Iterator j = rrset.rrs(); j.hasNext();)
299 m.addRecord((Record) j.next(), sec);
301 for (Iterator j = rrset.sigs(); j.hasNext();)
303 m.addRecord((Record) j.next(), sec);
308 if (mOPTRecord != null)
310 m.addRecord(mOPTRecord, Section.ADDITIONAL);
316 public int getCount(int section)
318 if (section == Section.QUESTION)
320 return mQuestion == null ? 0 : 1;
322 List sectionList = getSectionList(section);
323 if (sectionList == null) return 0;
324 if (sectionList.size() == 0) return 0;
327 for (Iterator i = sectionList.iterator(); i.hasNext(); )
329 SRRset sr = (SRRset) i.next();
330 count += sr.totalSize();
335 public String toString()
337 return getMessage().toString();
341 * Find a specific (S)RRset in a given section.
343 * @param name the name of the RRset.
344 * @param type the type of the RRset.
345 * @param dclass the class of the RRset.
346 * @param section the section to look in (ANSWER -> ADDITIONAL)
348 * @return The SRRset if found, null otherwise.
350 public SRRset findRRset(Name name, int type, int dclass, int section)
352 if (section <= Section.QUESTION || section > Section.ADDITIONAL)
353 throw new IllegalArgumentException("Invalid section.");
355 SRRset[] rrsets = getSectionRRsets(section);
357 for (int i = 0; i < rrsets.length; i++)
359 if (rrsets[i].getName().equals(name) && rrsets[i].getType() == type
360 && rrsets[i].getDClass() == dclass)
370 * Find an "answer" RRset. This will look for RRsets in the ANSWER section
371 * that match the <qname,qtype,qclass>, taking into consideration CNAMEs.
373 * @param qname The starting search name.
374 * @param qtype The search type.
375 * @param qclass The search class.
377 * @return a SRRset matching the query. This SRRset may have a different
378 * name from qname, due to following a CNAME chain.
380 public SRRset findAnswerRRset(Name qname, int qtype, int qclass)
382 SRRset[] srrsets = getSectionRRsets(Section.ANSWER);
384 for (int i = 0; i < srrsets.length; i++)
386 if (srrsets[i].getName().equals(qname)
387 && srrsets[i].getType() == Type.CNAME)
389 CNAMERecord cname = (CNAMERecord) srrsets[i].first();
390 qname = cname.getTarget();
394 if (srrsets[i].getName().equals(qname) && srrsets[i].getType() == qtype
395 && srrsets[i].getDClass() == qclass)