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.store.jndi.operations;
22
23
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Map;
28 import java.util.Properties;
29 import java.util.Set;
30
31 import javax.naming.CompoundName;
32 import javax.naming.Name;
33 import javax.naming.NamingEnumeration;
34 import javax.naming.NamingException;
35 import javax.naming.directory.Attribute;
36 import javax.naming.directory.Attributes;
37 import javax.naming.directory.DirContext;
38 import javax.naming.directory.SearchControls;
39 import javax.naming.directory.SearchResult;
40
41 import org.apache.directory.server.dns.messages.QuestionRecord;
42 import org.apache.directory.server.dns.messages.RecordClass;
43 import org.apache.directory.server.dns.messages.RecordType;
44 import org.apache.directory.server.dns.messages.ResourceRecord;
45 import org.apache.directory.server.dns.messages.ResourceRecordModifier;
46 import org.apache.directory.server.dns.store.DnsAttribute;
47 import org.apache.directory.server.dns.store.jndi.DnsOperation;
48 import org.apache.directory.shared.ldap.constants.SchemaConstants;
49
50
51
52
53
54
55
56
57 public class GetRecords implements DnsOperation
58 {
59 private static final long serialVersionUID = 1077580995617778894L;
60
61
62 private final QuestionRecord question;
63
64
65
66
67
68
69
70 public GetRecords( QuestionRecord question )
71 {
72 this.question = question;
73 }
74
75
76
77
78 private static final Map<RecordType, String> TYPE_TO_OBJECTCLASS;
79
80 static
81 {
82 Map<RecordType, String> typeToObjectClass = new HashMap<RecordType, String>();
83 typeToObjectClass.put( RecordType.SOA, "apacheDnsStartOfAuthorityRecord" );
84 typeToObjectClass.put( RecordType.A, "apacheDnsAddressRecord" );
85 typeToObjectClass.put( RecordType.NS, "apacheDnsNameServerRecord" );
86 typeToObjectClass.put( RecordType.CNAME, "apacheDnsCanonicalNameRecord" );
87 typeToObjectClass.put( RecordType.PTR, "apacheDnsPointerRecord" );
88 typeToObjectClass.put( RecordType.MX, "apacheDnsMailExchangeRecord" );
89 typeToObjectClass.put( RecordType.SRV, "apacheDnsServiceRecord" );
90 typeToObjectClass.put( RecordType.TXT, "apacheDnsTextRecord" );
91
92 TYPE_TO_OBJECTCLASS = Collections.unmodifiableMap( typeToObjectClass );
93 }
94
95
96
97
98 private static final Map<String, RecordType> OBJECTCLASS_TO_TYPE;
99
100 static
101 {
102 Map<String, RecordType> objectClassToType = new HashMap<String, RecordType>();
103 objectClassToType.put( "apacheDnsStartOfAuthorityRecord", RecordType.SOA );
104 objectClassToType.put( "apacheDnsAddressRecord", RecordType.A );
105 objectClassToType.put( "apacheDnsNameServerRecord", RecordType.NS );
106 objectClassToType.put( "apacheDnsCanonicalNameRecord", RecordType.CNAME );
107 objectClassToType.put( "apacheDnsPointerRecord", RecordType.PTR );
108 objectClassToType.put( "apacheDnsMailExchangeRecord", RecordType.MX );
109 objectClassToType.put( "apacheDnsServiceRecord", RecordType.SRV );
110 objectClassToType.put( "apacheDnsTextRecord", RecordType.TXT );
111 objectClassToType.put( "apacheDnsReferralNameServer", RecordType.NS );
112 objectClassToType.put( "apacheDnsReferralAddress", RecordType.A );
113
114 OBJECTCLASS_TO_TYPE = Collections.unmodifiableMap( objectClassToType );
115 }
116
117
118
119
120
121
122 public Set<ResourceRecord> execute( DirContext ctx, Name base ) throws Exception
123 {
124 if ( question == null )
125 {
126 return null;
127 }
128
129 String name = question.getDomainName();
130 RecordType type = question.getRecordType();
131
132 SearchControls controls = new SearchControls();
133 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
134
135 String filter = "(objectClass=" + TYPE_TO_OBJECTCLASS.get( type ) + ")";
136
137 NamingEnumeration<SearchResult> list = ctx.search( transformDomainName( name ), filter, controls );
138
139 Set<ResourceRecord> set = new HashSet<ResourceRecord>();
140
141 while ( list.hasMore() )
142 {
143 SearchResult result = list.next();
144 Name relative = getRelativeName( ctx.getNameInNamespace(), result.getName() );
145
146 set.add( getRecord( result.getAttributes(), relative ) );
147 }
148
149 return set;
150 }
151
152
153
154
155
156
157
158
159
160 private ResourceRecord getRecord( Attributes attrs, Name relative ) throws NamingException
161 {
162 String SOA_MINIMUM = "86400";
163 String SOA_CLASS = "IN";
164
165 ResourceRecordModifier modifier = new ResourceRecordModifier();
166
167 Attribute attr;
168
169
170 attr = attrs.get( DnsAttribute.NAME );
171
172 if ( attr != null )
173 {
174 modifier.setDnsName( ( String ) attr.get() );
175 }
176 else
177 {
178 relative = getDomainComponents( relative );
179
180 String dnsName;
181 dnsName = transformDistinguishedName( relative.toString() );
182 modifier.setDnsName( dnsName );
183 }
184
185
186 attr = attrs.get( DnsAttribute.TYPE );
187
188 if ( attr != null )
189 {
190 modifier.setDnsType( RecordType.valueOf( ( String ) attr.get() ) );
191 }
192 else
193 {
194 modifier.setDnsType( getType( attrs.get( SchemaConstants.OBJECT_CLASS_AT ) ) );
195 }
196
197
198 String dnsClass = ( attr = attrs.get( DnsAttribute.CLASS ) ) != null ? ( String ) attr.get() : SOA_CLASS;
199 modifier.setDnsClass( RecordClass.valueOf( dnsClass ) );
200
201
202 String dnsTtl = ( attr = attrs.get( DnsAttribute.TTL ) ) != null ? ( String ) attr.get() : SOA_MINIMUM;
203 modifier.setDnsTtl( Integer.parseInt( dnsTtl ) );
204
205 NamingEnumeration<String> ids = attrs.getIDs();
206
207 while ( ids.hasMore() )
208 {
209 String id = ids.next();
210 modifier.put( id, ( String ) attrs.get( id ).get() );
211 }
212
213 return modifier.getEntry();
214 }
215
216
217
218
219
220
221
222
223
224 String transformDomainName( String domainName )
225 {
226 if ( domainName == null || domainName.length() == 0 )
227 {
228 return "";
229 }
230
231 StringBuffer buf = new StringBuffer( domainName.length() + 16 );
232
233 buf.append( "dc=" );
234 buf.append( domainName.replaceAll( "\\.", ",dc=" ) );
235
236 return buf.toString();
237 }
238
239
240
241
242
243
244
245
246
247 String transformDistinguishedName( String distinguishedName )
248 {
249 if ( distinguishedName == null || distinguishedName.length() == 0 )
250 {
251 return "";
252 }
253
254 String domainName = distinguishedName.replaceFirst( "dc=", "" );
255 domainName = domainName.replaceAll( ",dc=", "." );
256
257 return domainName;
258 }
259
260
261 private RecordType getType( Attribute objectClass ) throws NamingException
262 {
263 NamingEnumeration<?> list = objectClass.getAll();
264
265 while ( list.hasMore() )
266 {
267 String value = ( String ) list.next();
268
269 if ( !value.equals( "apacheDnsAbstractRecord" ) )
270 {
271 RecordType type = OBJECTCLASS_TO_TYPE.get( value );
272
273 if ( type == null )
274 {
275 throw new RuntimeException( "Record type to objectClass mapping has not been set." );
276 }
277
278 return type;
279 }
280 }
281
282 throw new NamingException( "ResourceRecord requires STRUCTURAL objectClass" );
283 }
284
285
286 private Name getRelativeName( String nameInNamespace, String baseDn ) throws NamingException
287 {
288 Properties props = new Properties();
289 props.setProperty( "jndi.syntax.direction", "right_to_left" );
290 props.setProperty( "jndi.syntax.separator", "," );
291 props.setProperty( "jndi.syntax.ignorecase", "true" );
292 props.setProperty( "jndi.syntax.trimblanks", "true" );
293
294 Name searchBaseDn = null;
295
296 Name ctxRoot = new CompoundName( nameInNamespace, props );
297 searchBaseDn = new CompoundName( baseDn, props );
298
299 if ( !searchBaseDn.startsWith( ctxRoot ) )
300 {
301 throw new NamingException( "Invalid search base " + baseDn );
302 }
303
304 for ( int ii = 0; ii < ctxRoot.size(); ii++ )
305 {
306 searchBaseDn.remove( 0 );
307 }
308
309 return searchBaseDn;
310 }
311
312
313 private Name getDomainComponents( Name name ) throws NamingException
314 {
315 for ( int ii = 0; ii < name.size(); ii++ )
316 {
317 if ( !name.get( ii ).startsWith( "dc=" ) )
318 {
319 name.remove( ii );
320 }
321 }
322
323 return name;
324 }
325 }