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 */ 020package org.apache.directory.server.dns.service; 021 022 023import java.util.ArrayList; 024import java.util.Iterator; 025import java.util.List; 026import java.util.Set; 027 028import org.apache.directory.server.dns.DnsException; 029import org.apache.directory.server.dns.messages.DnsMessage; 030import org.apache.directory.server.dns.messages.DnsMessageModifier; 031import org.apache.directory.server.dns.messages.MessageType; 032import org.apache.directory.server.dns.messages.OpCode; 033import org.apache.directory.server.dns.messages.QuestionRecord; 034import org.apache.directory.server.dns.messages.ResourceRecord; 035import org.apache.directory.server.dns.messages.ResponseCode; 036import org.apache.directory.server.dns.store.RecordStore; 037import org.apache.directory.server.i18n.I18n; 038import org.slf4j.Logger; 039import 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 */ 047public final class DomainNameService 048{ 049 /** the log for this class */ 050 private static final Logger LOG = LoggerFactory.getLogger( DomainNameService.class ); 051 052 053 private DomainNameService() 054 { 055 } 056 057 058 /** 059 * Creates a new instance of DomainNameService. 060 */ 061 public static void execute( DnsContext dnsContext, DnsMessage request ) throws Exception 062 { 063 if ( LOG.isDebugEnabled() ) 064 { 065 monitorRequest( request ); 066 } 067 068 getResourceRecords( dnsContext, request ); 069 070 if ( LOG.isDebugEnabled() ) 071 { 072 monitorContext( dnsContext ); 073 } 074 075 buildReply( dnsContext, request ); 076 077 if ( LOG.isDebugEnabled() ) 078 { 079 monitorReply( dnsContext ); 080 } 081 } 082 083 084 private static void monitorRequest( DnsMessage request ) 085 { 086 try 087 { 088 if ( LOG.isDebugEnabled() ) 089 { 090 LOG.debug( monitorMessage( request, "request" ) ); 091 } 092 } 093 catch ( Exception e ) 094 { 095 // This is a monitor. No exceptions should bubble up. 096 LOG.error( I18n.err( I18n.ERR_153 ), e ); 097 } 098 } 099 100 101 private static void getResourceRecords( DnsContext dnsContext, DnsMessage request ) throws DnsException 102 { 103 RecordStore store = dnsContext.getStore(); 104 105 List<QuestionRecord> questions = request.getQuestionRecords(); 106 107 Iterator<QuestionRecord> it = questions.iterator(); 108 109 while ( it.hasNext() ) 110 { 111 dnsContext.addResourceRecords( getEntry( store, it.next() ) ); 112 } 113 } 114 115 116 /** 117 * Returns a set of {@link ResourceRecord}s from a {@link RecordStore}, given a DNS {@link QuestionRecord}. 118 * 119 * @param store 120 * @param question 121 * @return The set of {@link ResourceRecord}s. 122 * @throws DNSException 123 */ 124 private static Set<ResourceRecord> getEntry( RecordStore store, QuestionRecord question ) throws DnsException 125 { 126 Set<ResourceRecord> records = null; 127 128 records = store.getRecords( question ); 129 130 if ( records == null || records.isEmpty() ) 131 { 132 LOG.debug( "The domain name referenced in the query does not exist." ); 133 134 throw new DnsException( ResponseCode.NAME_ERROR ); 135 } 136 137 return records; 138 } 139 140 141 private static void monitorContext( DnsContext dnsContext ) 142 { 143 try 144 { 145 RecordStore store = dnsContext.getStore(); 146 List<ResourceRecord> records = dnsContext.getResourceRecords(); 147 148 StringBuilder sb = new StringBuilder(); 149 sb.append( "Monitoring context:" ); 150 sb.append( "\n\t" + "store: " + store ); 151 sb.append( "\n\t" + "records: " + records ); 152 153 LOG.debug( sb.toString() ); 154 } 155 catch ( Exception e ) 156 { 157 // This is a monitor. No exceptions should bubble up. 158 LOG.error( I18n.err( I18n.ERR_154 ), e ); 159 } 160 } 161 162 163 private static void buildReply( DnsContext dnsContext, DnsMessage request ) 164 { 165 List<ResourceRecord> records = dnsContext.getResourceRecords(); 166 167 DnsMessageModifier modifier = new DnsMessageModifier(); 168 169 modifier.setTransactionId( request.getTransactionId() ); 170 modifier.setMessageType( MessageType.RESPONSE ); 171 modifier.setOpCode( OpCode.QUERY ); 172 modifier.setAuthoritativeAnswer( false ); 173 modifier.setTruncated( false ); 174 modifier.setRecursionDesired( request.isRecursionDesired() ); 175 modifier.setRecursionAvailable( false ); 176 modifier.setReserved( false ); 177 modifier.setAcceptNonAuthenticatedData( false ); 178 modifier.setResponseCode( ResponseCode.NO_ERROR ); 179 modifier.setQuestionRecords( request.getQuestionRecords() ); 180 181 modifier.setAnswerRecords( records ); 182 modifier.setAuthorityRecords( new ArrayList<ResourceRecord>() ); 183 modifier.setAdditionalRecords( new ArrayList<ResourceRecord>() ); 184 185 dnsContext.setReply( modifier.getDnsMessage() ); 186 } 187 188 189 private static void monitorReply( DnsContext dnsContext ) 190 { 191 try 192 { 193 DnsMessage reply = dnsContext.getReply(); 194 195 if ( LOG.isDebugEnabled() ) 196 { 197 LOG.debug( monitorMessage( reply, "reply" ) ); 198 } 199 } 200 catch ( Exception e ) 201 { 202 // This is a monitor. No exceptions should bubble up. 203 LOG.error( I18n.err( I18n.ERR_155 ), e ); 204 } 205 } 206 207 208 private static String monitorMessage( DnsMessage message, String direction ) 209 { 210 MessageType messageType = message.getMessageType(); 211 OpCode opCode = message.getOpCode(); 212 ResponseCode responseCode = message.getResponseCode(); 213 int transactionId = message.getTransactionId(); 214 215 StringBuilder sb = new StringBuilder(); 216 sb.append( "Monitoring " + direction + ":" ); 217 sb.append( "\n\t" + "messageType " + messageType ); 218 sb.append( "\n\t" + "opCode " + opCode ); 219 sb.append( "\n\t" + "responseCode " + responseCode ); 220 sb.append( "\n\t" + "transactionId " + transactionId ); 221 222 sb.append( "\n\t" + "authoritativeAnswer " + message.isAuthoritativeAnswer() ); 223 sb.append( "\n\t" + "truncated " + message.isTruncated() ); 224 sb.append( "\n\t" + "recursionDesired " + message.isRecursionDesired() ); 225 sb.append( "\n\t" + "recursionAvailable " + message.isRecursionAvailable() ); 226 sb.append( "\n\t" + "reserved " + message.isReserved() ); 227 sb.append( "\n\t" + "acceptNonAuthenticatedData " + message.isAcceptNonAuthenticatedData() ); 228 229 List<QuestionRecord> questions = message.getQuestionRecords(); 230 231 sb.append( "\n\t" + "questions: " + questions ); 232 233 return sb.toString(); 234 } 235}