1 /***************************** -*- Java -*- ********************************\
3 * Copyright (c) 2009 VeriSign, Inc. All rights reserved. *
5 * This software is provided solely in connection with the terms of the *
6 * license agreement. Any other use without the prior express written *
7 * permission of VeriSign is completely prohibited. The software and *
8 * documentation are "Commercial Items", as that term is defined in 48 *
9 * C.F.R. section 2.101, consisting of "Commercial Computer Software" and *
10 * "Commercial Computer Software Documentation" as such terms are defined *
11 * in 48 C.F.R. section 252.227-7014(a)(5) and 48 C.F.R. section *
12 * 252.227-7014(a)(1), and used in 48 C.F.R. section 12.212 and 48 C.F.R. *
13 * section 227.7202, as applicable. Pursuant to the above and other *
14 * relevant sections of the Code of Federal Regulations, as applicable, *
15 * VeriSign's publications, commercial computer software, and commercial *
16 * computer software documentation are distributed and licensed to United *
17 * States Government end users with only those rights as granted to all *
18 * other end users, according to the terms and conditions contained in the *
19 * license agreement(s) that accompany the products and software *
22 \***************************************************************************/
24 package com.verisign.tat.dnssec;
26 import org.xbill.DNS.*;
32 * This class represents a DNS message with resolver/validator state.
34 public class SMessage {
35 private static SRRset [] empty_srrset_array = new SRRset[0];
36 private Header mHeader;
37 private Record mQuestion;
38 private OPTRecord mOPTRecord;
39 private List<SRRset> [] mSection;
40 private SecurityStatus mSecurityStatus;
42 @SuppressWarnings("unchecked")
43 public SMessage(Header h) {
44 mSection = (List<SRRset> []) new List[3];
46 mSecurityStatus = new SecurityStatus();
49 public SMessage(int id) {
57 public SMessage(Message m) {
59 mQuestion = m.getQuestion();
60 mOPTRecord = m.getOPT();
62 for (int i = Section.ANSWER; i <= Section.ADDITIONAL; i++) {
63 RRset [] rrsets = m.getSectionRRsets(i);
65 for (int j = 0; j < rrsets.length; j++) {
66 addRRset(rrsets[j], i);
71 public Header getHeader() {
75 public void setHeader(Header h) {
79 public void setQuestion(Record r) {
83 public Record getQuestion() {
87 public Name getQName() {
88 return getQuestion().getName();
91 public int getQType() {
92 return getQuestion().getType();
95 public int getQClass() {
96 return getQuestion().getDClass();
99 public void setOPT(OPTRecord r) {
103 public OPTRecord getOPT() {
107 public List<SRRset> getSectionList(int section) {
108 if ((section <= Section.QUESTION) || (section > Section.ADDITIONAL)) {
109 throw new IllegalArgumentException("Invalid section.");
112 if (mSection[section - 1] == null) {
113 mSection[section - 1] = new LinkedList<SRRset>();
116 return (List<SRRset>) mSection[section - 1];
119 public void addRRset(SRRset srrset, int section) {
120 if ((section <= Section.QUESTION) || (section > Section.ADDITIONAL)) {
121 throw new IllegalArgumentException("Invalid section");
124 if (srrset.getType() == Type.OPT) {
125 mOPTRecord = (OPTRecord) srrset.first();
130 List<SRRset> sectionList = getSectionList(section);
131 sectionList.add(srrset);
134 public void addRRset(RRset rrset, int section) {
135 if (rrset instanceof SRRset) {
136 addRRset((SRRset) rrset, section);
141 SRRset srrset = new SRRset(rrset);
142 addRRset(srrset, section);
145 public void prependRRsets(List<SRRset> rrsets, int section) {
146 if ((section <= Section.QUESTION) || (section > Section.ADDITIONAL)) {
147 throw new IllegalArgumentException("Invalid section");
150 List<SRRset> sectionList = getSectionList(section);
151 sectionList.addAll(0, rrsets);
154 public SRRset [] getSectionRRsets(int section) {
155 List<SRRset> slist = getSectionList(section);
157 return (SRRset []) slist.toArray(empty_srrset_array);
160 public SRRset [] getSectionRRsets(int section, int qtype) {
161 List<SRRset> slist = getSectionList(section);
163 if (slist.size() == 0) {
164 return new SRRset[0];
167 ArrayList<SRRset> result = new ArrayList<SRRset>(slist.size());
169 for (SRRset rrset : slist) {
170 if (rrset.getType() == qtype) {
175 return (SRRset []) result.toArray(empty_srrset_array);
178 public void deleteRRset(SRRset rrset, int section) {
179 List<SRRset> slist = getSectionList(section);
181 if (slist.size() == 0) {
188 public void clear(int section) {
189 if ((section < Section.QUESTION) || (section > Section.ADDITIONAL)) {
190 throw new IllegalArgumentException("Invalid section.");
193 if (section == Section.QUESTION) {
199 if (section == Section.ADDITIONAL) {
203 mSection[section - 1] = null;
206 public void clear() {
207 for (int s = Section.QUESTION; s <= Section.ADDITIONAL; s++) {
212 public int getRcode() {
213 // FIXME: might want to do what Message does and handle extended rcodes.
214 return mHeader.getRcode();
217 public int getStatus() {
218 return mSecurityStatus.getStatus();
221 public void setStatus(byte status) {
222 mSecurityStatus.setStatus(status);
225 public SecurityStatus getSecurityStatus() {
226 return mSecurityStatus;
229 public void setSecurityStatus(SecurityStatus s) {
237 public Message getMessage() {
238 // Generate our new message.
239 Message m = new Message(mHeader.getID());
241 // Convert the header
242 // We do this for two reasons: 1) setCount() is package scope, so we
243 // can't do that, and 2) setting the header on a message after creating
244 // the message frequently gets stuff out of sync, leading to malformed
245 // wire format messages.
246 Header h = m.getHeader();
247 h.setOpcode(mHeader.getOpcode());
248 h.setRcode(mHeader.getRcode());
250 for (int i = 0; i < 16; i++) {
251 if (Flags.isFlag(i)) {
252 if (mHeader.getFlag(i)) {
260 // Add all the records. -- this will set the counts correctly in the
262 if (mQuestion != null) {
263 m.addRecord(mQuestion, Section.QUESTION);
266 for (int sec = Section.ANSWER; sec <= Section.ADDITIONAL; sec++) {
267 List<SRRset> slist = getSectionList(sec);
269 for (SRRset rrset : slist) {
270 for (Iterator<Record> j = rrset.rrs(); j.hasNext();) {
271 m.addRecord(j.next(), sec);
274 for (Iterator<RRSIGRecord> j = rrset.sigs(); j.hasNext();) {
275 m.addRecord(j.next(), sec);
280 if (mOPTRecord != null) {
281 m.addRecord(mOPTRecord, Section.ADDITIONAL);
287 public int getCount(int section) {
288 if (section == Section.QUESTION) {
289 return (mQuestion == null) ? 0 : 1;
292 List<SRRset> sectionList = getSectionList(section);
294 if (sectionList == null) {
298 if (sectionList.size() == 0) {
304 for (SRRset sr : sectionList) {
305 count += sr.totalSize();
311 public String toString() {
312 return getMessage().toString();
316 * Find a specific (S)RRset in a given section.
319 * the name of the RRset.
321 * the type of the RRset.
323 * the class of the RRset.
325 * the section to look in (ANSWER -> ADDITIONAL)
327 * @return The SRRset if found, null otherwise.
329 public SRRset findRRset(Name name, int type, int dclass, int section) {
330 if ((section <= Section.QUESTION) || (section > Section.ADDITIONAL)) {
331 throw new IllegalArgumentException("Invalid section.");
334 SRRset [] rrsets = getSectionRRsets(section);
336 for (int i = 0; i < rrsets.length; i++) {
337 if (rrsets[i].getName().equals(name) &&
338 (rrsets[i].getType() == type) &&
339 (rrsets[i].getDClass() == dclass)) {
348 * Find an "answer" RRset. This will look for RRsets in the ANSWER section
349 * that match the <qname,qtype,qclass>, taking into consideration CNAMEs.
352 * The starting search name.
358 * @return a SRRset matching the query. This SRRset may have a different
359 * name from qname, due to following a CNAME chain.
361 public SRRset findAnswerRRset(Name qname, int qtype, int qclass) {
362 SRRset [] srrsets = getSectionRRsets(Section.ANSWER);
364 for (int i = 0; i < srrsets.length; i++) {
365 if (srrsets[i].getName().equals(qname) &&
366 (srrsets[i].getType() == Type.CNAME)) {
367 CNAMERecord cname = (CNAMERecord) srrsets[i].first();
368 qname = cname.getTarget();
373 if (srrsets[i].getName().equals(qname) &&
374 (srrsets[i].getType() == qtype) &&
375 (srrsets[i].getDClass() == qclass)) {