tcpiputils/dnd/src/message.cpp
changeset 0 af10295192d8
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // message.cpp - name resolver DNS message interpreter
       
    15 //
       
    16 
       
    17 #include <dns_qry.h>
       
    18 #include "res_sock.h"
       
    19 #include "message.h"
       
    20 #include <networking/dnd_err.h>
       
    21 #include "dns_ext.h"
       
    22 
       
    23 #ifdef EXCLUDE_SYMBIAN_DNS_PUNYCODE
       
    24 #undef SYMBIAN_DNS_PUNYCODE
       
    25 #endif //EXCLUDE_SYMBIAN_DNS_PUNYCODE
       
    26 
       
    27 // Constants
       
    28 
       
    29 _LIT8(KIPv4AddrToHost, ".in-addr.arpa");
       
    30 #ifdef DNS_REVERSE_IP6_INT
       
    31 _LIT8(KIPv6AddrToHost, ".ip6.int");
       
    32 #else
       
    33 _LIT8(KIPv6AddrToHost, ".ip6.arpa");
       
    34 #endif
       
    35 
       
    36 #ifdef SYMBIAN_DNS_PUNYCODE 
       
    37 /* This macro is to check whether the character passed is of UTF encoded */
       
    38 #define ISUTF16(x) ((x>= 0xD800 && x<= 0xDFFF)? ETrue : EFalse)
       
    39 #endif //SYMBIAN_DNS_PUNYCODE
       
    40 
       
    41 //
       
    42 // DnsCompareNames
       
    43 // ***************
       
    44 // A global utility function
       
    45 //
       
    46 /**
       
    47 // The DNS domain names have a special case folding rules. The names
       
    48 // are BINARY data (can include anything in range [0..255], but when
       
    49 // comparing two names, ASCII lower and and upper case letters should
       
    50 // compare equal, e.g  A-Z == a-z.
       
    51 //
       
    52 // @param	aName1	to be compared
       
    53 // @param	aName2	to be compared
       
    54 // @returns	TRUE, if names are equal under DNS case folding rules
       
    55 */
       
    56 TBool DnsCompareNames(const TDesC8 &aName1, const TDesC8 &aName2)
       
    57 	{
       
    58 	static const TUint8 KAscii_A = 0x41;
       
    59 	static const TUint8 KAscii_Z = 0x5a;
       
    60 	static const TUint8 KAscii_lower = 0x20;
       
    61 
       
    62 	TInt n = aName1.Length();
       
    63 	if (n != aName2.Length())
       
    64 		return 0;	// not same, lengths differ
       
    65 	//
       
    66 	// Need to do the special "DNS case insensitive" compare
       
    67 	//
       
    68 	const TUint8 *const p = aName1.Ptr();
       
    69 	const TUint8 *const q = aName2.Ptr();
       
    70 	while (--n >= 0)
       
    71 		{
       
    72 		TUint8 x = p[n];
       
    73 		TUint8 y = q[n];
       
    74 		if (x != y)
       
    75 			{
       
    76 			if (x >= KAscii_A && x <= KAscii_Z)
       
    77 				x += KAscii_lower;
       
    78 			if (y >= KAscii_A && y <= KAscii_Z)
       
    79 				y += KAscii_lower;
       
    80 			if (x != y)
       
    81 				return 0;
       
    82 			}
       
    83 		}
       
    84 	return 1;
       
    85 	}
       
    86 
       
    87 
       
    88 //
       
    89 // Initialize TDndHeader
       
    90 //
       
    91 void TDndHeader::Init(const TUint16 aID, const TUint8 aOpcode)
       
    92 	{
       
    93 	// Set ID to aID
       
    94 	i[0] = (TUint8)(aID / 0x0100);
       
    95 	i[1] = (TUint8)(aID % 0x0100);
       
    96 
       
    97 	// Set QR = 0; Opcode = aOpcode; AA = 0; TC = 0; RD = 1
       
    98 	i[2] = 1;
       
    99 	i[2] |= (aOpcode << 3);
       
   100 
       
   101 	// Set RA = 0; Z = 0; RCode = 0
       
   102 	i[3] = 0;
       
   103 
       
   104 	// Set QDCOUNT = 1
       
   105 	i[4] = 0;
       
   106 	i[5] = 1;
       
   107 	
       
   108 	// Set all other counts as zero.
       
   109 	// ANCOUNT = 0;
       
   110 	// NSCOUNT = 0;
       
   111 	// ARCOUNT = 0;
       
   112 	i[6] = 0;
       
   113 	i[7] = 0;
       
   114 	i[8] = 0;
       
   115 	i[9] = 0;
       
   116 	i[10] = 0;
       
   117 	i[11] = 0;
       
   118 	}
       
   119 
       
   120 // to set the ID field of header
       
   121 void TDndHeader::SetId(const TUint16 aID)
       
   122 	{
       
   123 	i[0] = (TUint8)(aID / 0x0100);
       
   124 	i[1] = (TUint8)(aID % 0x0100);
       
   125 	}
       
   126 
       
   127 #ifdef LLMNR_ENABLED
       
   128 // TDndHeader::SetQR() - To set the query/response bit of the header
       
   129 void TDndHeader::SetQR(const TUint aQR)
       
   130     {
       
   131     i[2] |= ((aQR & 0x1) << 7);
       
   132     }
       
   133 #endif
       
   134 
       
   135 // TDndHeader::SetOpcode() - To set the opcode field of the header
       
   136 void TDndHeader::SetOpcode(const TUint8 aOpcode)
       
   137 	{
       
   138 	i[2] |= ((aOpcode & 0xF) << 3);
       
   139 	}
       
   140 
       
   141 #ifdef LLMNR_ENABLED
       
   142 // TDndHeader::SetAA() - To set the authoritative answer bit of the header
       
   143 void TDndHeader::SetAA(const TUint aAA)
       
   144     {
       
   145     i[2] |= ((aAA & 0x1) << 2);
       
   146     }
       
   147 
       
   148 // TDndHeader::SetRCode() - To set the value of RCode field of the header
       
   149 void TDndHeader::SetRCode(const TUint aRCode)
       
   150     {
       
   151     i[3] |= aRCode & 0xF;
       
   152     }
       
   153 #endif
       
   154 
       
   155 // TDndHeader::SetQdCount() - To set the QdCount field
       
   156 void TDndHeader::SetQdCount(const TUint16 aQdCount)
       
   157 	{
       
   158 	i[4] = (TUint8)(aQdCount / 0x0100);
       
   159 	i[5] = (TUint8)(aQdCount % 0x0100);
       
   160 	}
       
   161 
       
   162 
       
   163 // TDndHeader::SetAnCount() - To set the answer count field
       
   164 void TDndHeader::SetAnCount(const TUint16 aAnCount)
       
   165 	{
       
   166 	i[6] = (TUint8)(aAnCount / 0x0100);
       
   167 	i[7] = (TUint8)(aAnCount % 0x0100);
       
   168 	}
       
   169 
       
   170 void TDndHeader::SetArCount(const TUint16 aArCount)
       
   171 	{
       
   172 	i[10] = (TUint8)(aArCount / 0x0100);
       
   173 	i[11] = (TUint8)(aArCount % 0x0100);
       
   174 	}
       
   175 #ifdef SYMBIAN_DNS_PROXY
       
   176 void TDndHeader::SetNsCount(const TUint16 aNsCount)
       
   177 	{
       
   178 	i[8] = (TUint8)(aNsCount / 0x0100);
       
   179 	i[9] = (TUint8)(aNsCount % 0x0100);
       
   180 	}
       
   181 #endif
       
   182 
       
   183 
       
   184 // TMsgBuf::VerifyMessage
       
   185 // **********************
       
   186 /**
       
   187 // Verify basic header fields in the responce.
       
   188 //
       
   189 // @retval aRCode The RCode from the message (if return > 0)
       
   190 // @retval aQuestion The question from the message (if return > 0)
       
   191 //
       
   192 // @return
       
   193 //	@li < 0, if there are any format errors with the message
       
   194 //	@li > 0, offset to the first answer RR after the question section
       
   195 */
       
   196 TInt TMsgBuf::VerifyMessage(TInt &aRCode, TDndQuestion &aQuestion) const
       
   197 	{
       
   198 	// Check that message is actually long enough for the header
       
   199 	// Return length of the fixed header (= offset pointing to next part)
       
   200 	ASSERT(sizeof(TDndHeader) == KDnsMinHeader);
       
   201 	if (Length() < TInt(sizeof(TDndHeader)))
       
   202 		return KErrDndDiscard;
       
   203 
       
   204 	const TDndHeader &hdr = Header();
       
   205 	// ..do some simple insanity tests, and discard if odd things
       
   206 	// detected.
       
   207 	if (hdr.ANCOUNT() < 0)
       
   208 		return KErrDndDiscard;
       
   209 	if (hdr.NSCOUNT() < 0)
       
   210 		return KErrDndDiscard;
       
   211 	if (hdr.ARCOUNT() < 0)
       
   212 		return KErrDndDiscard;
       
   213 
       
   214 	TInt offset = aQuestion.Create(*this, sizeof(TDndHeader));
       
   215 	if (offset > 0)
       
   216 		{
       
   217 		// Question extracted, now we can look for EDNS0 OPT record
       
   218 		// to find the real RCODE...
       
   219 		TDndRR opt_rr(*this);
       
   220 		const TInt start = hdr.ANCOUNT() + hdr.NSCOUNT();
       
   221 		if (opt_rr.LocateRR(offset, start + hdr.ARCOUNT(), EDnsQType_OPT, EDnsQClass_ANY, start) > offset)
       
   222 			{
       
   223 			// OPT RR has been located
       
   224 			// ..return extend RCODE.
       
   225 			aRCode = ((opt_rr.iTTL >> 20) & 0xFF0) | hdr.RCODE();
       
   226 			}
       
   227 		else
       
   228 			{
       
   229 			// NO OPT RR present, RCODE is as it
       
   230 			aRCode = hdr.RCODE();
       
   231 			}
       
   232 		}
       
   233 	return offset;
       
   234 	}
       
   235 
       
   236 
       
   237 // TMsgBuf::GetNextName
       
   238 // ********************
       
   239 /**
       
   240 // @param	aOffset	from the start of the message to the domain name
       
   241 // @retval	aName	receives the extracted domain name (in raw DNS 8bit encoding)
       
   242 // @param	aDepth	("internal" paramater) recursion count to catch looped compression
       
   243 // @returns
       
   244 //	@li > 0, updated offset pointing past the name portion
       
   245 //	@li	< 0, an error was detected
       
   246 */
       
   247 TInt TMsgBuf::GetNextName(TInt aOffset, TDes8 &aName, const TUint aDepth) const
       
   248 	{
       
   249 	TInt tag;
       
   250 	TInt err;
       
   251 
       
   252 	if (aDepth >= KDndMaxLoopCount ||	// Prevent infinite recursion...
       
   253 		aOffset >= Length() ||			// ...offsets beyond the buffer end,
       
   254 		aOffset < 0)					// ...or before buffer start (someone didn't check error return!)
       
   255 		return KErrDndDiscard;
       
   256 
       
   257 	const TUint8 *p = Ptr() + aOffset;
       
   258 
       
   259 	while ((tag = *p) != 0)
       
   260 		{
       
   261 		if ((tag & 0xC0) == 0xC0)
       
   262 			{
       
   263 			if (Length() < aOffset + 2)
       
   264 				return KErrDndDiscard;
       
   265 
       
   266 			const TInt tempOffset = (tag - 0xC0) * 256 + *(p+1);
       
   267 			err = GetNextName(tempOffset, aName, aDepth+1);
       
   268 			if (err < KErrNone)
       
   269 				return err;
       
   270 
       
   271 			p += 2;
       
   272 			aOffset += 2;
       
   273 			break;
       
   274 			}
       
   275 		else
       
   276 			{
       
   277 			p++;
       
   278 			aOffset++;
       
   279 			if (aName.Length() + tag >= aName.MaxLength())
       
   280 				return KErrDndNameTooBig;
       
   281 			if (Length() < aOffset + tag)
       
   282 				return KErrDndUnknown;
       
   283 
       
   284 			aName.Append(TPtrC8(p, tag));
       
   285 			aName.Append('.');
       
   286 			p += tag;
       
   287 			aOffset += tag;
       
   288 			}
       
   289 		}
       
   290 
       
   291 	if (tag == 0)
       
   292 		{
       
   293 		p++;
       
   294 		aOffset++;
       
   295 		// if there is a 'dot' at the end, get rid of it
       
   296 		if (aName.Length() != 0)
       
   297 			aName.Delete(aName.Length() - 1, 1);
       
   298 		}
       
   299 	return aOffset;
       
   300 	}
       
   301 
       
   302 
       
   303 // TMsgBuf::GetNextString
       
   304 // **********************
       
   305 /**
       
   306 // @param	aOffset	from the start of the message to the character string
       
   307 // @retval	aString	receives the extracted string (in raw DNS 8bit encoding). This
       
   308 //			is only a reference to the original DNS message buffer, which must be
       
   309 //			kept around while this is used.
       
   310 // @returns
       
   311 //	@li	> 0, updated offset pointing past extracted string
       
   312 //	@li	< 0, an error was detected
       
   313 */
       
   314 TInt TMsgBuf::GetNextString(TInt aOffset, TPtrC8 &aString) const
       
   315 	{
       
   316 	if (aOffset >= Length())
       
   317 		return KErrDndUnknown;	// corrupt data
       
   318 
       
   319 	const TUint8 *p = Ptr() + aOffset;
       
   320 	//
       
   321 	// Extract <character-string> length
       
   322 	//
       
   323 	TInt length = *p++;
       
   324 	aOffset += length + 1;
       
   325 	if (aOffset > Length())
       
   326 		return KErrDndUnknown;	// corrupt data
       
   327 
       
   328 	aString.Set(p, length);
       
   329 	return aOffset;
       
   330 	}
       
   331 
       
   332 // TMsgBuf::GetName
       
   333 // ****************
       
   334 /**
       
   335 // @param	aOffset	from the start of the message to the start of domain name
       
   336 #ifdef SYMBIAN_DNS_PUNYCODE
       
   337 // @param   aIdnEnabled   
       
   338 #endif
       
   339 // @retval	aName	the extracted domain name (system dependent encoding)
       
   340 // @returns
       
   341 //	@li	> 0, offset updated pointing past the name portion
       
   342 //	@li	< 0, an error was detected
       
   343 */
       
   344 #ifdef SYMBIAN_DNS_PUNYCODE
       
   345 TInt TMsgBuf::GetName(TInt aOffset, TDes &aName,TBool aIdnEnabled) const
       
   346 #else
       
   347 TInt TMsgBuf::GetName(TInt aOffset, TDes &aName) const
       
   348 #endif //SYMBIAN_DNS_PUNYCODE
       
   349 	{
       
   350 	// Use TDndName as temporary buffer. This seemingly
       
   351 	// unnecessary juggling is present because of the potentially
       
   352 	// hairy/complex issues of DNS <-> UNICODE translation. The idea
       
   353 	// is to have one clean location which implements it:
       
   354 	// TDndName::SetName and TDndName::GetName methods.
       
   355 	TDndName tmp;
       
   356 #ifdef SYMBIAN_DNS_PUNYCODE
       
   357 	tmp.EnableIdn(aIdnEnabled);
       
   358 #endif
       
   359 	TInt i = tmp.SetName(*this, aOffset);
       
   360 	if (i < 0)
       
   361 		return i;
       
   362 	TInt err = tmp.GetName(aName);
       
   363 	// This function must return offset when no errors
       
   364 	return err == KErrNone ? i : err;
       
   365 	}
       
   366 
       
   367 // TMsgBuf::AppendName
       
   368 // *******************
       
   369 /**
       
   370 // @param	aName
       
   371 //		domain name to be appended
       
   372 // @param	aCompressed
       
   373 //	@li	= 0,
       
   374 //		the name is assumed to be complete name will be terminated with "root label"
       
   375 //	@li	> 0,
       
   376 //		the name is assumed to be a prefix to another name already stored into the
       
   377 //		message starting at indicated offset.
       
   378 //		The name (prefix) is terminated with a "compression ptr".
       
   379 //		The value must be in range [1..Length()-1].
       
   380 //
       
   381 // @returns
       
   382 //	@li	KErrNone
       
   383 //		if name appended succesfully
       
   384 //	@li	KErrDndNameTooBig,
       
   385 //		if name does not fit the message buffer
       
   386 //	@li	KErrBadName,
       
   387 //		if name is invalid, e.g. has empty or too long (> 63)
       
   388 //		components
       
   389 //	@li	KErrDndUnknown
       
   390 //		if aCompressed is illegal, e.g. not in range [0..Length()-1]
       
   391 */
       
   392 TInt TMsgBuf::AppendName(const TDesC8 &aName, const TUint aCompressed)
       
   393 	{
       
   394 	if (aCompressed >= (TUint)Length())
       
   395 		return KErrDndUnknown; // Don't allow forward references in compression pointers.
       
   396 	// The space requirement
       
   397 	// + length of the iName
       
   398 	// and
       
   399 	//    + 1 (for the terminator NUL byte, root)
       
   400 	//  or
       
   401 	//    + 2 (for the compression pointer)
       
   402 	//	
       
   403 	// [note: if the name already has a trailing '.', the code below
       
   404 	// will handle it, but the spacerequirement computation is too
       
   405 	// large by one byte -- a minor discrepancy, which is
       
   406 	// not worth coding -- msa]
       
   407 	if (Length() + aName.Length() + 1 + (aCompressed > 0) > MaxLength())
       
   408 		return KErrDndNameTooBig;
       
   409 
       
   410 	//
       
   411 	// Append <domain-name> as labels
       
   412 	//
       
   413 	TInt i;
       
   414 	TPtrC8 name(aName);
       
   415 	while ((i = name.Locate('.')) != KErrNotFound)
       
   416 		{
       
   417 		// a valid label contains at least one and at most 63 characters
       
   418 		if (i < 1 || i > 63)
       
   419 			return KErrDndBadName;	// ..abort message build!
       
   420 		Append((TChar)i);
       
   421 		Append(name.Left(i));
       
   422 		name.Set(name.Mid(i+1));		// Skip the dot.
       
   423 		}
       
   424 	i = name.Length();
       
   425 	if (i > 0)
       
   426 		{
       
   427 		// append the last component...
       
   428 		if (i > 63)
       
   429 			return KErrDndBadName;
       
   430 		Append((TChar)i);
       
   431 		Append(name);
       
   432 		}
       
   433 	//
       
   434 	// Append terminator
       
   435 	//
       
   436 	if (!aCompressed)
       
   437 		Append((TChar)0);		//Root
       
   438 	else
       
   439 		{
       
   440 		Append((TChar)((aCompressed / 0x100) | 0xC0));
       
   441 		Append((TChar)(aCompressed % 0x100));
       
   442 		}
       
   443 	return KErrNone;
       
   444 	}
       
   445 
       
   446 // TMsgBuf::GetRR
       
   447 // **************
       
   448 /**
       
   449 // @param aOffset	of the recource record (points to NAME)
       
   450 // @retval aType	RR type
       
   451 // @retval aClass	RR class
       
   452 // @retval aTTL		RR TTL (time to live)
       
   453 // @retval aRD		offset to the beginning of the RDATA
       
   454 // @retval aRDLength	the length of the RDATA
       
   455 //	
       
   456 // @return	offset pointing after the RR.
       
   457 */
       
   458 TInt TMsgBuf::GetRR(const TInt aOffset, TUint16 &aType, TUint16 &aClass, TUint32 &aTTL, TUint &aRd, TUint &aRdLength) const
       
   459 	{
       
   460 	return Header().Resource(aOffset, Length(), aType, aClass, aTTL, aRd, aRdLength);
       
   461 	}
       
   462 
       
   463 TInt TMsgBuf::SkipName(TInt aOffset) const
       
   464 	{
       
   465 	return Header().NameSkip(aOffset, Length());
       
   466 	}
       
   467 
       
   468 
       
   469 // TDndName::SetName
       
   470 // *****************
       
   471 // Set PTR name from address
       
   472 //
       
   473 /**
       
   474 // Translate the address into a query name for the PTR query.
       
   475 // For example 172.21.33.80 -> 80.33.21.172.in-addr.arpa.
       
   476 //
       
   477 // @param	aAddr	the address to be translated into PTR name
       
   478 // @returns
       
   479 //	@li		KErrnone, if translation succeeded
       
   480 //	@li		KErrNotSupported, if translation not supported
       
   481 //			(bad address or unknown address family)
       
   482 */
       
   483 TInt TDndName::SetName(const TInetAddr &aAddr)
       
   484 	{
       
   485  
       
   486 	if (aAddr.Family() == KAfInet ||
       
   487 		aAddr.IsV4Mapped() ||	// V4 Mapped is internal, and always means IPv4
       
   488 		aAddr.IsV4Compat())		// Treating V4 Compatible as IPv4 might be questionable?
       
   489 		{
       
   490 		TUint32 address = aAddr.Address();
       
   491 		if (address == KInetAddrNone)
       
   492 			return KErrNotSupported;
       
   493 	
       
   494 		Format(_L8("%d.%d.%d.%d"),
       
   495 			(TUint8)(address),
       
   496 			(TUint8)(address >> 8),
       
   497 			(TUint8)(address >> 16),
       
   498 			(TUint8)(address >> 24));
       
   499 
       
   500 		Append(KIPv4AddrToHost);
       
   501 		return KErrNone;
       
   502 		}
       
   503 
       
   504 	else if (aAddr.Family() == KAfInet6)	// for IPv6
       
   505 		{
       
   506 		SetLength(0);
       
   507 
       
   508 		const TIp6Addr &address = aAddr.Ip6Address();
       
   509 		// ..are there any addresses that should never be
       
   510 		// PTR queried? unspecified? loopback? anything else?
       
   511 		// Or, should even these tests removed and let the
       
   512 		// query just fail normally? -- msa
       
   513 		if (address.IsUnspecified() ||
       
   514 			address.IsLoopback())
       
   515 			return KErrNotSupported;
       
   516 
       
   517 		for (TInt i = 15; i >= 0; i--)
       
   518 			{
       
   519 			for (TInt j = 0; j < 2; j++)
       
   520 				{
       
   521 				TChar c;
       
   522 				TUint8 digit = (TUint8)((address.u.iAddr8[i] >> (4 * j)) & 0x0f);
       
   523 				if (digit < 10)
       
   524 					c = (TChar)('0' + digit);
       
   525 				else
       
   526 					c = (TChar)('a' + digit - 10);
       
   527 				Append(c);
       
   528 				if (i != 0 || j != 1)
       
   529 					Append('.');
       
   530 				}
       
   531 			}
       
   532 		Append(KIPv6AddrToHost);
       
   533 		return KErrNone;
       
   534 		}
       
   535 	return KErrNotSupported;
       
   536 	}
       
   537 
       
   538 
       
   539 //
       
   540 // TDndName::SetName
       
   541 // *****************
       
   542 /**
       
   543 // Uncompres the <domain-name> from a DNS message into name
       
   544 //
       
   545 // @param	aBuf	buffer containing the DNS message packet
       
   546 // @param	aOffset	from the start of the message to the name
       
   547 // @returns
       
   548 //	@li		> 0, updated offset past the extracted name, if succesful
       
   549 //	@li		< 0, if some error
       
   550 */
       
   551 TInt TDndName::SetName(const TMsgBuf &aBuf, const TInt aOffset)
       
   552 	{
       
   553 	Zero();
       
   554 	return aBuf.GetNextName(aOffset, *this);
       
   555 	}
       
   556 		
       
   557 
       
   558 // TDndName::SetName
       
   559 // *****************
       
   560 // Set name from THostName
       
   561 //
       
   562 /**
       
   563 // Translate system encoding into query name. In Unicode this
       
   564 // means converting the Unicode to equivalent DNS name. For
       
   565 // narrow builds, this is usually a straight copy.
       
   566 //
       
   567 // @param	aName	the name to be translated into DNS format
       
   568 // @return
       
   569 //	@li		KErrNone, if translation succeeded
       
   570 //	@li		KErrNotSupported, if translation failed
       
   571 */
       
   572 TInt TDndName::SetName(const THostName &aName)
       
   573 	{
       
   574 #ifdef SYMBIAN_DNS_PUNYCODE
       
   575 	/* The UTF-16 encoded domain names are not supported irrespective
       
   576 	 * of whether the IDN support is enable or not.
       
   577 	 */ 
       
   578 	 
       
   579 	TBool isNameIDN= EFalse;
       
   580 	TUint8 nameLen = aName.Length();
       
   581 	for (TUint8 idxCounter = 0;  idxCounter < nameLen;  idxCounter++)
       
   582 		{
       
   583 		const TUint16 currVal = aName[idxCounter];
       
   584 		if (currVal >= 0x80 )
       
   585 			{
       
   586 			if(ISUTF16(currVal))
       
   587 				{
       
   588 				return KErrDndBadName; // UTF-16 encoding is currently not supported.
       
   589 				}
       
   590 			isNameIDN = ETrue;
       
   591 			}
       
   592 		}
       
   593 	if(isNameIDN && iIdnEnabled)
       
   594 		{
       
   595 		TInt err = iPunyCodeName.IdnToPunycode(aName);
       
   596 		// Set this to offset any previous setting (if any)
       
   597 		iPunyCodeConverted = EFalse; 
       
   598 		if (err == KErrNone)
       
   599 			{
       
   600 			Copy(iPunyCodeName);
       
   601 			iPunyCodeConverted = ETrue;
       
   602 			}
       
   603 		else
       
   604 			return KErrDndBadName; // returning error that PunyCode conversion failed.
       
   605 		}
       
   606 	else
       
   607 		{
       
   608 #endif
       
   609 		Copy(aName);
       
   610 #ifdef SYMBIAN_DNS_PUNYCODE
       
   611 		}
       
   612 #endif //SYMBIAN_DNS_PUNYCODE
       
   613 	//
       
   614 
       
   615 	// Eliminate single trailing '.', if present
       
   616 
       
   617 	const TInt index = Length() - 1;
       
   618 	if (index >= 0 && (*this)[index] == '.')
       
   619 		SetLength(index);
       
   620 
       
   621 	return KErrNone;
       
   622 	}
       
   623 
       
   624 // TDndName::GetName
       
   625 // *****************
       
   626 // Get name into buffer
       
   627 /**
       
   628 // This is reverse of the SetName and translates DNS name
       
   629 // into system specific encoding.
       
   630 //
       
   631 // This function behaves like a "copy", if aStart = 0 (the default),
       
   632 // or "append", if aStart = aName.Length().
       
   633 //
       
   634 // @retval	aName
       
   635 //		receives the translated name. The length of the
       
   636 //		buffer is determined by the end of the translated
       
   637 //		name.
       
   638 // @param	aStart	a start offset for the name
       
   639 // @return
       
   640 //	@li		KErrNone, if translation succeeded
       
   641 //	@li		KErrDndNameTooBig, name does not fit the buffer
       
   642 */
       
   643 TInt TDndName::GetName(TDes &aBuf, const TInt aStart) const
       
   644 	{
       
   645 
       
   646 #ifdef SYMBIAN_DNS_PUNYCODE
       
   647 
       
   648 	TPunyCodeDndName tempPunycodeName(iPunyCodeName);
       
   649 	TInt checkPrefix = tempPunycodeName.Find(KAcePrefix());
       
   650 
       
   651 	if( checkPrefix  != KErrNotFound && iPunyCodeConverted && iIdnEnabled)
       
   652 		{
       
   653 		TInt err = tempPunycodeName.PunycodeToIdn(aBuf,aStart);
       
   654 		if (err == KErrNone)
       
   655 			{
       
   656 			const TInt punycodeLength = tempPunycodeName.Length();
       
   657 			if (aStart + punycodeLength > aBuf.MaxLength())
       
   658 				{
       
   659 				return KErrDndNameTooBig;
       
   660 				}
       
   661 
       
   662 			aBuf.SetLength(aStart + punycodeLength);
       
   663 
       
   664 			TUint8 nameLen = aBuf.Length();
       
   665 			
       
   666 			for (TUint8 idxCounter = aStart;  idxCounter < nameLen;  idxCounter++)
       
   667 				{
       
   668 				const TUint16 currVal = aBuf[idxCounter];
       
   669 				if (currVal >= 0x80 && ISUTF16(currVal))
       
   670 					{
       
   671 					// UTF-16 encoding is not supported. 
       
   672 					// so copying the punycode as it is.
       
   673 					for (TInt i = 0; i < punycodeLength; ++i)
       
   674 						{
       
   675 						aBuf[aStart+i] = (TText)((tempPunycodeName)[i]);
       
   676 						}
       
   677 					return err;
       
   678 					}
       
   679 				}
       
   680 
       
   681 			return err;
       
   682 			}
       
   683 		else
       
   684 			{
       
   685 			return KErrDndBadName; // returning error that PunyCode conversion failed.
       
   686 			}
       
   687 		}
       
   688 		else
       
   689 			{
       
   690 #endif //SYMBIAN_DNS_PUNYCODE	
       
   691 	const TInt N = Length();
       
   692 	if (aStart + N > aBuf.MaxLength())
       
   693 		return KErrDndNameTooBig;
       
   694 
       
   695 	aBuf.SetLength(aStart + N);
       
   696 	for (TInt i = 0; i < N; ++i)
       
   697 		aBuf[aStart+i] = (TText)((*this)[i]);
       
   698 	return KErrNone;
       
   699 #ifdef SYMBIAN_DNS_PUNYCODE	
       
   700 			}
       
   701 #endif //SYMBIAN_DNS_PUNYCODE
       
   702 
       
   703 }
       
   704 
       
   705 // TDndName::GetAddress
       
   706 // ********************
       
   707 /**
       
   708 // This is reverse of SetName with TInetAddr and translates
       
   709 // the content of *.ip6.arpa or *.in-addr.arpa into TInetAddr,
       
   710 // if the address is complete.
       
   711 //
       
   712 // @retval aAddr The address, if conversion is possible
       
   713 // @return TRUE, if conversion was possible, and FALSE otherwise.
       
   714 */
       
   715 TBool TDndName::GetAddress(TInetAddr &aAddr) const
       
   716 	{
       
   717 	TInt k;
       
   718 	TLex8 decode(*this);
       
   719 
       
   720 	// Initialize to V4 mapped format, so that it is ready
       
   721 	// to be "patched" with IPv4 address. If the address
       
   722 	// is IPv6, all of the address will be overwritten.
       
   723 	TIp6Addr addr = {{{0,0,0,0,0,0,0,0,0,0,0xff,0xff,0,0,0,0}}};
       
   724 
       
   725 	if ((k = Find(KIPv4AddrToHost)) >= 0)
       
   726 		{
       
   727 		if (k + KIPv4AddrToHost().Length() != Length())
       
   728 			return FALSE;
       
   729 		for (TInt i = sizeof(addr); --i >= (TInt)(sizeof(addr) - 4); )
       
   730 			{
       
   731 			// Note: the check is loose on extra leading zeroes
       
   732 			// (which should not be present, but are accepted
       
   733 			// here).
       
   734 			TUint32 octet;
       
   735 			if (decode.Val(octet, EDecimal, 255) != KErrNone)
       
   736 				return FALSE;	// Too large value
       
   737 			if (decode.Get() != '.')
       
   738 				return FALSE;
       
   739 			addr.u.iAddr8[i] = (TUint8)octet;
       
   740 			}
       
   741 		}
       
   742 	else if ((k = Find(KIPv6AddrToHost)) >= 0)
       
   743 		{
       
   744 		if (k + KIPv6AddrToHost().Length() != Length())
       
   745 			return FALSE;
       
   746 		TInt j = sizeof(addr);
       
   747 		for (TUint i = 0; i < sizeof(addr)*2; ++i)
       
   748 			{
       
   749 			// Note: the check is loose on extra leading zeroes
       
   750 			// (which should not be present, but are accepted
       
   751 			// here).
       
   752 			TUint32 nibble;
       
   753 			if (decode.Val(nibble, EHex, 0xF) != KErrNone)
       
   754 				return FALSE;
       
   755 			if (decode.Get() != '.')
       
   756 				return FALSE;
       
   757 			if (i & 1)
       
   758 				{
       
   759 				// high nibble (always after low nibble, just OR high bits in)
       
   760 				addr.u.iAddr8[j] |= (TUint8)(nibble << 4);
       
   761 				}
       
   762 			else
       
   763 				{
       
   764 				ASSERT(j > 0);
       
   765 				// low nibble (this will happen first)
       
   766 				j -= 1;
       
   767 				addr.u.iAddr8[j] = (TUint8)nibble;
       
   768 				}
       
   769 			}
       
   770 		}
       
   771 	// The decoding must eat everything upto in-addr.arpa or ip6.arpa!
       
   772 	if (decode.Offset() != k+1)
       
   773 		return FALSE;
       
   774 	aAddr.SetAddress(addr);
       
   775 	return TRUE;
       
   776 	}
       
   777 
       
   778 
       
   779 // Creating TDndQuestion from the question section of the UDP message. The question
       
   780 // section starts at position 'aIndex' of the buffer 'aBuf'. The function returns the
       
   781 // offset pointing over the question section on return (or error).
       
   782 //
       
   783 // Returns
       
   784 //	> 0, the offset pointing over the question section
       
   785 //	< 0, an error is detected
       
   786 //
       
   787 TInt TDndQuestion::Create(const TMsgBuf &aBuf, TInt aIndex)
       
   788 	{
       
   789 	Zero();
       
   790 	TInt i = aBuf.GetNextName(aIndex, *this);
       
   791 	if (i > 0)
       
   792 		{
       
   793 		if (aBuf.Length() < i + 4)
       
   794 			return KErrDndDiscard;
       
   795 
       
   796 		iQType = EDnsQType((aBuf[i] << 8) | aBuf[i+1]);
       
   797 		iQClass = EDnsQClass((aBuf[i+2] << 8) | aBuf[i+3]);
       
   798 		i += 4;
       
   799 		}
       
   800 	return i;
       
   801 	}
       
   802 
       
   803 
       
   804 // TDndQuestion::Append(aMsgBuf, aFlags)
       
   805 // *************************************
       
   806 // Append a Question section to aMsgBuf 
       
   807 /**
       
   808 //
       
   809 // @retval	aMsgBuf	the DNS message to be modified
       
   810 // @param	aCompressed
       
   811 //		value of is used to convey whether the name contains a full name or only
       
   812 //		a prefix part.
       
   813 //	@li	= 0,
       
   814 //		the name is full name
       
   815 //	@li > 0,
       
   816 //		the name is only a prefix to the name already stored in to the
       
   817 //		message start at this offset.
       
   818 // @returns
       
   819 //	@li	KErrNone
       
   820 //		if question section appended succesfully
       
   821 //	@li	KErrDndNameTooBig,
       
   822 //		if question does not fit the message buffer
       
   823 //	@li	KErrBadName,
       
   824 //		if name is invalid, e.g. has empty or too long (> 63)
       
   825 //		components
       
   826 //	@li	KErrDndUnknown
       
   827 //		if aFlags is illegal, not in [0..Length()-1]
       
   828 */
       
   829 TInt TDndQuestion::Append(TMsgBuf& aMsgBuf, TUint aCompressed) const
       
   830 	{
       
   831 	const TInt err = aMsgBuf.AppendName(*this, aCompressed);
       
   832 	if (err != KErrNone)
       
   833 		return err;
       
   834 
       
   835 	if (aMsgBuf.MaxLength() < aMsgBuf.Length() + 4)
       
   836 		return KErrDndNameTooBig;
       
   837 
       
   838 	// Append the QType
       
   839 	aMsgBuf.Append((TChar)(iQType / 0x100));
       
   840 	aMsgBuf.Append((TChar)(iQType % 0x100));
       
   841 
       
   842 	// Append the QClass
       
   843 	aMsgBuf.Append((TChar)(iQClass / 0x100));
       
   844 	aMsgBuf.Append((TChar)(iQClass % 0x100));
       
   845 	return KErrNone;
       
   846 	}
       
   847 
       
   848 
       
   849 // TDndQuestion::CheckQuestion
       
   850 // ***************************
       
   851 /**
       
   852 // Compares the name, query type and query class.
       
   853 //
       
   854 // @param aQuestion	to be compared with
       
   855 // @returns
       
   856 //	@li	KErrNone, if questions are equal
       
   857 //	@li	KErrDndDiscard, if questions are not equal
       
   858 */
       
   859 TInt TDndQuestion::CheckQuestion(const TDndQuestion &aQuestion) const
       
   860 	{
       
   861 	return
       
   862 		(
       
   863 		aQuestion.iQClass == iQClass &&
       
   864 		aQuestion.iQType == iQType &&
       
   865 		DnsCompareNames(*this, aQuestion)) ? KErrNone : KErrDndDiscard;
       
   866 	}
       
   867 
       
   868 
       
   869 // TDndRR::GetSockAddr
       
   870 // *******************
       
   871 /**
       
   872 // @retval	aName contains the resulting name, if return is OK
       
   873 // @param	aOffset	to the start of name, relative to the RDATA
       
   874 // @returns	offset pointing to next octet after the extracted value (this
       
   875 //			offset is relative to the DNS message start). Negative returns
       
   876 //			are error returns.
       
   877 */
       
   878 TInt TDndRR::GetSockAddr(TInetAddr& aSockAddr) const
       
   879 	{
       
   880 	if (iType == EDnsType_A && iClass == EDnsClass_IN && iRdLength == 4)
       
   881 		{
       
   882 		const TUint32 KInetAddr = INET_ADDR(iBuf[iRd+0], iBuf[iRd+1], iBuf[iRd+2], iBuf[iRd+3]);
       
   883 		aSockAddr.SetAddress(KInetAddr);
       
   884 		return iRd + 4;
       
   885 		}
       
   886 
       
   887 	else if(iType == EDnsType_AAAA && iClass == EDnsClass_IN)
       
   888 		{
       
   889 		if (iRdLength < sizeof(TIp6Addr))
       
   890 			return KErrDndUnknown;
       
   891 		// TIp6Addr byteorder is network order, so can just copy
       
   892 		// bytes as is from the resource data... but, as RR is
       
   893 		// not necessarily aligned properly, must use a temporary
       
   894 		// address buffer for the transfer..
       
   895 		TIp6Addr addr;
       
   896 		Mem::Copy(addr.u.iAddr8, &iBuf[iRd], sizeof(addr.u.iAddr8));
       
   897 		aSockAddr.SetAddress(addr);
       
   898 		return iRd + sizeof(addr.u.iAddr8);
       
   899 		}
       
   900 	return KErrDndUnknown;
       
   901 	}
       
   902 
       
   903 
       
   904 // TDndRR::GetNameFromRDATA
       
   905 // ************************
       
   906 /**
       
   907 //
       
   908 // @retval	aName contains the extracted domain name.
       
   909 // @param	aOffset	to the start of the name, relative to the RDATA
       
   910 // @returns	offset pointing to next octet after the extracted value (this
       
   911 //			offset is relative to the DNS message start). Negative returns
       
   912 //			are error returns.
       
   913 */
       
   914 TInt TDndRR::GetNameFromRDATA(TDes8 &aName, TUint aOffset) const
       
   915 	{
       
   916 //	return aName.SetName(iBuf, iRd + aOffset);
       
   917 	aName.Zero();
       
   918 	return iBuf.GetNextName(iRd + aOffset, aName);
       
   919 	}
       
   920 
       
   921 // TDndRR::GetStringFromRDATA
       
   922 // **************************
       
   923 /**
       
   924 // @retval	aString
       
   925 //		is set to point to the string content in the message buffer.
       
   926 //		No copying occurs, the message buffer must exist when this
       
   927 //		return value is used!
       
   928 // @param	aOffset	to the start of the character string, relative to the RDATA
       
   929 // @returns	offset pointing to next octet after the extracted value (this
       
   930 //			offset is relative to the DNS message start). Negative returns
       
   931 //			are error returns.
       
   932 */
       
   933 TInt TDndRR::GetStringFromRDATA(TPtrC8 &aString, TUint aOffset) const
       
   934 	{
       
   935 	return iBuf.GetNextString(iRd + aOffset, aString);
       
   936 	}
       
   937 
       
   938 // Return TUint16 from a buffer
       
   939 static TUint16 Get16(const TUint8 *p)
       
   940 	{
       
   941 	return (TUint16)(p[0] << 8 | p[1]);
       
   942 	}
       
   943 // Return TUint32 from a buffer
       
   944 static TUint32 Get32(const TUint8 *p)
       
   945 	{
       
   946 	return (TUint32)(p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]);
       
   947 	}
       
   948 
       
   949 // TDndRR::GetResponse
       
   950 // *******************
       
   951 // Extract content of RR
       
   952 //
       
   953 /**
       
   954 // What exactly is returned, depends on the type of the RR (A, AAAA, CNAME and
       
   955 // PTR return "normal" results, for others some special values may returned,
       
   956 // see TInetDnsRR).
       
   957 //
       
   958 // @retval	aName	normally the domain name (system encoding)
       
   959 // @retval	aAddr	normally the address (but, also see TInetDnsRR)
       
   960 // @returns	KErrNone if extraction succeeded, and error otherwise.
       
   961 */
       
   962 TInt TDndRR::GetResponse(TDes &aName, TInetAddr &aAddr) const
       
   963 	{
       
   964 	TInt err = iName;	// (just to inialize, to offset of this RR record)
       
   965 	TDndName name;
       
   966 #ifdef SYMBIAN_DNS_PUNYCODE
       
   967 		name.EnableIdn(iIdnEnabled);
       
   968 #endif //SYMBIAN_DNS_PUNYCODE
       
   969 
       
   970 	if ((iType == EDnsType_A || iType == EDnsType_AAAA) && iClass == EDnsClass_IN)
       
   971 		{
       
   972 		err = name.SetName(iBuf, iName);
       
   973 		if (err < 0)
       
   974 			return err;
       
   975 		err = GetSockAddr(aAddr);
       
   976 		}
       
   977 	else  if (iType == EDnsType_PTR && iClass == EDnsClass_IN)
       
   978 		{
       
   979 		//
       
   980 		// For the PTR record, it is assumed the aAddr is already
       
   981 		// initialized to the original queried address (do not
       
   982 		// try to recompute address from the name part of the
       
   983 		// PTR record -- that is *NOT* always the address due
       
   984 		// to some CNAME games for the PTR records... -- msa)
       
   985 		//
       
   986 		// ..and get the real name from RData.
       
   987 		err = GetNameFromRDATA(name);
       
   988 		}
       
   989 	else if (iType == EDnsType_CNAME && iClass == EDnsClass_IN)
       
   990 		{
       
   991 		aAddr.SetAddress(0);
       
   992 		// ..and get the cname from RDATA
       
   993 		err = GetNameFromRDATA(name);
       
   994 		}
       
   995 	else
       
   996 		{
       
   997 		//
       
   998 		// Special RR values
       
   999 		//
       
  1000 		TInetDnsRR::Cast(aAddr) = TInetDnsRR();
       
  1001 		SDnsRR &rr = TInetDnsRR::Cast(aAddr).RR();
       
  1002 		rr.iClass = (TUint16)iClass;
       
  1003 		rr.iType = (TUint16)iType;
       
  1004 		if (iClass == EDnsClass_IN)
       
  1005 			{
       
  1006 			const TUint8 *const rd = iBuf.Ptr() + iRd;
       
  1007 			//
       
  1008 			// Only a select subset of RR's are supported
       
  1009 			//
       
  1010 			if (iType == EDnsType_SRV && iRdLength > 4)
       
  1011 				{
       
  1012 				rr.iSRV.iPriority = Get16(rd);
       
  1013 				rr.iSRV.iWeight = Get16(rd + 2);
       
  1014                 aAddr.SetPort(Get16(rd + 4));
       
  1015 				err = GetNameFromRDATA(name, 6);
       
  1016 				}
       
  1017 			else if (iType == EDnsType_NAPTR && iRdLength > 7)
       
  1018 				{
       
  1019 				rr.iNAPTR.iOrder = Get16(rd);
       
  1020 				rr.iNAPTR.iPreference = Get16(rd + 2);
       
  1021 				// get FLAGS
       
  1022 				TPtrC8 flags;
       
  1023 				err = GetStringFromRDATA(flags, 4);
       
  1024 				if (err < 0)
       
  1025 					return err;
       
  1026 				TInt flagLength = sizeof(rr.iNAPTR.iFlags);
       
  1027 				//The buffer size of TInetAddr(0x20 bytes) may not be sufficient to store the 
       
  1028 				//realtime length(upto 0xFF) of FLAGS field, so it is limited to 12 bytes. Hence if the 
       
  1029 				//flag length is more than 12 bytes, error KErrDndNameTooBig is raised.
       
  1030 				if(flagLength < (err - iRd - 5))
       
  1031 					return KErrDndNameTooBig;
       
  1032 				TPtr8 rr_flags(rr.iNAPTR.iFlags, flagLength , flagLength);
       
  1033 				rr_flags.FillZ();
       
  1034 				rr_flags = flags;
       
  1035 
       
  1036 				// get SERVICES
       
  1037 				TPtrC8 services;
       
  1038 				err = GetStringFromRDATA(services, err - iRd);
       
  1039 				if (err < 0)
       
  1040 					return err;
       
  1041 				// get REGEXP
       
  1042 				TPtrC8 regexp;
       
  1043 				err = GetStringFromRDATA(regexp, err - iRd);
       
  1044 				if (err < 0)
       
  1045 					return err;
       
  1046 				// Fetch REPLACEMENT
       
  1047 				err = GetNameFromRDATA(name, err - iRd);
       
  1048 				if (err < 0)
       
  1049 					return err;
       
  1050 
       
  1051 				// Try to append SERVICES and REGEXP into name
       
  1052 				TInt length = name.Length() + services.Length() + regexp.Length();
       
  1053 				if (length > name.MaxLength())
       
  1054 					return KErrDndNameTooBig;
       
  1055 				// ***** WARNING ********
       
  1056 				// The iL1 and iL2 will be problematic if the future
       
  1057 				// UNICODE conversion of the name is not 1 to 1!
       
  1058 				// Should use separators instead? -- msa
       
  1059 				rr.iNAPTR.iL1 = (TUint8)name.Length();
       
  1060 				rr.iNAPTR.iL2 = (TUint8)services.Length();
       
  1061 				name.Append(services);
       
  1062 				name.Append(regexp);
       
  1063 				}
       
  1064 			else if (iType == EDnsType_MX && iRdLength > 2)
       
  1065 				{
       
  1066 				rr.iMX.iPreference = Get16(rd);
       
  1067 				err = GetNameFromRDATA(name, 2);
       
  1068 				}
       
  1069 			else if (iType == EDnsType_NS)
       
  1070 				{
       
  1071 				err = GetNameFromRDATA(name);
       
  1072 				}
       
  1073 			else if (iType == EDnsType_SOA)
       
  1074 				{
       
  1075 				err = GetNameFromRDATA(name);
       
  1076 				if (err < 0)
       
  1077 					return err;
       
  1078 				if (name.Length() == name.MaxLength())
       
  1079 					return KErrDndNameTooBig;
       
  1080 				name.Append('@');
       
  1081 				err = iBuf.GetNextName(err, name);// *APPEND* RNAME to hostname!
       
  1082 				if (err < 0)
       
  1083 					return err;
       
  1084 
       
  1085 				err -= iRd;
       
  1086 				if (err < 0 || err + 20 > (TInt)iRdLength)
       
  1087 					return KErrDndUnknown;
       
  1088 				rr.iSOA.iSerial = Get32(rd+err);
       
  1089 				rr.iSOA.iRefresh = Get32(rd+err+4);
       
  1090 				rr.iSOA.iRetry = Get32(rd+err+8);
       
  1091 				rr.iSOA.iExpire = Get32(rd+err+12);
       
  1092 				rr.iSOA.iMinimum = Get32(rd+err+16);
       
  1093 				}
       
  1094 			}
       
  1095 		}
       
  1096 	return err > 0 ? name.GetName(aName) : err;
       
  1097 	}
       
  1098 
       
  1099 #ifndef NO_DNS_QUERY_SUPPORT
       
  1100 // TDndRR::GetResponse
       
  1101 // *******************
       
  1102 // Extract content of RR
       
  1103 //
       
  1104 /**
       
  1105 // What exactly is returned, depends on the type of the RR
       
  1106 //
       
  1107 // @retval	aAnswer	the "payload" will receive the RR content in TDnsQryRespBase format
       
  1108 // @retval	aAddr a pointer to "TInetAddr *" within the reply (only for A and AAAA, NULL otherwise)
       
  1109 // @returns	offset pointing to next octet after the extracted value (this
       
  1110 //			offset is relative to the DNS message start). Negative returns
       
  1111 //			are error returns.
       
  1112 */
       
  1113 TInt TDndRR::GetResponse(TDnsMessageBuf &aAnswer, TInetAddr **aAddr) const
       
  1114 	{
       
  1115 	TInt err = KErrNotSupported;
       
  1116 	const TInt max_len = aAnswer.MaxLength() - aAnswer().HeaderSize();
       
  1117 	TInt len = 0;
       
  1118 	*aAddr = NULL;
       
  1119 
       
  1120 	const TUint8 *const rd = iBuf.Ptr() + iRd;
       
  1121 
       
  1122 	switch ((TUint16)iType)
       
  1123 		{
       
  1124 		case KDnsRRTypeA:
       
  1125 			{
       
  1126 			TDndRespA &a = aAnswer().A();
       
  1127 			len = sizeof(a);
       
  1128 			if (len > max_len)
       
  1129 				return KErrOverflow;
       
  1130 			(void)new (&a) TDndRespA();
       
  1131 			err = GetSockAddr(a.HostAddress());
       
  1132 			*aAddr = &a.HostAddress();
       
  1133 			}
       
  1134 			break;
       
  1135 		case KDnsRRTypeAAAA:
       
  1136 			{
       
  1137 			TDndRespAAAA &aaaa = aAnswer().AAAA();
       
  1138 			len = sizeof(aaaa);
       
  1139 			if (len > max_len)
       
  1140 				return KErrOverflow;
       
  1141 			(void)new (&aaaa) TDndRespAAAA();
       
  1142 			err = GetSockAddr(aaaa.HostAddress());
       
  1143 			*aAddr = &aaaa.HostAddress();
       
  1144 			}
       
  1145 			break;
       
  1146 #if 0
       
  1147 		case KDnsRRTypeNS:
       
  1148 			{
       
  1149 			TDndRespNS &ns = aAnswer().NS();
       
  1150 			len = sizeof(ns);
       
  1151 			if (len > max_len)
       
  1152 				return KErrOverflow;
       
  1153 			(void)new (&ns) TDndRespNS();
       
  1154 			err = GetNameFromRDATA(ns.HostName());
       
  1155 			}
       
  1156 			break;
       
  1157 		case KDnsRRTypeCNAME:
       
  1158 			break;
       
  1159 		case KDnsRRTypeWKS:
       
  1160 			break;
       
  1161 #endif
       
  1162 		case KDnsRRTypePTR:
       
  1163 			{
       
  1164 			TDndRespPTR &ptr = aAnswer().PTR();
       
  1165 			len = sizeof(ptr);
       
  1166 			if (len > max_len)
       
  1167 				return KErrOverflow;
       
  1168 			(void)new (&ptr) TDndRespPTR();
       
  1169 			err = GetNameFromRDATA(ptr.HostName());
       
  1170 			}
       
  1171 			break;
       
  1172 #if 0
       
  1173 		case KDnsRRTypeHINFO:
       
  1174 			break;
       
  1175 #endif
       
  1176 		case KDnsRRTypeMX:
       
  1177 			if (iRdLength > 2)
       
  1178 				{
       
  1179 				TDndRespMX &mx = aAnswer().MX();
       
  1180 				len = sizeof(mx);
       
  1181 				if (len > max_len)
       
  1182 					return KErrOverflow;
       
  1183 				(void)new (&mx) TDndRespMX();
       
  1184 				mx.SetPref(Get16(rd));
       
  1185 				err = GetNameFromRDATA(mx.HostName(), 2);
       
  1186 				}
       
  1187 			else
       
  1188 				err = KErrDndUnknown;
       
  1189 			break;
       
  1190 #if 0
       
  1191 		case KDnsRRTypeTXT:
       
  1192 			break;
       
  1193 #endif
       
  1194 		case KDnsRRTypeSRV:
       
  1195 			if (iRdLength > 4)
       
  1196 				{
       
  1197 				TDndRespSRV &srv = aAnswer().SRV();
       
  1198 				len = sizeof(srv);
       
  1199 				if (len > max_len)
       
  1200 					return KErrOverflow;
       
  1201 				(void)new (&srv) TDndRespSRV();
       
  1202 				srv.SetPriority(Get16(rd));
       
  1203 				srv.SetWeight(Get16(rd + 2));
       
  1204 				srv.SetPort(Get16(rd + 4));
       
  1205 				err = GetNameFromRDATA(srv.Target(), 6);
       
  1206 				}
       
  1207 			else
       
  1208 				err = KErrDndUnknown;
       
  1209 			break;
       
  1210 		case KDnsRRTypeNAPTR:
       
  1211 			if (iRdLength > 7)
       
  1212 				{
       
  1213 				TDndRespNAPTR &naptr = aAnswer().NAPTR();
       
  1214 				len = sizeof(naptr);
       
  1215 				if (len > max_len)
       
  1216 					return KErrOverflow;
       
  1217 				(void)new (&naptr) TDndRespNAPTR();
       
  1218 				naptr.SetOrder(Get16(rd));
       
  1219 				naptr.SetPref(Get16(rd + 2));
       
  1220 				// get FLAGS
       
  1221 				TPtrC8 flags;
       
  1222 				err = GetStringFromRDATA(flags, 4);
       
  1223 				if (err < 0)
       
  1224 					break;
       
  1225 				naptr.SetFlags(flags);
       
  1226 				// get SERVICES
       
  1227 				TPtrC8 services;
       
  1228 				err = GetStringFromRDATA(services, err - iRd);
       
  1229 				if (err < 0)
       
  1230 					break;
       
  1231 				naptr.SetService(services);
       
  1232 				// get REGEXP
       
  1233 				TPtrC8 regexp;
       
  1234 				err = GetStringFromRDATA(regexp, err - iRd);
       
  1235 				if (err < 0)
       
  1236 					break;
       
  1237 				naptr.SetRegexp(regexp);
       
  1238 				// Fetch REPLACEMENT
       
  1239 				err = GetNameFromRDATA(naptr.Replacement(), err - iRd);
       
  1240 				}
       
  1241 			else
       
  1242 				err = KErrDndUnknown;
       
  1243 			break;
       
  1244 #if 0
       
  1245 		case EDnsType_SOA:
       
  1246 			{
       
  1247 			TDndRespSOA &soa = aAnswer().SOA();
       
  1248 			len = sizeof(soa);
       
  1249 			if (len > max_len)
       
  1250 				return KErrOverflow;
       
  1251 			new (&soa) TDndRespSOA();
       
  1252 
       
  1253 			err = GetNameFromRDATA(soa.MName());
       
  1254 			if (err < 0)
       
  1255 				return err;
       
  1256 			err = GetNameFromRDATA(soa.RName(), err - iRd);
       
  1257 			if (err < 0)
       
  1258 				return err;
       
  1259 
       
  1260 			const TInt i = err - iRd;
       
  1261 			if (i < 0 || i + 20 > (TInt)iRdLength)
       
  1262 				return KErrDndUnknown;
       
  1263 			soa.SetSerial(Get32(rd+i));
       
  1264 			soa.SetRefresh(Get32(rd+i+4));
       
  1265 			soa.SetRetry(Get32(rd+i+8));
       
  1266 			soa.SetExpire(Get32(rd+i+12));
       
  1267 			soa.SetMininum(Get32(rd+i+16));
       
  1268 			}
       
  1269 			break;
       
  1270 #endif
       
  1271 		default:
       
  1272 			// For all yet unsupported replies, return only
       
  1273 			// the basic reply: TDnsQryRespBase
       
  1274 			{
       
  1275 			TDndReply &basic = aAnswer().Reply();
       
  1276 			len = sizeof(basic);
       
  1277 			if (len > max_len)
       
  1278 				return KErrOverflow;
       
  1279 			(void)new (&basic) TDndReply((TUint16)iType, (TUint16)iClass);
       
  1280 			basic.SetRRTtl(iTTL);
       
  1281 			}
       
  1282 			break;
       
  1283 		}
       
  1284 	aAnswer.SetLength(len + aAnswer().HeaderSize());
       
  1285 	// Return the TTL
       
  1286 	aAnswer().Reply().SetRRTtl(iTTL);
       
  1287 	return err;
       
  1288 	}
       
  1289 #endif
       
  1290 
       
  1291 //
       
  1292 // TDndRR::FindRR
       
  1293 // **************
       
  1294 // Locate Nth (aNext) RR entry from the message
       
  1295 //
       
  1296 /**
       
  1297 // The RR's are "virtually" numbered from 0 to aNumRR-1.
       
  1298 // All RR's matching the original query are numbered
       
  1299 // first, and all others follow them.
       
  1300 //
       
  1301 // @param	aOffset	from the start of the message to the beginning of the RR section
       
  1302 // @param	aNumRR	the number of the RR's in this section
       
  1303 // @param	aType	the original query type
       
  1304 // @param	aClass	the original query class
       
  1305 // @param	aNext	select the Nth RR to be returned [0..aNumRR-1]
       
  1306 // @returns
       
  1307 // @li	> 0, Nth resource entry located (value is offset to first octet following this RR)
       
  1308 // @li	< 0, the following errors:
       
  1309 // @li	KErrDndNoRecord, there was no Nth RR.
       
  1310 // @li	KErrDndCache, the message is corrupt and should be discarded
       
  1311 // @li	Never returns 0 (KErrNone)!
       
  1312 */
       
  1313 TInt TDndRR::FindRR(TInt aOffset, TInt aNumRR, EDnsQType aType, EDnsQClass aClass, TInt aNext)
       
  1314 	{
       
  1315 	TInt count = 0;
       
  1316 
       
  1317 	aNext++;	// Looking for this! (internally numbered from 1..n)
       
  1318 	for (TInt any = 0;; any = 1)
       
  1319 		{
       
  1320 		TInt offset = aOffset;		// Start from beginning of RR's
       
  1321 
       
  1322 		for (TInt j = 0; j < aNumRR; j++)
       
  1323 			{
       
  1324 			iName = offset;
       
  1325 			offset = iBuf.GetRR(iName, iType, iClass, iTTL, iRd, iRdLength);
       
  1326 			if (offset < 0)
       
  1327 				// ..if the above Resource() access fails (-1), then the stored cache
       
  1328 				// record must be corrupt, indicate so to the caller...
       
  1329 				return KErrDndCache;
       
  1330 			if (EDnsQType(iType) == aType && EDnsQClass(iClass) == aClass)
       
  1331 				// on first pass (any == 0), only count exact matches
       
  1332 				count += any ? 0 : 1;
       
  1333 			else
       
  1334 				// on second pass (any == 1), only count non-matches (CNAMES, etc.)
       
  1335 				count += any ? 1 : 0;
       
  1336 			if (count == aNext)
       
  1337 				{
       
  1338 				// Found the target RR
       
  1339 				return offset;
       
  1340 				}
       
  1341 			}
       
  1342 		// exit, if second pass completed!
       
  1343 		if (any != 0)
       
  1344 			break;
       
  1345 		}
       
  1346 	//
       
  1347 	// No matching entry located
       
  1348 	//
       
  1349 	return KErrDndNoRecord;
       
  1350 	}
       
  1351 
       
  1352 /**
       
  1353 // The RR's are numbered from 0 to aNumRR-1.
       
  1354 // @param	aOffset	from the start of the message to the first RR to be tested
       
  1355 // @param	aNumRR	the number of the RR's
       
  1356 // @param	aType	the query type
       
  1357 // @param	aClass	the query class (EDnsQClass_ANY matches any class)
       
  1358 // @retval	aStart	the first RR to test [0..aNumRR-1]
       
  1359 // @returns
       
  1360 // @li	> 0, Nth resource entry located (value is offset to first octet following this RR)
       
  1361 // @li	< 0, the following errors:
       
  1362 // @li	KErrDndNoRecord, there was no such RR
       
  1363 // @li	KErrDndCache, the message is corrupt and should be discarded
       
  1364 // @li	Never returns 0 (KErrNone)!
       
  1365 */
       
  1366 TInt TDndRR::LocateRR(TInt aOffset, TInt aNumRR, EDnsQType aType, EDnsQClass aClass, TInt aStart)
       
  1367 	{
       
  1368 	for (TInt j = 0; j < aNumRR; j++)
       
  1369 		{
       
  1370 		iName = aOffset;
       
  1371 		aOffset = iBuf.GetRR(iName, iType, iClass, iTTL, iRd, iRdLength);
       
  1372 		if (aOffset < 0)
       
  1373 			// ..if the above Resource() access fails (-1), then the stored cache
       
  1374 			// record must be corrupt, indicate so to the caller...
       
  1375 			return KErrDndCache;
       
  1376 		if (j >= aStart && EDnsQType(iType) == aType && (EDnsQClass(aClass) == EDnsQClass_ANY || EDnsQClass(iClass) == aClass))
       
  1377 			{
       
  1378 			// The object has been located
       
  1379 			return aOffset;
       
  1380 			}
       
  1381 		}
       
  1382 	//
       
  1383 	// No matching entry located
       
  1384 	//
       
  1385 	return KErrDndNoRecord;
       
  1386 	}
       
  1387 
       
  1388 #ifdef LLMNR_ENABLED
       
  1389 
       
  1390 /**
       
  1391 // Append a new RR
       
  1392 //
       
  1393 // This will append a new complete RR (with empty RDATA, RDLENGTH = 0)
       
  1394 // to the message buffer.
       
  1395 //
       
  1396 // @param	aName
       
  1397 //		content of the NAME field
       
  1398 // @param	aCompression
       
  1399 //		if non-zero, the name portion indicated by this
       
  1400 //		offset will be logically conctenated into the
       
  1401 //		NAME field.
       
  1402 // @returns
       
  1403 //	@li	KErrNone, on success
       
  1404 //	@li	KErrDndNameTooBig, when RR does not fit into the buffer
       
  1405 */
       
  1406 TInt TDndRROut::Append(const TDesC8 &aName, TInt aCompression)
       
  1407 	{
       
  1408 	// Append the NAME
       
  1409 	TInt ret = iBuf.AppendName(aName, aCompression);
       
  1410 	if (ret != KErrNone)
       
  1411 		return ret;
       
  1412 
       
  1413 	// Available space after fixed portion of the RR (after RDLENGTH)
       
  1414 	// has been appended.
       
  1415 	const TInt room = iBuf.MaxLength() - iBuf.Length() - 10;
       
  1416 	if (room < 0)
       
  1417 		return KErrDndNameTooBig; // Oops.. cannot fit RR into message (a bit dubious error code)
       
  1418 
       
  1419 	// Append the TYPE
       
  1420 	iBuf.Append((TChar)(iType / 0x100));
       
  1421 	iBuf.Append((TChar)(iType % 0x100));
       
  1422 
       
  1423 	// Append the CLASS
       
  1424 	iBuf.Append((TChar)(iClass / 0x100));
       
  1425 	iBuf.Append((TChar)(iClass % 0x100));
       
  1426 
       
  1427 	// Append the TTL
       
  1428 	iBuf.Append((TChar)(iTTL / 0x1000000));
       
  1429 	iBuf.Append((TChar)((iTTL / 0x10000) % 0x100));
       
  1430 	iBuf.Append((TChar)((iTTL / 0x100) % 0x100));
       
  1431 	iBuf.Append((TChar)(iTTL % 0x100));
       
  1432 
       
  1433 	// Append the RDLENGTH (placeholder)
       
  1434 
       
  1435 	iBuf.Append((TChar)(0));
       
  1436 	iBuf.Append((TChar)(0));
       
  1437 
       
  1438 	iRd = iBuf.Length();
       
  1439 	return KErrNone;
       
  1440 	}
       
  1441 
       
  1442 
       
  1443 /**
       
  1444 // Extend the RR with address RDATA
       
  1445 //
       
  1446 // This will append address RDATA the Resource Record.
       
  1447 // Only types AAAA or A are supported, and the length
       
  1448 // and format of the RDATA is selected accordingly.
       
  1449 //
       
  1450 // @param	aAddr	specifies the address to be appended
       
  1451 //
       
  1452 // @returns
       
  1453 //	@li	KErrNone, on success
       
  1454 //	@li	KErrDndNameTooBig, when RR does not fit into the buffer
       
  1455 //	@li KErrDndNotImplemented, if RR type is not A or AAAA.
       
  1456 */
       
  1457 TInt TDndRROut::AppendRData(const TInetAddr &aAddr) const
       
  1458 	{
       
  1459 	const TInt room = iBuf.MaxLength() - iBuf.Length();
       
  1460 
       
  1461 	if (iType == EDnsType_A)
       
  1462 		{
       
  1463 		if (room < 4)
       
  1464 			return KErrDndNameTooBig; // Oops.. cannot fit RR into message (a bit dubious error code)
       
  1465 		TUint32 address = aAddr.Address();
       
  1466 		iBuf.Append((TChar)(address >> 24));
       
  1467 		iBuf.Append((TChar)(address >> 16));
       
  1468 		iBuf.Append((TChar)(address >> 8));
       
  1469 		iBuf.Append((TChar)address);
       
  1470 		}
       
  1471 	else if(iType == EDnsType_AAAA)
       
  1472 		{
       
  1473 		// assumes aAddr is in KAfInet6 format!!!
       
  1474 		const TIp6Addr &address = aAddr.Ip6Address();
       
  1475 		if (room < (TInt)sizeof(address.u.iAddr8))
       
  1476 			return KErrDndNameTooBig; // Oops.. cannot fit RR into message (a bit dubious error code)
       
  1477 		iBuf.Append(address.u.iAddr8, sizeof(address.u.iAddr8));
       
  1478 		}
       
  1479 	else
       
  1480 		return KErrDndNotImplemented;
       
  1481 
       
  1482 	AppendRData();
       
  1483 	return KErrNone;
       
  1484 	}
       
  1485 
       
  1486 /**
       
  1487 // Extend the RR with domain name
       
  1488 //
       
  1489 // This will append domain name RDATA the Resource Record.
       
  1490 //
       
  1491 // @param	aName
       
  1492 //		the domain name to be added
       
  1493 // @param	aCompression
       
  1494 //		if non-zero, the name portion indicated by this
       
  1495 //		offset will be logically conctenated into aName.
       
  1496 //
       
  1497 // @returns
       
  1498 //	@li	KErrNone, on success
       
  1499 //	@li	KErrDndNameTooBig, when RR does not fit into the buffer
       
  1500 */
       
  1501 TInt TDndRROut::AppendRData(const TDesC8 &aName, TInt aCompression) const
       
  1502 	{
       
  1503 
       
  1504 	TInt ret = iBuf.AppendName(aName, aCompression);
       
  1505 
       
  1506 	AppendRData();
       
  1507 	return ret;
       
  1508 	}
       
  1509 
       
  1510 /**
       
  1511 // Extend the RR with any binary data
       
  1512 //
       
  1513 // This will append binary data into the Resource Record.
       
  1514 // (just a convenience method, which provides length checking
       
  1515 // and implicitly calls AppendRData())
       
  1516 //
       
  1517 // @param	aRData	the data to be appended
       
  1518 //
       
  1519 // @returns
       
  1520 //	@li	KErrNone, on success
       
  1521 //	@li	KErrDndNameTooBig, when RR does not fit into the buffer
       
  1522 */
       
  1523 TInt TDndRROut::AppendRData(const TDesC8 &aRData) const
       
  1524 	{
       
  1525 	const TInt room = iBuf.MaxLength() - iBuf.Length();
       
  1526 	if (room < aRData.Length())
       
  1527 		return KErrDndNameTooBig;
       
  1528 	iBuf.Append(aRData);
       
  1529 
       
  1530 	AppendRData();
       
  1531 	return KErrNone;
       
  1532 	}
       
  1533 
       
  1534 /**
       
  1535 //	Update the RDLENGTH to match the current appended data
       
  1536 //
       
  1537 //	Assume Recource Record is complete and compute
       
  1538 //	the total amount RDATA that has been appended.
       
  1539 //
       
  1540 //	This can be called any number of times. 
       
  1541 */
       
  1542 void TDndRROut::AppendRData() const
       
  1543 	{
       
  1544 	// Append(..) must have been called before this!
       
  1545 	__ASSERT_DEBUG(iRd > 1, User::Panic(_L("DEBUG"), 0));
       
  1546 	// Patch in the RD lenght
       
  1547 	const TInt length = iBuf.Length() - iRd;
       
  1548 	iBuf[iRd-2] = (TUint8)(length / 0x100);
       
  1549 	iBuf[iRd-1] = (TUint8)(length % 0x100);
       
  1550 	}
       
  1551 
       
  1552 #endif