1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.directory.server.dns.io.encoder;
22
23
24 import java.io.IOException;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30
31 import org.apache.directory.server.dns.messages.DnsMessage;
32 import org.apache.directory.server.dns.messages.MessageType;
33 import org.apache.directory.server.dns.messages.OpCode;
34 import org.apache.directory.server.dns.messages.QuestionRecord;
35 import org.apache.directory.server.dns.messages.RecordType;
36 import org.apache.directory.server.dns.messages.ResourceRecord;
37 import org.apache.directory.server.dns.messages.ResponseCode;
38 import org.apache.mina.common.ByteBuffer;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42
43
44
45
46
47
48
49
50
51
52 public class DnsMessageEncoder
53 {
54
55 private static final Logger log = LoggerFactory.getLogger( DnsMessageEncoder.class );
56
57
58
59
60 private static final Map<RecordType, RecordEncoder> DEFAULT_ENCODERS;
61
62 static
63 {
64 Map<RecordType, RecordEncoder> map = new HashMap<RecordType, RecordEncoder>();
65
66 map.put( RecordType.SOA, new StartOfAuthorityRecordEncoder() );
67 map.put( RecordType.A, new AddressRecordEncoder() );
68 map.put( RecordType.NS, new NameServerRecordEncoder() );
69 map.put( RecordType.CNAME, new CanonicalNameRecordEncoder() );
70 map.put( RecordType.PTR, new PointerRecordEncoder() );
71 map.put( RecordType.MX, new MailExchangeRecordEncoder() );
72 map.put( RecordType.SRV, new ServerSelectionRecordEncoder() );
73 map.put( RecordType.TXT, new TextRecordEncoder() );
74
75 DEFAULT_ENCODERS = Collections.unmodifiableMap( map );
76 }
77
78
79
80
81
82
83
84
85 public void encode( ByteBuffer byteBuffer, DnsMessage message )
86 {
87 byteBuffer.putShort( ( short ) message.getTransactionId() );
88
89 byte header = ( byte ) 0x00;
90 header |= encodeMessageType( message.getMessageType() );
91 header |= encodeOpCode( message.getOpCode() );
92 header |= encodeAuthoritativeAnswer( message.isAuthoritativeAnswer() );
93 header |= encodeTruncated( message.isTruncated() );
94 header |= encodeRecursionDesired( message.isRecursionDesired() );
95 byteBuffer.put( header );
96
97 header = ( byte ) 0x00;
98 header |= encodeRecursionAvailable( message.isRecursionAvailable() );
99 header |= encodeResponseCode( message.getResponseCode() );
100 byteBuffer.put( header );
101
102 byteBuffer
103 .putShort( ( short ) ( message.getQuestionRecords() != null ? message.getQuestionRecords().size() : 0 ) );
104 byteBuffer.putShort( ( short ) ( message.getAnswerRecords() != null ? message.getAnswerRecords().size() : 0 ) );
105 byteBuffer.putShort( ( short ) ( message.getAuthorityRecords() != null ? message.getAuthorityRecords().size()
106 : 0 ) );
107 byteBuffer.putShort( ( short ) ( message.getAdditionalRecords() != null ? message.getAdditionalRecords().size()
108 : 0 ) );
109
110 putQuestionRecords( byteBuffer, message.getQuestionRecords() );
111 putResourceRecords( byteBuffer, message.getAnswerRecords() );
112 putResourceRecords( byteBuffer, message.getAuthorityRecords() );
113 putResourceRecords( byteBuffer, message.getAdditionalRecords() );
114 }
115
116
117 private void putQuestionRecords( ByteBuffer byteBuffer, List<QuestionRecord> questions )
118 {
119 if ( questions == null )
120 {
121 return;
122 }
123
124 QuestionRecordEncoder encoder = new QuestionRecordEncoder();
125
126 Iterator<QuestionRecord> it = questions.iterator();
127
128 while ( it.hasNext() )
129 {
130 QuestionRecord question = it.next();
131 encoder.put( byteBuffer, question );
132 }
133 }
134
135
136 private void putResourceRecords( ByteBuffer byteBuffer, List<ResourceRecord> records )
137 {
138 if ( records == null )
139 {
140 return;
141 }
142
143 Iterator<ResourceRecord> it = records.iterator();
144
145 while ( it.hasNext() )
146 {
147 ResourceRecord record = it.next();
148
149 try
150 {
151 put( byteBuffer, record );
152 }
153 catch ( IOException ioe )
154 {
155 log.error( ioe.getMessage(), ioe );
156 }
157 }
158 }
159
160
161 private void put( ByteBuffer byteBuffer, ResourceRecord record ) throws IOException
162 {
163 RecordType type = record.getRecordType();
164
165 RecordEncoder encoder = DEFAULT_ENCODERS.get( type );
166
167 if ( encoder == null )
168 {
169 throw new IOException( "Encoder unavailable for " + type );
170 }
171
172 encoder.put( byteBuffer, record );
173 }
174
175
176 private byte encodeMessageType( MessageType messageType )
177 {
178 byte oneBit = ( byte ) ( messageType.convert() & 0x01 );
179 return ( byte ) ( oneBit << 7 );
180 }
181
182
183 private byte encodeOpCode( OpCode opCode )
184 {
185 byte fourBits = ( byte ) ( opCode.convert() & 0x0F );
186 return ( byte ) ( fourBits << 3 );
187 }
188
189
190 private byte encodeAuthoritativeAnswer( boolean authoritative )
191 {
192 if ( authoritative )
193 {
194 return ( byte ) ( ( byte ) 0x01 << 2 );
195 }
196 return ( byte ) 0;
197 }
198
199
200 private byte encodeTruncated( boolean truncated )
201 {
202 if ( truncated )
203 {
204 return ( byte ) ( ( byte ) 0x01 << 1 );
205 }
206 return 0;
207 }
208
209
210 private byte encodeRecursionDesired( boolean recursionDesired )
211 {
212 if ( recursionDesired )
213 {
214 return ( byte ) 0x01;
215 }
216 return 0;
217 }
218
219
220 private byte encodeRecursionAvailable( boolean recursionAvailable )
221 {
222 if ( recursionAvailable )
223 {
224 return ( byte ) ( ( byte ) 0x01 << 7 );
225 }
226 return 0;
227 }
228
229
230 private byte encodeResponseCode( ResponseCode responseCode )
231 {
232 return ( byte ) ( responseCode.convert() & 0x0F );
233 }
234 }