Author: erodriguez Date: Mon Jan 10 17:14:34 2005 New Revision: 124859 URL: http://svn.apache.org/viewcvs?view=rev&rev=124859 Log: Basic DNS message decoder. Added: incubator/directory/dns/trunk/core/src/java/org/apache/dns/io/DnsMessageDecoder.java
Added: incubator/directory/dns/trunk/core/src/java/org/apache/dns/io/DnsMessageDecoder.java Url: http://svn.apache.org/viewcvs/incubator/directory/dns/trunk/core/src/java/org/apache/dns/io/DnsMessageDecoder.java?view=auto&rev=124859 ============================================================================== --- (empty file) +++ incubator/directory/dns/trunk/core/src/java/org/apache/dns/io/DnsMessageDecoder.java Mon Jan 10 17:14:34 2005 @@ -0,0 +1,191 @@ +/* + * Copyright 2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.dns.io; + +import java.nio.ByteBuffer; + +import org.apache.dns.messages.DnsMessage; +import org.apache.dns.messages.DnsMessageModifier; +import org.apache.dns.messages.MessageType; +import org.apache.dns.messages.OpCode; +import org.apache.dns.messages.ResponseCode; +import org.apache.dns.records.QuestionRecord; +import org.apache.dns.records.RecordClass; +import org.apache.dns.records.RecordType; +import org.apache.dns.records.ResourceRecord; + + +public class DnsMessageDecoder +{ + public DnsMessage decode( ByteBuffer byteBuffer ) + { + DnsMessageModifier modifier = new DnsMessageModifier(); + + modifier.setTransactionId( byteBuffer.getShort() ); + + byte header = byteBuffer.get(); + modifier.setMessageType( parseMessageType( header ) ); + modifier.setOpCode( parseOpCode( header ) ); + modifier.setAuthoritativeAnswer( parseAuthoritativeAnswer( header ) ); + modifier.setTruncated( parseTruncated( header ) ); + modifier.setRecursionDesired( parseRecursionDesired( header ) ); + + header = byteBuffer.get(); + modifier.setRecursionAvailable( parseRecursionAvailable( header ) ); + modifier.setResponseCode( parseResponseCode( header ) ); + + short questionCount = byteBuffer.getShort(); + short answerCount = byteBuffer.getShort(); + short authorityCount = byteBuffer.getShort(); + short additionalCount = byteBuffer.getShort(); + + modifier.setQuestionRecords( parseQuestions( questionCount, byteBuffer ) ); + modifier.setAnswerRecords( parseRecords( answerCount, byteBuffer ) ); + modifier.setAuthorityRecords( parseRecords( authorityCount, byteBuffer ) ); + modifier.setAdditionalRecords( parseRecords( additionalCount, byteBuffer ) ); + + return modifier.getDnsMessage(); + } + + private ResourceRecord[] parseRecords( short recordCount, ByteBuffer byteBuffer ) + { + ResourceRecord[] questions = new ResourceRecord[ recordCount ]; + + for ( int ii = 0; ii < recordCount; ii++ ) + { + String domainName = parseDomainName( byteBuffer ); + + RecordType recordType = RecordType.getTypeByOrdinal( byteBuffer.getShort() ); + RecordClass recordClass = RecordClass.getTypeByOrdinal( byteBuffer.getShort() ); + + int timeToLive = byteBuffer.getInt(); + short dataLength = byteBuffer.getShort(); + + byte[] data = new byte[ dataLength ]; + byteBuffer.get( data ); + + questions[ ii ] = new ResourceRecord( domainName, recordType, + recordClass, timeToLive, data ); + } + + return questions; + } + + private QuestionRecord[] parseQuestions( short questionCount, ByteBuffer byteBuffer ) + { + QuestionRecord[] questions = new QuestionRecord[ questionCount ]; + + for ( int ii = 0; ii < questionCount; ii++ ) + { + String domainName = parseDomainName( byteBuffer ); + + RecordType recordType = RecordType.getTypeByOrdinal( byteBuffer.getShort() ); + RecordClass recordClass = RecordClass.getTypeByOrdinal( byteBuffer.getShort() ); + + questions[ ii ] = new QuestionRecord( domainName, recordType, recordClass ); + } + + return questions; + } + + private String parseDomainName( ByteBuffer byteBuffer ) + { + StringBuffer domainName = new StringBuffer(); + recurseDomainName( domainName, byteBuffer ); + + return domainName.toString(); + } + + private void recurseDomainName( StringBuffer domainName, ByteBuffer byteBuffer ) + { + byte currentByte = byteBuffer.get(); + + boolean isCompressed = ( ( currentByte & (byte)0xc0 ) == (byte)0xc0 ); + boolean isLabelLength = ( ( currentByte != 0 ) && !isCompressed ); + + if ( isCompressed ) + { + int position = byteBuffer.get(); + int originalPosition = byteBuffer.position(); + byteBuffer.position( position ); + + int labelLength = byteBuffer.get(); + getLabel( labelLength, byteBuffer, domainName ); + recurseDomainName( domainName, byteBuffer ); + + byteBuffer.position( originalPosition ); + } + + if ( isLabelLength ) + { + int labelLength = currentByte; + getLabel( labelLength, byteBuffer, domainName ); + recurseDomainName( domainName, byteBuffer ); + } + } + + private void getLabel( int labelLength, ByteBuffer byteBuffer, StringBuffer domainName ) + { + for ( int jj = 0; jj < labelLength; jj++ ) + { + char character = (char)byteBuffer.get(); + domainName.append( character ); + } + + if ( byteBuffer.get( byteBuffer.position() ) != 0 ) + { + domainName.append( "." ); + } + } + + private MessageType parseMessageType( byte header ) + { + return MessageType.getTypeByOrdinal( ( header & 0x80 ) >>> 7 ); + } + + private OpCode parseOpCode( byte header ) + { + return OpCode.getTypeByOrdinal( ( header & 0x78 ) >>> 3 ); + } + + private boolean parseAuthoritativeAnswer( byte header ) + { + return ( ( header & 0x04 ) >>> 2 ) == 1; + } + + private boolean parseTruncated( byte header ) + { + return ( ( header & 0x02 ) >>> 1 ) == 1; + } + + private boolean parseRecursionDesired( byte header ) + { + return ( ( header & 0x01 ) ) == 1; + } + + private boolean parseRecursionAvailable( byte header ) + { + return ( ( header & 0x80 ) >>> 7 ) == 1; + } + + private ResponseCode parseResponseCode( byte header ) + { + return ResponseCode.getTypeByOrdinal( header & 0x0F ); + } +} +
