/*
* Copyright 2004-2006 Luke Quinane and Daniel Frampton
*
* 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.
*
*/
using System;
using System.Collections;
using System.Net;
using System.Text;
namespace NDns.Message{
/// <summary>
/// This class encodes and decodes DNS string names in or for DNS messages.
/// </summary>
public class DomainCoder {
/// <summary>
/// A hash table of references indexed by string names.
/// </summary>
protected Hashtable references = new Hashtable();
#region EncodeDomain
/// <summary>
/// Encodes a string entry or a reference to the string entry for the given
/// domain.
/// </summary>
/// <param name="domainName">The string to create the entry for.</param>
/// <param name="start">The reference to the start of this entry in the message.</param>
/// <returns>The string name or a reference to the first occurence.</returns>
public byte[] EncodeDomain(string domainName, ushort start) {
// TODO: sub-domains :p
byte[] result;
if (this.references.ContainsKey(domainName)) {
// create a reference to the previous entry
ushort reference = (ushort) this.references[domainName];
result = new byte[2];
result[0] = (3 << 6);
result[0] |= (byte) ((reference >> 8) & 0x3f);
result[1] = (byte) reference;
return result;
}
byte[] data = new byte[255];
string[] labels = domainName.Split('.');
int position = 0;
// convert string to a byte array (prepending with length)
foreach (string label in labels) {
data[position++] = (byte) label.Length;
byte[] labelData = Encoding.ASCII.GetBytes(label.ToCharArray());
labelData.CopyTo(data, position);
position += labelData.Length;
}
// terminate entry
data[position++] = 0;
// add the entry to the lists
this.references.Add(domainName, start);
// copy to byte array of the correct size
result = new byte[position];
Array.Copy(data, 0, result, 0, position);
return result;
}
#endregion
#region DecodeDomain
/// <summary>
/// Decodes the data to retrieve a string name.
/// </summary>
/// <param name="data">The data to process.</param>
/// <param name="start">The position to start processing from.</param>
/// <param name="length">The length of data read.</param>
/// <returns>The string decoded.</returns>
public string DecodeDomain(byte[] data, ushort start, out ushort length) {
ushort position = start;
string domainName = "";
while (true) {
ushort dataLength = data[position++];
if (dataLength == 0) {
// end of string name
length = (ushort) (position - start);
return domainName;
}
if ((dataLength & 0xC0) == 0xC0) {
// reference to previous string entry
ushort key = (ushort) ((dataLength >> 8) & 0x3f);
key |= data[position++];
length = (ushort) (position - start);
ushort tmp;
if (domainName.Length > 0) {
return domainName + "." + DecodeDomain(data, key, out tmp);
}
else {
return DecodeDomain(data, key, out tmp);
}
}
// read the next label
char[] labelData = new char[dataLength];
position += (ushort) Encoding.ASCII.GetDecoder().GetChars(data, position, dataLength, labelData, 0);
string label = new string(labelData);
// append the label onto the domain
if (domainName.Length > 0) {
domainName += "." + label;
}
else {
domainName += label;
}
}
}
#endregion
}
}
|