001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.server.dns.service;
021    
022    
023    import java.util.ArrayList;
024    import java.util.Iterator;
025    import java.util.List;
026    import java.util.Set;
027    
028    import org.apache.directory.server.dns.DnsException;
029    import org.apache.directory.server.dns.messages.DnsMessage;
030    import org.apache.directory.server.dns.messages.DnsMessageModifier;
031    import org.apache.directory.server.dns.messages.MessageType;
032    import org.apache.directory.server.dns.messages.OpCode;
033    import org.apache.directory.server.dns.messages.QuestionRecord;
034    import org.apache.directory.server.dns.messages.ResourceRecord;
035    import org.apache.directory.server.dns.messages.ResponseCode;
036    import org.apache.directory.server.dns.store.RecordStore;
037    import org.apache.directory.server.i18n.I18n;
038    import org.slf4j.Logger;
039    import org.slf4j.LoggerFactory;
040    
041    
042    /**
043     * Domain Name Service (DNS) Protocol (RFC 1034, 1035)
044     * 
045     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
046     * @version $Rev: 901657 $, $Date: 2010-01-21 12:27:15 +0100 (Thu, 21 Jan 2010) $
047     */
048    public class DomainNameService
049    {
050        /** the log for this class */
051        private static final Logger LOG = LoggerFactory.getLogger( DomainNameService.class );
052    
053    
054        /**
055         * Creates a new instance of DomainNameService.
056         */
057        public static void execute( DnsContext dnsContext, DnsMessage request ) throws Exception
058        {
059            if ( LOG.isDebugEnabled() )
060            {
061                monitorRequest( request );
062            }
063    
064            getResourceRecords( dnsContext, request );
065    
066            if ( LOG.isDebugEnabled() )
067            {
068                monitorContext( dnsContext );
069            }
070    
071            buildReply( dnsContext, request );
072    
073            if ( LOG.isDebugEnabled() )
074            {
075                monitorReply( dnsContext );
076            }
077        }
078        
079        private static void monitorRequest( DnsMessage request ) throws Exception
080        {
081            try
082            {
083                LOG.debug( monitorMessage( request, "request" ) );
084            }
085            catch ( Exception e )
086            {
087                // This is a monitor.  No exceptions should bubble up.
088                LOG.error( I18n.err( I18n.ERR_153 ), e );
089            }
090        }
091        
092    
093        private static void getResourceRecords( DnsContext dnsContext, DnsMessage request ) throws Exception
094        {
095            RecordStore store = dnsContext.getStore();
096    
097            List<QuestionRecord> questions = request.getQuestionRecords();
098    
099            Iterator<QuestionRecord> it = questions.iterator();
100    
101            while ( it.hasNext() )
102            {
103                dnsContext.addResourceRecords( getEntry( store, it.next() ) );
104            }
105        }
106        
107        
108        /**
109         * Returns a set of {@link ResourceRecord}s from a {@link RecordStore}, given a DNS {@link QuestionRecord}.
110         *
111         * @param store
112         * @param question
113         * @return The set of {@link ResourceRecord}s.
114         * @throws DNSException
115         */
116        private static Set<ResourceRecord> getEntry( RecordStore store, QuestionRecord question ) throws DnsException
117        {
118            Set<ResourceRecord> records = null;
119    
120            records = store.getRecords( question );
121    
122            if ( records == null || records.isEmpty() )
123            {
124                LOG.debug( "The domain name referenced in the query does not exist." );
125    
126                throw new DnsException( ResponseCode.NAME_ERROR );
127            }
128    
129            return records;
130        }
131        
132        
133        private static void monitorContext( DnsContext dnsContext ) throws Exception
134        {
135            try
136            {
137                RecordStore store = dnsContext.getStore();
138                List<ResourceRecord> records = dnsContext.getResourceRecords();
139    
140                StringBuffer sb = new StringBuffer();
141                sb.append( "Monitoring context:" );
142                sb.append( "\n\t" + "store:                     " + store );
143                sb.append( "\n\t" + "records:                   " + records );
144    
145                LOG.debug( sb.toString() );
146            }
147            catch ( Exception e )
148            {
149                // This is a monitor.  No exceptions should bubble up.
150                LOG.error( I18n.err( I18n.ERR_154 ), e );
151            }
152        }
153        
154        
155        private static void buildReply( DnsContext dnsContext, DnsMessage request ) throws Exception
156        {
157            List<ResourceRecord> records = dnsContext.getResourceRecords();
158    
159            DnsMessageModifier modifier = new DnsMessageModifier();
160    
161            modifier.setTransactionId( request.getTransactionId() );
162            modifier.setMessageType( MessageType.RESPONSE );
163            modifier.setOpCode( OpCode.QUERY );
164            modifier.setAuthoritativeAnswer( false );
165            modifier.setTruncated( false );
166            modifier.setRecursionDesired( request.isRecursionDesired() );
167            modifier.setRecursionAvailable( false );
168            modifier.setReserved( false );
169            modifier.setAcceptNonAuthenticatedData( false );
170            modifier.setResponseCode( ResponseCode.NO_ERROR );
171            modifier.setQuestionRecords( request.getQuestionRecords() );
172    
173            modifier.setAnswerRecords( records );
174            modifier.setAuthorityRecords( new ArrayList<ResourceRecord>() );
175            modifier.setAdditionalRecords( new ArrayList<ResourceRecord>() );
176    
177            dnsContext.setReply( modifier.getDnsMessage() );
178        }
179     
180        
181        private static void monitorReply( DnsContext dnsContext ) throws Exception
182        {
183            try
184            {
185                DnsMessage reply = dnsContext.getReply();
186    
187                LOG.debug( monitorMessage( reply, "reply" ) );
188            }
189            catch ( Exception e )
190            {
191                // This is a monitor.  No exceptions should bubble up.
192                LOG.error( I18n.err( I18n.ERR_155 ), e );
193            }
194        }
195        
196        
197        private static String monitorMessage( DnsMessage message, String direction )
198        {
199            MessageType messageType = message.getMessageType();
200            OpCode opCode = message.getOpCode();
201            ResponseCode responseCode = message.getResponseCode();
202            int transactionId = message.getTransactionId();
203    
204            StringBuffer sb = new StringBuffer();
205            sb.append( "Monitoring " + direction + ":" );
206            sb.append( "\n\t" + "messageType                " + messageType );
207            sb.append( "\n\t" + "opCode                     " + opCode );
208            sb.append( "\n\t" + "responseCode               " + responseCode );
209            sb.append( "\n\t" + "transactionId              " + transactionId );
210    
211            sb.append( "\n\t" + "authoritativeAnswer        " + message.isAuthoritativeAnswer() );
212            sb.append( "\n\t" + "truncated                  " + message.isTruncated() );
213            sb.append( "\n\t" + "recursionDesired           " + message.isRecursionDesired() );
214            sb.append( "\n\t" + "recursionAvailable         " + message.isRecursionAvailable() );
215            sb.append( "\n\t" + "reserved                   " + message.isReserved() );
216            sb.append( "\n\t" + "acceptNonAuthenticatedData " + message.isAcceptNonAuthenticatedData() );
217    
218            List<QuestionRecord> questions = message.getQuestionRecords();
219    
220            sb.append( "\n\t" + "questions:                 " + questions );
221    
222            return sb.toString();
223        }
224    }