DNSQuery.java

back to DNS queries in Java

001 // 
002 // DNSQuery.java
003 // 
004 // DNS query submission wrapper class.
005 // 
006 // Copyright 1997  W. Scott Means (http://smeans.com)
007 //
008 // Licensed under the Apache License, Version 2.0 (the "License");
009 // you may not use this file except in compliance with the License.
010 // You may obtain a copy of the License at
011 //
012 //     http://www.apache.org/licenses/LICENSE-2.0
013 //
014 // Unless required by applicable law or agreed to in writing, software
015 // distributed under the License is distributed on an "AS IS" BASIS,
016 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 //  See the License for the specific language governing permissions and
018 // limitations under the License.
019 //
020 
021 import java.io.DataOutputStream;
022 import java.io.DataInputStream;
023 import java.io.OutputStream;
024 import java.io.IOException;
025 import java.io.ByteArrayInputStream;
026 
027 class DNSQuery 
028 {
029   // DNS constants
030   private final static int MAX_LABEL = 128;
031 
032   // DNS flag values
033   private final static int QR_MASK = 0x8000;
034   private final static int QR_SHIFT = 0;
035 
036   private final static int OPCODE_MASK = 0x7800;
037 
038   private final static int AA_MASK = 0x0400;
039   private final static int TC_MASK = 0x0200;
040   private final static int RD_MASK = 0x0100;
041   private final static int RA_MASK = 0x0080;
042   private final static int ZERO_MASK = 0x0070;
043   private final static int RCODE_MASK = 0x000f;
044 
045   // DNS query/type constants
046   public final static int TYPE_A = 1;
047   public final static int TYPE_NS = 2;
048   public final static int TYPE_MD = 3;
049   public final static int TYPE_MF = 4;
050   public final static int TYPE_CNAME = 5;
051   public final static int TYPE_SOA = 6;
052   public final static int TYPE_MB = 7;
053   public final static int TYPE_MG = 8;
054   public final static int TYPE_MR = 9;
055   public final static int TYPE_NULL = 10;
056   public final static int TYPE_WKS = 11;
057   public final static int TYPE_PTR = 12;
058   public final static int TYPE_HINFO = 13;
059   public final static int TYPE_MINFO = 14;
060   public final static int TYPE_MX = 15;
061   public final static int TYPE_AXFR = 252;
062   public final static int TYPE_ANY = 255;
063 
064   // DNS query classes
065   public final static byte CLASS_INTERNET = 1;
066 
067   // query data members
068   public int m_idQuery = 0x0101;
069   
070   // opcodes
071   public final static int OP_NORM_QRY = 0x0000;
072   public final static int OP_INVERSE_QRY = 0x0800;
073   public final static int OP_SERVER_STAT = 0x1000;
074   public int m_iOpCode = OP_NORM_QRY;
075 
076   // flags
077   public boolean m_fQueryResult = false;
078   public boolean m_fAuthAns = false;
079   public boolean m_fTruncated = false;
080   public boolean m_fRecurse = true;
081   public boolean m_fRecursionAvail = false;
082   
083   private int m_iQryType = TYPE_A;
084   private int m_iQryClass = CLASS_INTERNET;
085   private String m_strQryName = null;
086 
087   // return codes
088   public int m_iRCode = 0;
089   public final static int RCODE_SUCCESS = 0;
090   public final static int RCODE_NAME_ERROR = 0x0003;
091 
092   public int m_cQuestions = 1;
093   public int m_cAnswerRRs = 0;
094   public int m_cAuthRRs = 0;
095   public int m_cInfoRRs = 0;
096 
097   DNSResourceRecord [] m_arrAns;
098   DNSResourceRecord [] m_arrAuth;
099   DNSResourceRecord [] m_arrInfo;
100 
101   public static String GetTypeDesc(int iType) {
102     String str = null;
103     
104     switch (iType) {
105     case TYPE_A: str = new String("TYPE_A")break;
106     case TYPE_NS: str = new String("TYPE_NS")break;
107     case TYPE_CNAME: str = new String("TYPE_CNAME")break;
108     case TYPE_SOA: str = new String("TYPE_SOA")break;
109     case TYPE_PTR: str = new String("TYPE_PTR")break;
110     case TYPE_HINFO: str = new String("TYPE_HINFO")break;
111     case TYPE_MX: str = new String("TYPE_MX")break;
112     case TYPE_AXFR: str = new String("TYPE_AXFR")break;
113     case TYPE_ANY: str = new String("TYPE_ANY")break;
114     defaultstr = new String(Integer.toString(iType))};
115     }
116 
117     return str;
118   }
119 
120   public static String GetClassDesc(int iClass) {
121     String str = null;
122 
123     switch (iClass) {
124     case CLASS_INTERNET: str = new String("CLASS_INTERNET")break;
125     defaultstr = new String()};
126     }
127 
128     return str;
129   }
130 
131   private int BuildFlags() {
132     int iFlags = 0;
133 
134     iFlags |= m_iOpCode;
135 
136     if (m_fRecurse) {
137       iFlags |= RD_MASK;
138     }
139 
140     return iFlags;
141   }
142 
143   private boolean SetFlags(int iFlags) {
144     m_fQueryResult = (iFlags & QR_MASK== QR_MASK;
145     m_fAuthAns = (iFlags & AA_MASK== AA_MASK;
146     m_fTruncated = (iFlags & TC_MASK== TC_MASK;
147     m_fRecurse = (iFlags & RD_MASK== RD_MASK;
148     m_fRecursionAvail = (iFlags & RA_MASK== RA_MASK;
149     m_iRCode = iFlags & RCODE_MASK;
150 
151     return m_iRCode == RCODE_SUCCESS;
152   }
153 
154   public boolean SetQuery(int iType, int iClass, String strName) {
155     m_iQryType = iType;
156     m_iQryClass = iClass;
157     m_cQuestions = 1;
158     m_strQryName = new String(strName);
159 
160     return true;
161   }
162 
163   private boolean WriteFQDN(DataOutputStream dos, String strName) {
164     try {
165       int iPos = 0;
166       int iSep = 0;
167 
168       while ((iSep = strName.indexOf('.', iPos)) >= 0) {
169         dos.writeByte((byte)(iSep - iPos));
170         dos.writeBytes(strName.substring(iPos, iSep));
171         iPos = iSep + 1;
172       }
173 
174       if (iPos < strName.length()) {
175         dos.writeByte((byte)(strName.length() - iPos));
176         dos.writeBytes(strName.substring(iPos));
177       }
178       
179       // terminator
180       dos.writeByte(0);
181 
182       return true;
183     catch (IOException ioe) {
184       return false;
185     }
186   }
187   
188   public static String ReadLabelList(DataInputStream dis, byte [] abData) {
189     int cb;
190      byte [] ab = new byte[MAX_LABEL];
191     String str = new String();
192     String strNext = new String();
193 
194     try {
195       while ((cb = dis.readUnsignedByte()) 0) {
196         if ((cb & 0xc0== 0xc0) {
197           int iReadOff = (int)(cb & ~0xc0<< 8;
198 
199           cb = dis.readUnsignedByte();
200           iReadOff += (int)cb;
201           
202           while (iReadOff < abData.length && ((cb = abData[iReadOff++]) 0)) {
203             if ((cb & 0xc0== 0xc0) {
204               return str;
205             }
206 
207             strNext = new String(abData, 0, iReadOff, cb);
208 
209             if (str.length() 0) {
210               str += "." + strNext;
211             else {
212               str = strNext;
213             }
214 
215             iReadOff += cb;
216           }
217 
218           return str;
219         else {
220           byte [] abNext = new byte[cb];
221 
222           if (dis.read(abNext< cb) {
223             return new String();
224           }
225           
226           strNext = new String(abNext, 00, cb);
227         }
228 
229         if (str.length() 0) {
230           str += "." + strNext;
231         else {
232           str = strNext;
233         }
234       }
235     catch (IOException ioe) {
236       System.err.println("exception: " + ioe.getMessage());
237     }
238   
239     return str;
240   }
241 
242   public boolean WriteQuery(OutputStream os) {
243     try {
244       if (m_strQryName == null) {
245         return false;
246       }
247 
248       DataOutputStream dos = new DataOutputStream(os);
249 
250       // query sequence ID
251       dos.writeShort(m_idQuery);
252 
253       // query flags
254       dos.writeShort(BuildFlags());
255 
256       // question count
257       dos.writeShort(1);
258 
259       // answer count
260       dos.writeShort(0);
261 
262       // authority count
263       dos.writeShort(0);
264 
265       // additional info count
266       dos.writeShort(0);
267 
268       // write query name
269       WriteFQDN(dos, m_strQryName);
270 
271       // query type
272       dos.writeShort(m_iQryType);
273 
274       // query class
275       dos.writeShort(m_iQryClass);
276 
277       return true;
278     catch (IOException ioe) {  
279       return false;
280     }
281   }
282 
283   private void SortRRs(DNSResourceRecord [] arr, boolean fDescending) {
284     if (arr == null || arr.length < 2) {
285       return;
286     }
287 
288     boolean fSwapped;
289     DNSResourceRecord rrSwap;
290 
291     do {
292       fSwapped = false;
293       
294       for (int i = 0; i < arr.length - 1; i++) {
295         boolean fSwap = false;
296 
297         if (arr[i+1].m_iType < arr[i].m_iType) {  
298           fSwap = true;
299         else if (arr[i+1].m_iType == arr[i].m_iType) {
300           switch (arr[i].m_iType) {
301           case TYPE_MX: {
302             fSwap = arr[i+1].m_lData < arr[i].m_lData;
303           break;
304           }
305         }
306 
307         if (fSwap = fSwap ^ fDescending) {
308           rrSwap = arr[i];
309           arr[i= arr[i+1];
310           arr[i+1= rrSwap;
311           fSwapped = true;
312         }
313       }
314     while (fSwapped);
315   }
316 
317   public boolean ReadQuery(byte [] abData, int cbData) {
318     try {
319       ByteArrayInputStream is = new ByteArrayInputStream(abData, 0, cbData);
320 
321       DataInputStream dis = new DataInputStream(is);
322 
323       // query sequence ID
324       m_idQuery = dis.readShort();
325 
326       // query flags
327       if (!SetFlags(dis.readShort())) {
328         return false;
329       }
330 
331       // question count
332       m_cQuestions = dis.readShort();
333 
334       // answer count
335       m_cAnswerRRs = dis.readShort();
336 
337       // authority count
338       m_cAuthRRs = dis.readShort();
339 
340       // additional info count
341       m_cInfoRRs = dis.readShort();
342 
343       // read query name
344       m_strQryName = ReadLabelList(dis, abData);
345 
346       // query type
347       m_iQryType = dis.readShort();
348 
349       // query class
350       m_iQryClass = dis.readShort();
351 
352       m_arrAns = new DNSResourceRecord[m_cAnswerRRs];
353 
354       for (int i = 0; i < m_cAnswerRRs; i++) {
355         m_arrAns[inew DNSResourceRecord();
356 
357         if (!m_arrAns[i].readRecord(dis, abData)) {
358           return false;
359         }
360       }
361 
362       SortRRs(m_arrAns, false);
363 
364       if (m_cAuthRRs > 0) {
365         m_arrAuth = new DNSResourceRecord[m_cAuthRRs];
366 
367         for (int i = 0; i < m_cAuthRRs; i++) {
368           m_arrAuth[inew DNSResourceRecord();
369 
370           if (!m_arrAuth[i].readRecord(dis, abData)) {
371             return false;
372           }
373         }
374 
375         SortRRs(m_arrAuth, false);
376       else {
377         m_arrAuth = null;
378       }
379 
380       if (m_cInfoRRs > 0) {
381         m_arrInfo = new DNSResourceRecord[m_cInfoRRs];
382 
383         for (int i = 0; i < m_cInfoRRs; i++) {
384           m_arrInfo[inew DNSResourceRecord();
385 
386           if (!m_arrInfo[i].readRecord(dis, abData)) {
387             return false;
388           }
389         }
390 
391         SortRRs(m_arrInfo, false);
392       else {
393         m_arrInfo = null;
394       }
395 
396     catch (IOException ioe) {
397       System.err.println("exception: " + ioe.getMessage());
398       
399       return false;
400     }
401 
402     return true;
403   }
404 }
Java2html

Comments are closed.