Source code: com/act365/net/dns/DNSReader.java
1 /*
2 * JSocket Wrench
3 *
4 * Copyright (C) act365.com October 2003
5 *
6 * Web site: http://www.act365.com/wrench
7 * E-mail: developers@act365.com
8 *
9 * The JSocket Wrench library adds support for low-level Internet protocols
10 * to the Java programming language.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 2 of the License, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
20 * Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * this program; if not, write to the Free Software Foundation, Inc.,
24 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27 package com.act365.net.dns ;
28
29 import com.act365.net.*;
30
31 /**
32 * Reads DNS messages from bytestreams.
33 */
34
35 public class DNSReader {
36
37 int headerLength ;
38
39 /**
40 Constructs a parser to decode DNS bytestreams.
41 @param headerLength length of the transport header, e.g. 8 for UDP or 20 for TCP
42 */
43
44 public DNSReader( int headerLength ){
45 this.headerLength = headerLength ;
46 }
47
48 /**
49 Extracts a domain name string from a DNS message, even if compressed.
50 */
51
52 int domainName( byte[] buffer , int offset , StringBuffer name ) throws Exception {
53
54 final int start = offset ;
55
56 byte next = buffer[ offset ++ ];
57
58 int inext = next >= 0 ? next : 0xffffff00 ^ next ;
59
60 while( inext != 0x00 ){
61 if( inext >>> 6 == 0x03 ){
62 StringBuffer compressed = new StringBuffer();
63 int compressed_offset = ( inext & 0x3F ) << 8 ;
64 next = buffer[ offset ++ ];
65 inext = next >= 0 ? next : 0xffffff00 ^ next ;
66 compressed_offset |= inext ;
67 domainName( buffer , compressed_offset + headerLength , compressed );
68 name.append( compressed.toString() );
69 break;
70 } else {
71 name.append( new String( buffer , offset , inext , "UTF8" ) );
72 offset += inext ;
73 }
74 next = buffer[ offset ++ ];
75 inext = next >= 0 ? next : 0xffffff00 ^ next ;
76 if( inext > 0 ){
77 name.append('.');
78 }
79 }
80
81 return offset - start ;
82 }
83
84 /**
85 Converts the data in a ResourceRecord object into an appropriate string.
86 */
87
88 String dataString( byte[] buffer , int offset , int count , short type ) throws Exception {
89
90 StringBuffer name = new StringBuffer();
91
92 final int start = offset ;
93
94 switch( type ){
95
96 case DNSMessage.A :
97
98 while( offset < start + count ){
99 int datum = buffer[ offset ];
100 name.append( datum >= 0 ? datum : 0xffffff00 ^ datum );
101 if( offset ++ < start + count - 1 ){
102 name.append('.');
103 }
104 }
105
106 break;
107
108 case DNSMessage.NS :
109 case DNSMessage.CNAME :
110 case DNSMessage.PTR :
111
112 domainName( buffer , offset , name );
113
114 break;
115
116 default:
117
118 }
119
120 return name.toString();
121 }
122
123 /**
124 Reads all of the information from a DNS response.
125 */
126
127 public DNSMessage read( byte[] buffer ) throws Exception {
128
129 DNSMessage message = new DNSMessage();
130
131 message.identification = SocketUtils.shortFromBytes( buffer , headerLength );
132 message.flags = SocketUtils.shortFromBytes( buffer , headerLength + 2 );
133
134 short n_questions = SocketUtils.shortFromBytes( buffer , headerLength + 4 ) ,
135 n_answers = SocketUtils.shortFromBytes( buffer , headerLength + 6 ) ,
136 n_authority = SocketUtils.shortFromBytes( buffer , headerLength + 8 ) ,
137 n_additional = SocketUtils.shortFromBytes( buffer , headerLength + 10 );
138
139 message.questions = new Query[ n_questions ];
140 message.answers = new ResourceRecord[ n_answers ];
141 message.authority_records = new ResourceRecord[ n_authority ];
142 message.additional_records = new ResourceRecord[ n_additional ];
143
144 int i = -1 , j , offset = headerLength + 12 ;
145
146 StringBuffer name ;
147
148 String datastring ;
149
150 byte[] namebuffer , databuffer ;
151
152 short type_value , class_value , data_length ;
153
154 int time_to_live ;
155
156 while( ++ i < n_questions ){
157 name = new StringBuffer();
158 offset += domainName( buffer , offset , name );
159 namebuffer = name.toString().getBytes("UTF8");
160 type_value = SocketUtils.shortFromBytes( buffer , offset );
161 offset += 2 ;
162 class_value = SocketUtils.shortFromBytes( buffer , offset );
163 offset += 2 ;
164
165 message.questions[ i ] = new Query( namebuffer , type_value , class_value , name.toString() );
166 }
167
168 i = -1 ;
169
170 while( ++ i < n_answers ){
171 name = new StringBuffer();
172 offset += domainName( buffer , offset , name );
173 namebuffer = name.toString().getBytes("UTF8");
174 type_value = SocketUtils.shortFromBytes( buffer , offset );
175 offset += 2 ;
176 class_value = SocketUtils.shortFromBytes( buffer , offset );
177 offset += 2 ;
178 time_to_live = SocketUtils.intFromBytes( buffer , offset );
179 offset += 4 ;
180 data_length = SocketUtils.shortFromBytes( buffer , offset );
181 offset += 2 ;
182 datastring = dataString( buffer , offset , data_length , type_value );
183 databuffer = new byte[ data_length ];
184 j = -1 ;
185 while( ++ j < data_length ){
186 databuffer[ j ] = buffer[ offset ++ ];
187 }
188
189 message.answers[ i ] = new ResourceRecord( namebuffer ,
190 type_value ,
191 class_value ,
192 time_to_live ,
193 databuffer ,
194 datastring );
195 }
196
197 i = -1 ;
198
199 while( ++ i < n_authority ){
200 name = new StringBuffer();
201 offset += domainName( buffer , offset , name );
202 namebuffer = name.toString().getBytes("UTF8");
203 type_value = SocketUtils.shortFromBytes( buffer , offset );
204 offset += 2 ;
205 class_value = SocketUtils.shortFromBytes( buffer , offset );
206 offset += 2 ;
207 time_to_live = SocketUtils.intFromBytes( buffer , offset );
208 offset += 4 ;
209 data_length = SocketUtils.shortFromBytes( buffer , offset );
210 offset += 2 ;
211 datastring = dataString( buffer , offset , data_length , type_value );
212 databuffer = new byte[ data_length ];
213 j = -1 ;
214 while( ++ j < data_length ){
215 databuffer[ j ] = buffer[ offset ++ ];
216 }
217
218 message.authority_records[ i ] = new ResourceRecord( namebuffer ,
219 type_value ,
220 class_value ,
221 time_to_live ,
222 databuffer ,
223 datastring );
224 }
225
226 i = -1 ;
227
228 while( ++ i < n_additional ){
229 name = new StringBuffer();
230 offset += domainName( buffer , offset , name );
231 namebuffer = name.toString().getBytes("UTF8");
232 type_value = SocketUtils.shortFromBytes( buffer , offset );
233 offset += 2 ;
234 class_value = SocketUtils.shortFromBytes( buffer , offset );
235 offset += 2 ;
236 time_to_live = SocketUtils.intFromBytes( buffer , offset );
237 offset += 4 ;
238 data_length = SocketUtils.shortFromBytes( buffer , offset );
239 offset += 2 ;
240 datastring = dataString( buffer , offset , data_length , type_value );
241 databuffer = new byte[ data_length ];
242 j = -1 ;
243 while( ++ j < data_length ){
244 databuffer[ j ] = buffer[ offset ++ ];
245 }
246
247 message.additional_records[ i ] = new ResourceRecord( namebuffer ,
248 type_value ,
249 class_value ,
250 time_to_live ,
251 databuffer ,
252 datastring );
253 }
254
255 return message ;
256 }
257 }
258
259