--- /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