tcpiputils/dnd/src/message.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dnd/src/message.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,1552 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// message.cpp - name resolver DNS message interpreter
+//
+
+#include <dns_qry.h>
+#include "res_sock.h"
+#include "message.h"
+#include <networking/dnd_err.h>
+#include "dns_ext.h"
+
+#ifdef EXCLUDE_SYMBIAN_DNS_PUNYCODE
+#undef SYMBIAN_DNS_PUNYCODE
+#endif //EXCLUDE_SYMBIAN_DNS_PUNYCODE
+
+// Constants
+
+_LIT8(KIPv4AddrToHost, ".in-addr.arpa");
+#ifdef DNS_REVERSE_IP6_INT
+_LIT8(KIPv6AddrToHost, ".ip6.int");
+#else
+_LIT8(KIPv6AddrToHost, ".ip6.arpa");
+#endif
+
+#ifdef SYMBIAN_DNS_PUNYCODE 
+/* This macro is to check whether the character passed is of UTF encoded */
+#define ISUTF16(x) ((x>= 0xD800 && x<= 0xDFFF)? ETrue : EFalse)
+#endif //SYMBIAN_DNS_PUNYCODE
+
+//
+// DnsCompareNames
+// ***************
+// A global utility function
+//
+/**
+// The DNS domain names have a special case folding rules. The names
+// are BINARY data (can include anything in range [0..255], but when
+// comparing two names, ASCII lower and and upper case letters should
+// compare equal, e.g  A-Z == a-z.
+//
+// @param	aName1	to be compared
+// @param	aName2	to be compared
+// @returns	TRUE, if names are equal under DNS case folding rules
+*/
+TBool DnsCompareNames(const TDesC8 &aName1, const TDesC8 &aName2)
+	{
+	static const TUint8 KAscii_A = 0x41;
+	static const TUint8 KAscii_Z = 0x5a;
+	static const TUint8 KAscii_lower = 0x20;
+
+	TInt n = aName1.Length();
+	if (n != aName2.Length())
+		return 0;	// not same, lengths differ
+	//
+	// Need to do the special "DNS case insensitive" compare
+	//
+	const TUint8 *const p = aName1.Ptr();
+	const TUint8 *const q = aName2.Ptr();
+	while (--n >= 0)
+		{
+		TUint8 x = p[n];
+		TUint8 y = q[n];
+		if (x != y)
+			{
+			if (x >= KAscii_A && x <= KAscii_Z)
+				x += KAscii_lower;
+			if (y >= KAscii_A && y <= KAscii_Z)
+				y += KAscii_lower;
+			if (x != y)
+				return 0;
+			}
+		}
+	return 1;
+	}
+
+
+//
+// Initialize TDndHeader
+//
+void TDndHeader::Init(const TUint16 aID, const TUint8 aOpcode)
+	{
+	// Set ID to aID
+	i[0] = (TUint8)(aID / 0x0100);
+	i[1] = (TUint8)(aID % 0x0100);
+
+	// Set QR = 0; Opcode = aOpcode; AA = 0; TC = 0; RD = 1
+	i[2] = 1;
+	i[2] |= (aOpcode << 3);
+
+	// Set RA = 0; Z = 0; RCode = 0
+	i[3] = 0;
+
+	// Set QDCOUNT = 1
+	i[4] = 0;
+	i[5] = 1;
+	
+	// Set all other counts as zero.
+	// ANCOUNT = 0;
+	// NSCOUNT = 0;
+	// ARCOUNT = 0;
+	i[6] = 0;
+	i[7] = 0;
+	i[8] = 0;
+	i[9] = 0;
+	i[10] = 0;
+	i[11] = 0;
+	}
+
+// to set the ID field of header
+void TDndHeader::SetId(const TUint16 aID)
+	{
+	i[0] = (TUint8)(aID / 0x0100);
+	i[1] = (TUint8)(aID % 0x0100);
+	}
+
+#ifdef LLMNR_ENABLED
+// TDndHeader::SetQR() - To set the query/response bit of the header
+void TDndHeader::SetQR(const TUint aQR)
+    {
+    i[2] |= ((aQR & 0x1) << 7);
+    }
+#endif
+
+// TDndHeader::SetOpcode() - To set the opcode field of the header
+void TDndHeader::SetOpcode(const TUint8 aOpcode)
+	{
+	i[2] |= ((aOpcode & 0xF) << 3);
+	}
+
+#ifdef LLMNR_ENABLED
+// TDndHeader::SetAA() - To set the authoritative answer bit of the header
+void TDndHeader::SetAA(const TUint aAA)
+    {
+    i[2] |= ((aAA & 0x1) << 2);
+    }
+
+// TDndHeader::SetRCode() - To set the value of RCode field of the header
+void TDndHeader::SetRCode(const TUint aRCode)
+    {
+    i[3] |= aRCode & 0xF;
+    }
+#endif
+
+// TDndHeader::SetQdCount() - To set the QdCount field
+void TDndHeader::SetQdCount(const TUint16 aQdCount)
+	{
+	i[4] = (TUint8)(aQdCount / 0x0100);
+	i[5] = (TUint8)(aQdCount % 0x0100);
+	}
+
+
+// TDndHeader::SetAnCount() - To set the answer count field
+void TDndHeader::SetAnCount(const TUint16 aAnCount)
+	{
+	i[6] = (TUint8)(aAnCount / 0x0100);
+	i[7] = (TUint8)(aAnCount % 0x0100);
+	}
+
+void TDndHeader::SetArCount(const TUint16 aArCount)
+	{
+	i[10] = (TUint8)(aArCount / 0x0100);
+	i[11] = (TUint8)(aArCount % 0x0100);
+	}
+#ifdef SYMBIAN_DNS_PROXY
+void TDndHeader::SetNsCount(const TUint16 aNsCount)
+	{
+	i[8] = (TUint8)(aNsCount / 0x0100);
+	i[9] = (TUint8)(aNsCount % 0x0100);
+	}
+#endif
+
+
+// TMsgBuf::VerifyMessage
+// **********************
+/**
+// Verify basic header fields in the responce.
+//
+// @retval aRCode The RCode from the message (if return > 0)
+// @retval aQuestion The question from the message (if return > 0)
+//
+// @return
+//	@li < 0, if there are any format errors with the message
+//	@li > 0, offset to the first answer RR after the question section
+*/
+TInt TMsgBuf::VerifyMessage(TInt &aRCode, TDndQuestion &aQuestion) const
+	{
+	// Check that message is actually long enough for the header
+	// Return length of the fixed header (= offset pointing to next part)
+	ASSERT(sizeof(TDndHeader) == KDnsMinHeader);
+	if (Length() < TInt(sizeof(TDndHeader)))
+		return KErrDndDiscard;
+
+	const TDndHeader &hdr = Header();
+	// ..do some simple insanity tests, and discard if odd things
+	// detected.
+	if (hdr.ANCOUNT() < 0)
+		return KErrDndDiscard;
+	if (hdr.NSCOUNT() < 0)
+		return KErrDndDiscard;
+	if (hdr.ARCOUNT() < 0)
+		return KErrDndDiscard;
+
+	TInt offset = aQuestion.Create(*this, sizeof(TDndHeader));
+	if (offset > 0)
+		{
+		// Question extracted, now we can look for EDNS0 OPT record
+		// to find the real RCODE...
+		TDndRR opt_rr(*this);
+		const TInt start = hdr.ANCOUNT() + hdr.NSCOUNT();
+		if (opt_rr.LocateRR(offset, start + hdr.ARCOUNT(), EDnsQType_OPT, EDnsQClass_ANY, start) > offset)
+			{
+			// OPT RR has been located
+			// ..return extend RCODE.
+			aRCode = ((opt_rr.iTTL >> 20) & 0xFF0) | hdr.RCODE();
+			}
+		else
+			{
+			// NO OPT RR present, RCODE is as it
+			aRCode = hdr.RCODE();
+			}
+		}
+	return offset;
+	}
+
+
+// TMsgBuf::GetNextName
+// ********************
+/**
+// @param	aOffset	from the start of the message to the domain name
+// @retval	aName	receives the extracted domain name (in raw DNS 8bit encoding)
+// @param	aDepth	("internal" paramater) recursion count to catch looped compression
+// @returns
+//	@li > 0, updated offset pointing past the name portion
+//	@li	< 0, an error was detected
+*/
+TInt TMsgBuf::GetNextName(TInt aOffset, TDes8 &aName, const TUint aDepth) const
+	{
+	TInt tag;
+	TInt err;
+
+	if (aDepth >= KDndMaxLoopCount ||	// Prevent infinite recursion...
+		aOffset >= Length() ||			// ...offsets beyond the buffer end,
+		aOffset < 0)					// ...or before buffer start (someone didn't check error return!)
+		return KErrDndDiscard;
+
+	const TUint8 *p = Ptr() + aOffset;
+
+	while ((tag = *p) != 0)
+		{
+		if ((tag & 0xC0) == 0xC0)
+			{
+			if (Length() < aOffset + 2)
+				return KErrDndDiscard;
+
+			const TInt tempOffset = (tag - 0xC0) * 256 + *(p+1);
+			err = GetNextName(tempOffset, aName, aDepth+1);
+			if (err < KErrNone)
+				return err;
+
+			p += 2;
+			aOffset += 2;
+			break;
+			}
+		else
+			{
+			p++;
+			aOffset++;
+			if (aName.Length() + tag >= aName.MaxLength())
+				return KErrDndNameTooBig;
+			if (Length() < aOffset + tag)
+				return KErrDndUnknown;
+
+			aName.Append(TPtrC8(p, tag));
+			aName.Append('.');
+			p += tag;
+			aOffset += tag;
+			}
+		}
+
+	if (tag == 0)
+		{
+		p++;
+		aOffset++;
+		// if there is a 'dot' at the end, get rid of it
+		if (aName.Length() != 0)
+			aName.Delete(aName.Length() - 1, 1);
+		}
+	return aOffset;
+	}
+
+
+// TMsgBuf::GetNextString
+// **********************
+/**
+// @param	aOffset	from the start of the message to the character string
+// @retval	aString	receives the extracted string (in raw DNS 8bit encoding). This
+//			is only a reference to the original DNS message buffer, which must be
+//			kept around while this is used.
+// @returns
+//	@li	> 0, updated offset pointing past extracted string
+//	@li	< 0, an error was detected
+*/
+TInt TMsgBuf::GetNextString(TInt aOffset, TPtrC8 &aString) const
+	{
+	if (aOffset >= Length())
+		return KErrDndUnknown;	// corrupt data
+
+	const TUint8 *p = Ptr() + aOffset;
+	//
+	// Extract <character-string> length
+	//
+	TInt length = *p++;
+	aOffset += length + 1;
+	if (aOffset > Length())
+		return KErrDndUnknown;	// corrupt data
+
+	aString.Set(p, length);
+	return aOffset;
+	}
+
+// TMsgBuf::GetName
+// ****************
+/**
+// @param	aOffset	from the start of the message to the start of domain name
+#ifdef SYMBIAN_DNS_PUNYCODE
+// @param   aIdnEnabled   
+#endif
+// @retval	aName	the extracted domain name (system dependent encoding)
+// @returns
+//	@li	> 0, offset updated pointing past the name portion
+//	@li	< 0, an error was detected
+*/
+#ifdef SYMBIAN_DNS_PUNYCODE
+TInt TMsgBuf::GetName(TInt aOffset, TDes &aName,TBool aIdnEnabled) const
+#else
+TInt TMsgBuf::GetName(TInt aOffset, TDes &aName) const
+#endif //SYMBIAN_DNS_PUNYCODE
+	{
+	// Use TDndName as temporary buffer. This seemingly
+	// unnecessary juggling is present because of the potentially
+	// hairy/complex issues of DNS <-> UNICODE translation. The idea
+	// is to have one clean location which implements it:
+	// TDndName::SetName and TDndName::GetName methods.
+	TDndName tmp;
+#ifdef SYMBIAN_DNS_PUNYCODE
+	tmp.EnableIdn(aIdnEnabled);
+#endif
+	TInt i = tmp.SetName(*this, aOffset);
+	if (i < 0)
+		return i;
+	TInt err = tmp.GetName(aName);
+	// This function must return offset when no errors
+	return err == KErrNone ? i : err;
+	}
+
+// TMsgBuf::AppendName
+// *******************
+/**
+// @param	aName
+//		domain name to be appended
+// @param	aCompressed
+//	@li	= 0,
+//		the name is assumed to be complete name will be terminated with "root label"
+//	@li	> 0,
+//		the name is assumed to be a prefix to another name already stored into the
+//		message starting at indicated offset.
+//		The name (prefix) is terminated with a "compression ptr".
+//		The value must be in range [1..Length()-1].
+//
+// @returns
+//	@li	KErrNone
+//		if name appended succesfully
+//	@li	KErrDndNameTooBig,
+//		if name does not fit the message buffer
+//	@li	KErrBadName,
+//		if name is invalid, e.g. has empty or too long (> 63)
+//		components
+//	@li	KErrDndUnknown
+//		if aCompressed is illegal, e.g. not in range [0..Length()-1]
+*/
+TInt TMsgBuf::AppendName(const TDesC8 &aName, const TUint aCompressed)
+	{
+	if (aCompressed >= (TUint)Length())
+		return KErrDndUnknown; // Don't allow forward references in compression pointers.
+	// The space requirement
+	// + length of the iName
+	// and
+	//    + 1 (for the terminator NUL byte, root)
+	//  or
+	//    + 2 (for the compression pointer)
+	//	
+	// [note: if the name already has a trailing '.', the code below
+	// will handle it, but the spacerequirement computation is too
+	// large by one byte -- a minor discrepancy, which is
+	// not worth coding -- msa]
+	if (Length() + aName.Length() + 1 + (aCompressed > 0) > MaxLength())
+		return KErrDndNameTooBig;
+
+	//
+	// Append <domain-name> as labels
+	//
+	TInt i;
+	TPtrC8 name(aName);
+	while ((i = name.Locate('.')) != KErrNotFound)
+		{
+		// a valid label contains at least one and at most 63 characters
+		if (i < 1 || i > 63)
+			return KErrDndBadName;	// ..abort message build!
+		Append((TChar)i);
+		Append(name.Left(i));
+		name.Set(name.Mid(i+1));		// Skip the dot.
+		}
+	i = name.Length();
+	if (i > 0)
+		{
+		// append the last component...
+		if (i > 63)
+			return KErrDndBadName;
+		Append((TChar)i);
+		Append(name);
+		}
+	//
+	// Append terminator
+	//
+	if (!aCompressed)
+		Append((TChar)0);		//Root
+	else
+		{
+		Append((TChar)((aCompressed / 0x100) | 0xC0));
+		Append((TChar)(aCompressed % 0x100));
+		}
+	return KErrNone;
+	}
+
+// TMsgBuf::GetRR
+// **************
+/**
+// @param aOffset	of the recource record (points to NAME)
+// @retval aType	RR type
+// @retval aClass	RR class
+// @retval aTTL		RR TTL (time to live)
+// @retval aRD		offset to the beginning of the RDATA
+// @retval aRDLength	the length of the RDATA
+//	
+// @return	offset pointing after the RR.
+*/
+TInt TMsgBuf::GetRR(const TInt aOffset, TUint16 &aType, TUint16 &aClass, TUint32 &aTTL, TUint &aRd, TUint &aRdLength) const
+	{
+	return Header().Resource(aOffset, Length(), aType, aClass, aTTL, aRd, aRdLength);
+	}
+
+TInt TMsgBuf::SkipName(TInt aOffset) const
+	{
+	return Header().NameSkip(aOffset, Length());
+	}
+
+
+// TDndName::SetName
+// *****************
+// Set PTR name from address
+//
+/**
+// Translate the address into a query name for the PTR query.
+// For example 172.21.33.80 -> 80.33.21.172.in-addr.arpa.
+//
+// @param	aAddr	the address to be translated into PTR name
+// @returns
+//	@li		KErrnone, if translation succeeded
+//	@li		KErrNotSupported, if translation not supported
+//			(bad address or unknown address family)
+*/
+TInt TDndName::SetName(const TInetAddr &aAddr)
+	{
+ 
+	if (aAddr.Family() == KAfInet ||
+		aAddr.IsV4Mapped() ||	// V4 Mapped is internal, and always means IPv4
+		aAddr.IsV4Compat())		// Treating V4 Compatible as IPv4 might be questionable?
+		{
+		TUint32 address = aAddr.Address();
+		if (address == KInetAddrNone)
+			return KErrNotSupported;
+	
+		Format(_L8("%d.%d.%d.%d"),
+			(TUint8)(address),
+			(TUint8)(address >> 8),
+			(TUint8)(address >> 16),
+			(TUint8)(address >> 24));
+
+		Append(KIPv4AddrToHost);
+		return KErrNone;
+		}
+
+	else if (aAddr.Family() == KAfInet6)	// for IPv6
+		{
+		SetLength(0);
+
+		const TIp6Addr &address = aAddr.Ip6Address();
+		// ..are there any addresses that should never be
+		// PTR queried? unspecified? loopback? anything else?
+		// Or, should even these tests removed and let the
+		// query just fail normally? -- msa
+		if (address.IsUnspecified() ||
+			address.IsLoopback())
+			return KErrNotSupported;
+
+		for (TInt i = 15; i >= 0; i--)
+			{
+			for (TInt j = 0; j < 2; j++)
+				{
+				TChar c;
+				TUint8 digit = (TUint8)((address.u.iAddr8[i] >> (4 * j)) & 0x0f);
+				if (digit < 10)
+					c = (TChar)('0' + digit);
+				else
+					c = (TChar)('a' + digit - 10);
+				Append(c);
+				if (i != 0 || j != 1)
+					Append('.');
+				}
+			}
+		Append(KIPv6AddrToHost);
+		return KErrNone;
+		}
+	return KErrNotSupported;
+	}
+
+
+//
+// TDndName::SetName
+// *****************
+/**
+// Uncompres the <domain-name> from a DNS message into name
+//
+// @param	aBuf	buffer containing the DNS message packet
+// @param	aOffset	from the start of the message to the name
+// @returns
+//	@li		> 0, updated offset past the extracted name, if succesful
+//	@li		< 0, if some error
+*/
+TInt TDndName::SetName(const TMsgBuf &aBuf, const TInt aOffset)
+	{
+	Zero();
+	return aBuf.GetNextName(aOffset, *this);
+	}
+		
+
+// TDndName::SetName
+// *****************
+// Set name from THostName
+//
+/**
+// Translate system encoding into query name. In Unicode this
+// means converting the Unicode to equivalent DNS name. For
+// narrow builds, this is usually a straight copy.
+//
+// @param	aName	the name to be translated into DNS format
+// @return
+//	@li		KErrNone, if translation succeeded
+//	@li		KErrNotSupported, if translation failed
+*/
+TInt TDndName::SetName(const THostName &aName)
+	{
+#ifdef SYMBIAN_DNS_PUNYCODE
+	/* The UTF-16 encoded domain names are not supported irrespective
+	 * of whether the IDN support is enable or not.
+	 */ 
+	 
+	TBool isNameIDN= EFalse;
+	TUint8 nameLen = aName.Length();
+	for (TUint8 idxCounter = 0;  idxCounter < nameLen;  idxCounter++)
+		{
+		const TUint16 currVal = aName[idxCounter];
+		if (currVal >= 0x80 )
+			{
+			if(ISUTF16(currVal))
+				{
+				return KErrDndBadName; // UTF-16 encoding is currently not supported.
+				}
+			isNameIDN = ETrue;
+			}
+		}
+	if(isNameIDN && iIdnEnabled)
+		{
+		TInt err = iPunyCodeName.IdnToPunycode(aName);
+		// Set this to offset any previous setting (if any)
+		iPunyCodeConverted = EFalse; 
+		if (err == KErrNone)
+			{
+			Copy(iPunyCodeName);
+			iPunyCodeConverted = ETrue;
+			}
+		else
+			return KErrDndBadName; // returning error that PunyCode conversion failed.
+		}
+	else
+		{
+#endif
+		Copy(aName);
+#ifdef SYMBIAN_DNS_PUNYCODE
+		}
+#endif //SYMBIAN_DNS_PUNYCODE
+	//
+
+	// Eliminate single trailing '.', if present
+
+	const TInt index = Length() - 1;
+	if (index >= 0 && (*this)[index] == '.')
+		SetLength(index);
+
+	return KErrNone;
+	}
+
+// TDndName::GetName
+// *****************
+// Get name into buffer
+/**
+// This is reverse of the SetName and translates DNS name
+// into system specific encoding.
+//
+// This function behaves like a "copy", if aStart = 0 (the default),
+// or "append", if aStart = aName.Length().
+//
+// @retval	aName
+//		receives the translated name. The length of the
+//		buffer is determined by the end of the translated
+//		name.
+// @param	aStart	a start offset for the name
+// @return
+//	@li		KErrNone, if translation succeeded
+//	@li		KErrDndNameTooBig, name does not fit the buffer
+*/
+TInt TDndName::GetName(TDes &aBuf, const TInt aStart) const
+	{
+
+#ifdef SYMBIAN_DNS_PUNYCODE
+
+	TPunyCodeDndName tempPunycodeName(iPunyCodeName);
+	TInt checkPrefix = tempPunycodeName.Find(KAcePrefix());
+
+	if( checkPrefix  != KErrNotFound && iPunyCodeConverted && iIdnEnabled)
+		{
+		TInt err = tempPunycodeName.PunycodeToIdn(aBuf,aStart);
+		if (err == KErrNone)
+			{
+			const TInt punycodeLength = tempPunycodeName.Length();
+			if (aStart + punycodeLength > aBuf.MaxLength())
+				{
+				return KErrDndNameTooBig;
+				}
+
+			aBuf.SetLength(aStart + punycodeLength);
+
+			TUint8 nameLen = aBuf.Length();
+			
+			for (TUint8 idxCounter = aStart;  idxCounter < nameLen;  idxCounter++)
+				{
+				const TUint16 currVal = aBuf[idxCounter];
+				if (currVal >= 0x80 && ISUTF16(currVal))
+					{
+					// UTF-16 encoding is not supported. 
+					// so copying the punycode as it is.
+					for (TInt i = 0; i < punycodeLength; ++i)
+						{
+						aBuf[aStart+i] = (TText)((tempPunycodeName)[i]);
+						}
+					return err;
+					}
+				}
+
+			return err;
+			}
+		else
+			{
+			return KErrDndBadName; // returning error that PunyCode conversion failed.
+			}
+		}
+		else
+			{
+#endif //SYMBIAN_DNS_PUNYCODE	
+	const TInt N = Length();
+	if (aStart + N > aBuf.MaxLength())
+		return KErrDndNameTooBig;
+
+	aBuf.SetLength(aStart + N);
+	for (TInt i = 0; i < N; ++i)
+		aBuf[aStart+i] = (TText)((*this)[i]);
+	return KErrNone;
+#ifdef SYMBIAN_DNS_PUNYCODE	
+			}
+#endif //SYMBIAN_DNS_PUNYCODE
+
+}
+
+// TDndName::GetAddress
+// ********************
+/**
+// This is reverse of SetName with TInetAddr and translates
+// the content of *.ip6.arpa or *.in-addr.arpa into TInetAddr,
+// if the address is complete.
+//
+// @retval aAddr The address, if conversion is possible
+// @return TRUE, if conversion was possible, and FALSE otherwise.
+*/
+TBool TDndName::GetAddress(TInetAddr &aAddr) const
+	{
+	TInt k;
+	TLex8 decode(*this);
+
+	// Initialize to V4 mapped format, so that it is ready
+	// to be "patched" with IPv4 address. If the address
+	// is IPv6, all of the address will be overwritten.
+	TIp6Addr addr = {{{0,0,0,0,0,0,0,0,0,0,0xff,0xff,0,0,0,0}}};
+
+	if ((k = Find(KIPv4AddrToHost)) >= 0)
+		{
+		if (k + KIPv4AddrToHost().Length() != Length())
+			return FALSE;
+		for (TInt i = sizeof(addr); --i >= (TInt)(sizeof(addr) - 4); )
+			{
+			// Note: the check is loose on extra leading zeroes
+			// (which should not be present, but are accepted
+			// here).
+			TUint32 octet;
+			if (decode.Val(octet, EDecimal, 255) != KErrNone)
+				return FALSE;	// Too large value
+			if (decode.Get() != '.')
+				return FALSE;
+			addr.u.iAddr8[i] = (TUint8)octet;
+			}
+		}
+	else if ((k = Find(KIPv6AddrToHost)) >= 0)
+		{
+		if (k + KIPv6AddrToHost().Length() != Length())
+			return FALSE;
+		TInt j = sizeof(addr);
+		for (TUint i = 0; i < sizeof(addr)*2; ++i)
+			{
+			// Note: the check is loose on extra leading zeroes
+			// (which should not be present, but are accepted
+			// here).
+			TUint32 nibble;
+			if (decode.Val(nibble, EHex, 0xF) != KErrNone)
+				return FALSE;
+			if (decode.Get() != '.')
+				return FALSE;
+			if (i & 1)
+				{
+				// high nibble (always after low nibble, just OR high bits in)
+				addr.u.iAddr8[j] |= (TUint8)(nibble << 4);
+				}
+			else
+				{
+				ASSERT(j > 0);
+				// low nibble (this will happen first)
+				j -= 1;
+				addr.u.iAddr8[j] = (TUint8)nibble;
+				}
+			}
+		}
+	// The decoding must eat everything upto in-addr.arpa or ip6.arpa!
+	if (decode.Offset() != k+1)
+		return FALSE;
+	aAddr.SetAddress(addr);
+	return TRUE;
+	}
+
+
+// Creating TDndQuestion from the question section of the UDP message. The question
+// section starts at position 'aIndex' of the buffer 'aBuf'. The function returns the
+// offset pointing over the question section on return (or error).
+//
+// Returns
+//	> 0, the offset pointing over the question section
+//	< 0, an error is detected
+//
+TInt TDndQuestion::Create(const TMsgBuf &aBuf, TInt aIndex)
+	{
+	Zero();
+	TInt i = aBuf.GetNextName(aIndex, *this);
+	if (i > 0)
+		{
+		if (aBuf.Length() < i + 4)
+			return KErrDndDiscard;
+
+		iQType = EDnsQType((aBuf[i] << 8) | aBuf[i+1]);
+		iQClass = EDnsQClass((aBuf[i+2] << 8) | aBuf[i+3]);
+		i += 4;
+		}
+	return i;
+	}
+
+
+// TDndQuestion::Append(aMsgBuf, aFlags)
+// *************************************
+// Append a Question section to aMsgBuf 
+/**
+//
+// @retval	aMsgBuf	the DNS message to be modified
+// @param	aCompressed
+//		value of is used to convey whether the name contains a full name or only
+//		a prefix part.
+//	@li	= 0,
+//		the name is full name
+//	@li > 0,
+//		the name is only a prefix to the name already stored in to the
+//		message start at this offset.
+// @returns
+//	@li	KErrNone
+//		if question section appended succesfully
+//	@li	KErrDndNameTooBig,
+//		if question does not fit the message buffer
+//	@li	KErrBadName,
+//		if name is invalid, e.g. has empty or too long (> 63)
+//		components
+//	@li	KErrDndUnknown
+//		if aFlags is illegal, not in [0..Length()-1]
+*/
+TInt TDndQuestion::Append(TMsgBuf& aMsgBuf, TUint aCompressed) const
+	{
+	const TInt err = aMsgBuf.AppendName(*this, aCompressed);
+	if (err != KErrNone)
+		return err;
+
+	if (aMsgBuf.MaxLength() < aMsgBuf.Length() + 4)
+		return KErrDndNameTooBig;
+
+	// Append the QType
+	aMsgBuf.Append((TChar)(iQType / 0x100));
+	aMsgBuf.Append((TChar)(iQType % 0x100));
+
+	// Append the QClass
+	aMsgBuf.Append((TChar)(iQClass / 0x100));
+	aMsgBuf.Append((TChar)(iQClass % 0x100));
+	return KErrNone;
+	}
+
+
+// TDndQuestion::CheckQuestion
+// ***************************
+/**
+// Compares the name, query type and query class.
+//
+// @param aQuestion	to be compared with
+// @returns
+//	@li	KErrNone, if questions are equal
+//	@li	KErrDndDiscard, if questions are not equal
+*/
+TInt TDndQuestion::CheckQuestion(const TDndQuestion &aQuestion) const
+	{
+	return
+		(
+		aQuestion.iQClass == iQClass &&
+		aQuestion.iQType == iQType &&
+		DnsCompareNames(*this, aQuestion)) ? KErrNone : KErrDndDiscard;
+	}
+
+
+// TDndRR::GetSockAddr
+// *******************
+/**
+// @retval	aName contains the resulting name, if return is OK
+// @param	aOffset	to the start of name, relative to the RDATA
+// @returns	offset pointing to next octet after the extracted value (this
+//			offset is relative to the DNS message start). Negative returns
+//			are error returns.
+*/
+TInt TDndRR::GetSockAddr(TInetAddr& aSockAddr) const
+	{
+	if (iType == EDnsType_A && iClass == EDnsClass_IN && iRdLength == 4)
+		{
+		const TUint32 KInetAddr = INET_ADDR(iBuf[iRd+0], iBuf[iRd+1], iBuf[iRd+2], iBuf[iRd+3]);
+		aSockAddr.SetAddress(KInetAddr);
+		return iRd + 4;
+		}
+
+	else if(iType == EDnsType_AAAA && iClass == EDnsClass_IN)
+		{
+		if (iRdLength < sizeof(TIp6Addr))
+			return KErrDndUnknown;
+		// TIp6Addr byteorder is network order, so can just copy
+		// bytes as is from the resource data... but, as RR is
+		// not necessarily aligned properly, must use a temporary
+		// address buffer for the transfer..
+		TIp6Addr addr;
+		Mem::Copy(addr.u.iAddr8, &iBuf[iRd], sizeof(addr.u.iAddr8));
+		aSockAddr.SetAddress(addr);
+		return iRd + sizeof(addr.u.iAddr8);
+		}
+	return KErrDndUnknown;
+	}
+
+
+// TDndRR::GetNameFromRDATA
+// ************************
+/**
+//
+// @retval	aName contains the extracted domain name.
+// @param	aOffset	to the start of the name, relative to the RDATA
+// @returns	offset pointing to next octet after the extracted value (this
+//			offset is relative to the DNS message start). Negative returns
+//			are error returns.
+*/
+TInt TDndRR::GetNameFromRDATA(TDes8 &aName, TUint aOffset) const
+	{
+//	return aName.SetName(iBuf, iRd + aOffset);
+	aName.Zero();
+	return iBuf.GetNextName(iRd + aOffset, aName);
+	}
+
+// TDndRR::GetStringFromRDATA
+// **************************
+/**
+// @retval	aString
+//		is set to point to the string content in the message buffer.
+//		No copying occurs, the message buffer must exist when this
+//		return value is used!
+// @param	aOffset	to the start of the character string, relative to the RDATA
+// @returns	offset pointing to next octet after the extracted value (this
+//			offset is relative to the DNS message start). Negative returns
+//			are error returns.
+*/
+TInt TDndRR::GetStringFromRDATA(TPtrC8 &aString, TUint aOffset) const
+	{
+	return iBuf.GetNextString(iRd + aOffset, aString);
+	}
+
+// Return TUint16 from a buffer
+static TUint16 Get16(const TUint8 *p)
+	{
+	return (TUint16)(p[0] << 8 | p[1]);
+	}
+// Return TUint32 from a buffer
+static TUint32 Get32(const TUint8 *p)
+	{
+	return (TUint32)(p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]);
+	}
+
+// TDndRR::GetResponse
+// *******************
+// Extract content of RR
+//
+/**
+// What exactly is returned, depends on the type of the RR (A, AAAA, CNAME and
+// PTR return "normal" results, for others some special values may returned,
+// see TInetDnsRR).
+//
+// @retval	aName	normally the domain name (system encoding)
+// @retval	aAddr	normally the address (but, also see TInetDnsRR)
+// @returns	KErrNone if extraction succeeded, and error otherwise.
+*/
+TInt TDndRR::GetResponse(TDes &aName, TInetAddr &aAddr) const
+	{
+	TInt err = iName;	// (just to inialize, to offset of this RR record)
+	TDndName name;
+#ifdef SYMBIAN_DNS_PUNYCODE
+		name.EnableIdn(iIdnEnabled);
+#endif //SYMBIAN_DNS_PUNYCODE
+
+	if ((iType == EDnsType_A || iType == EDnsType_AAAA) && iClass == EDnsClass_IN)
+		{
+		err = name.SetName(iBuf, iName);
+		if (err < 0)
+			return err;
+		err = GetSockAddr(aAddr);
+		}
+	else  if (iType == EDnsType_PTR && iClass == EDnsClass_IN)
+		{
+		//
+		// For the PTR record, it is assumed the aAddr is already
+		// initialized to the original queried address (do not
+		// try to recompute address from the name part of the
+		// PTR record -- that is *NOT* always the address due
+		// to some CNAME games for the PTR records... -- msa)
+		//
+		// ..and get the real name from RData.
+		err = GetNameFromRDATA(name);
+		}
+	else if (iType == EDnsType_CNAME && iClass == EDnsClass_IN)
+		{
+		aAddr.SetAddress(0);
+		// ..and get the cname from RDATA
+		err = GetNameFromRDATA(name);
+		}
+	else
+		{
+		//
+		// Special RR values
+		//
+		TInetDnsRR::Cast(aAddr) = TInetDnsRR();
+		SDnsRR &rr = TInetDnsRR::Cast(aAddr).RR();
+		rr.iClass = (TUint16)iClass;
+		rr.iType = (TUint16)iType;
+		if (iClass == EDnsClass_IN)
+			{
+			const TUint8 *const rd = iBuf.Ptr() + iRd;
+			//
+			// Only a select subset of RR's are supported
+			//
+			if (iType == EDnsType_SRV && iRdLength > 4)
+				{
+				rr.iSRV.iPriority = Get16(rd);
+				rr.iSRV.iWeight = Get16(rd + 2);
+                aAddr.SetPort(Get16(rd + 4));
+				err = GetNameFromRDATA(name, 6);
+				}
+			else if (iType == EDnsType_NAPTR && iRdLength > 7)
+				{
+				rr.iNAPTR.iOrder = Get16(rd);
+				rr.iNAPTR.iPreference = Get16(rd + 2);
+				// get FLAGS
+				TPtrC8 flags;
+				err = GetStringFromRDATA(flags, 4);
+				if (err < 0)
+					return err;
+				TInt flagLength = sizeof(rr.iNAPTR.iFlags);
+				//The buffer size of TInetAddr(0x20 bytes) may not be sufficient to store the 
+				//realtime length(upto 0xFF) of FLAGS field, so it is limited to 12 bytes. Hence if the 
+				//flag length is more than 12 bytes, error KErrDndNameTooBig is raised.
+				if(flagLength < (err - iRd - 5))
+					return KErrDndNameTooBig;
+				TPtr8 rr_flags(rr.iNAPTR.iFlags, flagLength , flagLength);
+				rr_flags.FillZ();
+				rr_flags = flags;
+
+				// get SERVICES
+				TPtrC8 services;
+				err = GetStringFromRDATA(services, err - iRd);
+				if (err < 0)
+					return err;
+				// get REGEXP
+				TPtrC8 regexp;
+				err = GetStringFromRDATA(regexp, err - iRd);
+				if (err < 0)
+					return err;
+				// Fetch REPLACEMENT
+				err = GetNameFromRDATA(name, err - iRd);
+				if (err < 0)
+					return err;
+
+				// Try to append SERVICES and REGEXP into name
+				TInt length = name.Length() + services.Length() + regexp.Length();
+				if (length > name.MaxLength())
+					return KErrDndNameTooBig;
+				// ***** WARNING ********
+				// The iL1 and iL2 will be problematic if the future
+				// UNICODE conversion of the name is not 1 to 1!
+				// Should use separators instead? -- msa
+				rr.iNAPTR.iL1 = (TUint8)name.Length();
+				rr.iNAPTR.iL2 = (TUint8)services.Length();
+				name.Append(services);
+				name.Append(regexp);
+				}
+			else if (iType == EDnsType_MX && iRdLength > 2)
+				{
+				rr.iMX.iPreference = Get16(rd);
+				err = GetNameFromRDATA(name, 2);
+				}
+			else if (iType == EDnsType_NS)
+				{
+				err = GetNameFromRDATA(name);
+				}
+			else if (iType == EDnsType_SOA)
+				{
+				err = GetNameFromRDATA(name);
+				if (err < 0)
+					return err;
+				if (name.Length() == name.MaxLength())
+					return KErrDndNameTooBig;
+				name.Append('@');
+				err = iBuf.GetNextName(err, name);// *APPEND* RNAME to hostname!
+				if (err < 0)
+					return err;
+
+				err -= iRd;
+				if (err < 0 || err + 20 > (TInt)iRdLength)
+					return KErrDndUnknown;
+				rr.iSOA.iSerial = Get32(rd+err);
+				rr.iSOA.iRefresh = Get32(rd+err+4);
+				rr.iSOA.iRetry = Get32(rd+err+8);
+				rr.iSOA.iExpire = Get32(rd+err+12);
+				rr.iSOA.iMinimum = Get32(rd+err+16);
+				}
+			}
+		}
+	return err > 0 ? name.GetName(aName) : err;
+	}
+
+#ifndef NO_DNS_QUERY_SUPPORT
+// TDndRR::GetResponse
+// *******************
+// Extract content of RR
+//
+/**
+// What exactly is returned, depends on the type of the RR
+//
+// @retval	aAnswer	the "payload" will receive the RR content in TDnsQryRespBase format
+// @retval	aAddr a pointer to "TInetAddr *" within the reply (only for A and AAAA, NULL otherwise)
+// @returns	offset pointing to next octet after the extracted value (this
+//			offset is relative to the DNS message start). Negative returns
+//			are error returns.
+*/
+TInt TDndRR::GetResponse(TDnsMessageBuf &aAnswer, TInetAddr **aAddr) const
+	{
+	TInt err = KErrNotSupported;
+	const TInt max_len = aAnswer.MaxLength() - aAnswer().HeaderSize();
+	TInt len = 0;
+	*aAddr = NULL;
+
+	const TUint8 *const rd = iBuf.Ptr() + iRd;
+
+	switch ((TUint16)iType)
+		{
+		case KDnsRRTypeA:
+			{
+			TDndRespA &a = aAnswer().A();
+			len = sizeof(a);
+			if (len > max_len)
+				return KErrOverflow;
+			(void)new (&a) TDndRespA();
+			err = GetSockAddr(a.HostAddress());
+			*aAddr = &a.HostAddress();
+			}
+			break;
+		case KDnsRRTypeAAAA:
+			{
+			TDndRespAAAA &aaaa = aAnswer().AAAA();
+			len = sizeof(aaaa);
+			if (len > max_len)
+				return KErrOverflow;
+			(void)new (&aaaa) TDndRespAAAA();
+			err = GetSockAddr(aaaa.HostAddress());
+			*aAddr = &aaaa.HostAddress();
+			}
+			break;
+#if 0
+		case KDnsRRTypeNS:
+			{
+			TDndRespNS &ns = aAnswer().NS();
+			len = sizeof(ns);
+			if (len > max_len)
+				return KErrOverflow;
+			(void)new (&ns) TDndRespNS();
+			err = GetNameFromRDATA(ns.HostName());
+			}
+			break;
+		case KDnsRRTypeCNAME:
+			break;
+		case KDnsRRTypeWKS:
+			break;
+#endif
+		case KDnsRRTypePTR:
+			{
+			TDndRespPTR &ptr = aAnswer().PTR();
+			len = sizeof(ptr);
+			if (len > max_len)
+				return KErrOverflow;
+			(void)new (&ptr) TDndRespPTR();
+			err = GetNameFromRDATA(ptr.HostName());
+			}
+			break;
+#if 0
+		case KDnsRRTypeHINFO:
+			break;
+#endif
+		case KDnsRRTypeMX:
+			if (iRdLength > 2)
+				{
+				TDndRespMX &mx = aAnswer().MX();
+				len = sizeof(mx);
+				if (len > max_len)
+					return KErrOverflow;
+				(void)new (&mx) TDndRespMX();
+				mx.SetPref(Get16(rd));
+				err = GetNameFromRDATA(mx.HostName(), 2);
+				}
+			else
+				err = KErrDndUnknown;
+			break;
+#if 0
+		case KDnsRRTypeTXT:
+			break;
+#endif
+		case KDnsRRTypeSRV:
+			if (iRdLength > 4)
+				{
+				TDndRespSRV &srv = aAnswer().SRV();
+				len = sizeof(srv);
+				if (len > max_len)
+					return KErrOverflow;
+				(void)new (&srv) TDndRespSRV();
+				srv.SetPriority(Get16(rd));
+				srv.SetWeight(Get16(rd + 2));
+				srv.SetPort(Get16(rd + 4));
+				err = GetNameFromRDATA(srv.Target(), 6);
+				}
+			else
+				err = KErrDndUnknown;
+			break;
+		case KDnsRRTypeNAPTR:
+			if (iRdLength > 7)
+				{
+				TDndRespNAPTR &naptr = aAnswer().NAPTR();
+				len = sizeof(naptr);
+				if (len > max_len)
+					return KErrOverflow;
+				(void)new (&naptr) TDndRespNAPTR();
+				naptr.SetOrder(Get16(rd));
+				naptr.SetPref(Get16(rd + 2));
+				// get FLAGS
+				TPtrC8 flags;
+				err = GetStringFromRDATA(flags, 4);
+				if (err < 0)
+					break;
+				naptr.SetFlags(flags);
+				// get SERVICES
+				TPtrC8 services;
+				err = GetStringFromRDATA(services, err - iRd);
+				if (err < 0)
+					break;
+				naptr.SetService(services);
+				// get REGEXP
+				TPtrC8 regexp;
+				err = GetStringFromRDATA(regexp, err - iRd);
+				if (err < 0)
+					break;
+				naptr.SetRegexp(regexp);
+				// Fetch REPLACEMENT
+				err = GetNameFromRDATA(naptr.Replacement(), err - iRd);
+				}
+			else
+				err = KErrDndUnknown;
+			break;
+#if 0
+		case EDnsType_SOA:
+			{
+			TDndRespSOA &soa = aAnswer().SOA();
+			len = sizeof(soa);
+			if (len > max_len)
+				return KErrOverflow;
+			new (&soa) TDndRespSOA();
+
+			err = GetNameFromRDATA(soa.MName());
+			if (err < 0)
+				return err;
+			err = GetNameFromRDATA(soa.RName(), err - iRd);
+			if (err < 0)
+				return err;
+
+			const TInt i = err - iRd;
+			if (i < 0 || i + 20 > (TInt)iRdLength)
+				return KErrDndUnknown;
+			soa.SetSerial(Get32(rd+i));
+			soa.SetRefresh(Get32(rd+i+4));
+			soa.SetRetry(Get32(rd+i+8));
+			soa.SetExpire(Get32(rd+i+12));
+			soa.SetMininum(Get32(rd+i+16));
+			}
+			break;
+#endif
+		default:
+			// For all yet unsupported replies, return only
+			// the basic reply: TDnsQryRespBase
+			{
+			TDndReply &basic = aAnswer().Reply();
+			len = sizeof(basic);
+			if (len > max_len)
+				return KErrOverflow;
+			(void)new (&basic) TDndReply((TUint16)iType, (TUint16)iClass);
+			basic.SetRRTtl(iTTL);
+			}
+			break;
+		}
+	aAnswer.SetLength(len + aAnswer().HeaderSize());
+	// Return the TTL
+	aAnswer().Reply().SetRRTtl(iTTL);
+	return err;
+	}
+#endif
+
+//
+// TDndRR::FindRR
+// **************
+// Locate Nth (aNext) RR entry from the message
+//
+/**
+// The RR's are "virtually" numbered from 0 to aNumRR-1.
+// All RR's matching the original query are numbered
+// first, and all others follow them.
+//
+// @param	aOffset	from the start of the message to the beginning of the RR section
+// @param	aNumRR	the number of the RR's in this section
+// @param	aType	the original query type
+// @param	aClass	the original query class
+// @param	aNext	select the Nth RR to be returned [0..aNumRR-1]
+// @returns
+// @li	> 0, Nth resource entry located (value is offset to first octet following this RR)
+// @li	< 0, the following errors:
+// @li	KErrDndNoRecord, there was no Nth RR.
+// @li	KErrDndCache, the message is corrupt and should be discarded
+// @li	Never returns 0 (KErrNone)!
+*/
+TInt TDndRR::FindRR(TInt aOffset, TInt aNumRR, EDnsQType aType, EDnsQClass aClass, TInt aNext)
+	{
+	TInt count = 0;
+
+	aNext++;	// Looking for this! (internally numbered from 1..n)
+	for (TInt any = 0;; any = 1)
+		{
+		TInt offset = aOffset;		// Start from beginning of RR's
+
+		for (TInt j = 0; j < aNumRR; j++)
+			{
+			iName = offset;
+			offset = iBuf.GetRR(iName, iType, iClass, iTTL, iRd, iRdLength);
+			if (offset < 0)
+				// ..if the above Resource() access fails (-1), then the stored cache
+				// record must be corrupt, indicate so to the caller...
+				return KErrDndCache;
+			if (EDnsQType(iType) == aType && EDnsQClass(iClass) == aClass)
+				// on first pass (any == 0), only count exact matches
+				count += any ? 0 : 1;
+			else
+				// on second pass (any == 1), only count non-matches (CNAMES, etc.)
+				count += any ? 1 : 0;
+			if (count == aNext)
+				{
+				// Found the target RR
+				return offset;
+				}
+			}
+		// exit, if second pass completed!
+		if (any != 0)
+			break;
+		}
+	//
+	// No matching entry located
+	//
+	return KErrDndNoRecord;
+	}
+
+/**
+// The RR's are numbered from 0 to aNumRR-1.
+// @param	aOffset	from the start of the message to the first RR to be tested
+// @param	aNumRR	the number of the RR's
+// @param	aType	the query type
+// @param	aClass	the query class (EDnsQClass_ANY matches any class)
+// @retval	aStart	the first RR to test [0..aNumRR-1]
+// @returns
+// @li	> 0, Nth resource entry located (value is offset to first octet following this RR)
+// @li	< 0, the following errors:
+// @li	KErrDndNoRecord, there was no such RR
+// @li	KErrDndCache, the message is corrupt and should be discarded
+// @li	Never returns 0 (KErrNone)!
+*/
+TInt TDndRR::LocateRR(TInt aOffset, TInt aNumRR, EDnsQType aType, EDnsQClass aClass, TInt aStart)
+	{
+	for (TInt j = 0; j < aNumRR; j++)
+		{
+		iName = aOffset;
+		aOffset = iBuf.GetRR(iName, iType, iClass, iTTL, iRd, iRdLength);
+		if (aOffset < 0)
+			// ..if the above Resource() access fails (-1), then the stored cache
+			// record must be corrupt, indicate so to the caller...
+			return KErrDndCache;
+		if (j >= aStart && EDnsQType(iType) == aType && (EDnsQClass(aClass) == EDnsQClass_ANY || EDnsQClass(iClass) == aClass))
+			{
+			// The object has been located
+			return aOffset;
+			}
+		}
+	//
+	// No matching entry located
+	//
+	return KErrDndNoRecord;
+	}
+
+#ifdef LLMNR_ENABLED
+
+/**
+// Append a new RR
+//
+// This will append a new complete RR (with empty RDATA, RDLENGTH = 0)
+// to the message buffer.
+//
+// @param	aName
+//		content of the NAME field
+// @param	aCompression
+//		if non-zero, the name portion indicated by this
+//		offset will be logically conctenated into the
+//		NAME field.
+// @returns
+//	@li	KErrNone, on success
+//	@li	KErrDndNameTooBig, when RR does not fit into the buffer
+*/
+TInt TDndRROut::Append(const TDesC8 &aName, TInt aCompression)
+	{
+	// Append the NAME
+	TInt ret = iBuf.AppendName(aName, aCompression);
+	if (ret != KErrNone)
+		return ret;
+
+	// Available space after fixed portion of the RR (after RDLENGTH)
+	// has been appended.
+	const TInt room = iBuf.MaxLength() - iBuf.Length() - 10;
+	if (room < 0)
+		return KErrDndNameTooBig; // Oops.. cannot fit RR into message (a bit dubious error code)
+
+	// Append the TYPE
+	iBuf.Append((TChar)(iType / 0x100));
+	iBuf.Append((TChar)(iType % 0x100));
+
+	// Append the CLASS
+	iBuf.Append((TChar)(iClass / 0x100));
+	iBuf.Append((TChar)(iClass % 0x100));
+
+	// Append the TTL
+	iBuf.Append((TChar)(iTTL / 0x1000000));
+	iBuf.Append((TChar)((iTTL / 0x10000) % 0x100));
+	iBuf.Append((TChar)((iTTL / 0x100) % 0x100));
+	iBuf.Append((TChar)(iTTL % 0x100));
+
+	// Append the RDLENGTH (placeholder)
+
+	iBuf.Append((TChar)(0));
+	iBuf.Append((TChar)(0));
+
+	iRd = iBuf.Length();
+	return KErrNone;
+	}
+
+
+/**
+// Extend the RR with address RDATA
+//
+// This will append address RDATA the Resource Record.
+// Only types AAAA or A are supported, and the length
+// and format of the RDATA is selected accordingly.
+//
+// @param	aAddr	specifies the address to be appended
+//
+// @returns
+//	@li	KErrNone, on success
+//	@li	KErrDndNameTooBig, when RR does not fit into the buffer
+//	@li KErrDndNotImplemented, if RR type is not A or AAAA.
+*/
+TInt TDndRROut::AppendRData(const TInetAddr &aAddr) const
+	{
+	const TInt room = iBuf.MaxLength() - iBuf.Length();
+
+	if (iType == EDnsType_A)
+		{
+		if (room < 4)
+			return KErrDndNameTooBig; // Oops.. cannot fit RR into message (a bit dubious error code)
+		TUint32 address = aAddr.Address();
+		iBuf.Append((TChar)(address >> 24));
+		iBuf.Append((TChar)(address >> 16));
+		iBuf.Append((TChar)(address >> 8));
+		iBuf.Append((TChar)address);
+		}
+	else if(iType == EDnsType_AAAA)
+		{
+		// assumes aAddr is in KAfInet6 format!!!
+		const TIp6Addr &address = aAddr.Ip6Address();
+		if (room < (TInt)sizeof(address.u.iAddr8))
+			return KErrDndNameTooBig; // Oops.. cannot fit RR into message (a bit dubious error code)
+		iBuf.Append(address.u.iAddr8, sizeof(address.u.iAddr8));
+		}
+	else
+		return KErrDndNotImplemented;
+
+	AppendRData();
+	return KErrNone;
+	}
+
+/**
+// Extend the RR with domain name
+//
+// This will append domain name RDATA the Resource Record.
+//
+// @param	aName
+//		the domain name to be added
+// @param	aCompression
+//		if non-zero, the name portion indicated by this
+//		offset will be logically conctenated into aName.
+//
+// @returns
+//	@li	KErrNone, on success
+//	@li	KErrDndNameTooBig, when RR does not fit into the buffer
+*/
+TInt TDndRROut::AppendRData(const TDesC8 &aName, TInt aCompression) const
+	{
+
+	TInt ret = iBuf.AppendName(aName, aCompression);
+
+	AppendRData();
+	return ret;
+	}
+
+/**
+// Extend the RR with any binary data
+//
+// This will append binary data into the Resource Record.
+// (just a convenience method, which provides length checking
+// and implicitly calls AppendRData())
+//
+// @param	aRData	the data to be appended
+//
+// @returns
+//	@li	KErrNone, on success
+//	@li	KErrDndNameTooBig, when RR does not fit into the buffer
+*/
+TInt TDndRROut::AppendRData(const TDesC8 &aRData) const
+	{
+	const TInt room = iBuf.MaxLength() - iBuf.Length();
+	if (room < aRData.Length())
+		return KErrDndNameTooBig;
+	iBuf.Append(aRData);
+
+	AppendRData();
+	return KErrNone;
+	}
+
+/**
+//	Update the RDLENGTH to match the current appended data
+//
+//	Assume Recource Record is complete and compute
+//	the total amount RDATA that has been appended.
+//
+//	This can be called any number of times. 
+*/
+void TDndRROut::AppendRData() const
+	{
+	// Append(..) must have been called before this!
+	__ASSERT_DEBUG(iRd > 1, User::Panic(_L("DEBUG"), 0));
+	// Patch in the RD lenght
+	const TInt length = iBuf.Length() - iRd;
+	iBuf[iRd-2] = (TUint8)(length / 0x100);
+	iBuf[iRd-1] = (TUint8)(length % 0x100);
+	}
+
+#endif