You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by er...@apache.org on 2005/01/11 02:14:35 UTC

svn commit: r124859 - /incubator/directory/dns/trunk/core/src/java/org/apache/dns/io/DnsMessageDecoder.java

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 );
+	}
+}
+