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 default: { str = 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 default: { str = 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, 0, 0, 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[i] = new 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[i] = new 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[i] = new 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
|