Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3619 lines
84 KiB

  1. /*++
  2. Copyright (c) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. packet.c
  5. Abstract:
  6. Domain Name System (DNS) API
  7. Packet writing utilities.
  8. Author:
  9. Jim Gilroy (jamesg) October, 1996
  10. Environment:
  11. User Mode - Win32
  12. Revision History:
  13. --*/
  14. #include "local.h"
  15. //
  16. // Receive buffer size
  17. // - use 16K, max size where compression useful
  18. // other choices would be ethernet UDP frag size
  19. // (1472 or 1280 depending on who you talk to)
  20. //
  21. DWORD g_RecvBufSize = 0x4000;
  22. //
  23. // Class values for UPDATE packets
  24. // (Key concept here -- designed by committee)
  25. //
  26. // These arrays are indexed by
  27. // !wDataLength -- row
  28. // Delete flag -- column
  29. //
  30. WORD PrereqClassArray[2][2] =
  31. {
  32. DNS_RCLASS_INTERNET, // data != 0, no delete
  33. 0, // data != 0, delete => ERROR
  34. DNS_RCLASS_ANY, // no data, no delete
  35. DNS_RCLASS_NONE, // no data, delete
  36. };
  37. WORD UpdateClassArray[2][2] =
  38. {
  39. DNS_RCLASS_INTERNET, // data != 0, no delete
  40. DNS_RCLASS_NONE, // data != 0, delete
  41. 0, // no data, no delete => ERROR
  42. DNS_RCLASS_ANY, // no data, delete
  43. };
  44. PDNS_MSG_BUF
  45. Dns_AllocateMsgBuf(
  46. IN WORD wBufferLength OPTIONAL
  47. )
  48. /*++
  49. Routine Description:
  50. Allocate message buffer.
  51. Arguments:
  52. wBufferLength - optional length of message buffer; default is MAX
  53. UDP size
  54. Return Value:
  55. Ptr to message buffer.
  56. NULL on error.
  57. --*/
  58. {
  59. PDNS_MSG_BUF pmsg;
  60. BOOL ftcp = FALSE;
  61. WORD allocLength;
  62. //
  63. // default allocation to "classical" UDP max buffer length
  64. // this is good enough for writing questions
  65. // recv size buffers should request larger size
  66. //
  67. if ( wBufferLength < DNS_RFC_MAX_UDP_PACKET_LENGTH )
  68. {
  69. allocLength = DNS_RFC_MAX_UDP_PACKET_LENGTH;
  70. }
  71. else if ( wBufferLength == MAXWORD )
  72. {
  73. allocLength = (WORD) g_RecvBufSize;
  74. }
  75. else
  76. {
  77. allocLength = wBufferLength;
  78. ftcp = TRUE;
  79. }
  80. pmsg = ALLOCATE_HEAP( SIZEOF_MSG_BUF_OVERHEAD + allocLength );
  81. if ( !pmsg )
  82. {
  83. return( NULL );
  84. }
  85. //
  86. // limit UDP sends to classical RFC UDP limit (512 bytes)
  87. // regardless of actual allocation
  88. // write routines use pBufferEnd to determine writeability
  89. //
  90. // DCR: allow big UDP send buffers for update?
  91. // problem is that must roll back NOT just OPT, but also
  92. // big buffer
  93. //
  94. // DCR: not really necessary as if write exceeds 512, can
  95. // just flip to TCP anyway
  96. //
  97. pmsg->BufferLength = allocLength;
  98. if ( !ftcp )
  99. {
  100. allocLength = DNS_RFC_MAX_UDP_PACKET_LENGTH;
  101. }
  102. pmsg->pBufferEnd = (PCHAR)&pmsg->MessageHead + allocLength;
  103. pmsg->fTcp = (BOOLEAN)ftcp;
  104. //
  105. // init -- this follows fTcp set as flag is used to set fields
  106. //
  107. Dns_InitializeMsgBuf( pmsg );
  108. return( pmsg );
  109. }
  110. VOID
  111. Dns_InitializeMsgBuf(
  112. IN OUT PDNS_MSG_BUF pMsg
  113. )
  114. /*++
  115. Routine Description:
  116. Initialize message buffer to "clean" state.
  117. Arguments:
  118. pMsg -- message to init
  119. Return Value:
  120. Ptr to message buffer.
  121. NULL on error.
  122. --*/
  123. {
  124. // clear info + header
  125. //
  126. // DCR_CLEANUP: can't take this approach without reworking Allocate
  127. // function which sets BufferLength and pBufferEnd
  128. // if this function is NOT independently used, then we can fix
  129. // it to clean and completely
  130. //
  131. // RtlZeroMemory(
  132. // pMsg,
  133. // ((PBYTE)&pMsg->MessageBody - (PBYTE)pMsg) );
  134. // setup addressing info
  135. pMsg->Socket = 0;
  136. pMsg->Socket4 = 0;
  137. pMsg->Socket6 = 0;
  138. // set for packet reception
  139. if ( pMsg->fTcp )
  140. {
  141. SET_MESSAGE_FOR_TCP_RECV( pMsg );
  142. }
  143. else
  144. {
  145. SET_MESSAGE_FOR_UDP_RECV( pMsg );
  146. }
  147. // clear header
  148. RtlZeroMemory(
  149. (PBYTE) &pMsg->MessageBody,
  150. sizeof(DNS_HEADER) );
  151. // set for rewriting
  152. pMsg->pCurrent = pMsg->MessageBody;
  153. pMsg->pPreOptEnd = NULL;
  154. }
  155. //
  156. // Writing to packet
  157. //
  158. PCHAR
  159. _fastcall
  160. Dns_WriteDottedNameToPacket(
  161. IN OUT PCHAR pch,
  162. IN PCHAR pchStop,
  163. IN PSTR pszName,
  164. IN PSTR pszDomain, OPTIONAL
  165. IN WORD wDomainOffset, OPTIONAL
  166. IN BOOL fUnicodeName
  167. )
  168. /*++
  169. Routine Description:
  170. Write lookup name to packet.
  171. Arguments:
  172. pch -- ptr to current position in packet buffer
  173. pchStop -- end of packet buffer
  174. pszName - dotted FQDN to write
  175. pszDomain - domain name already in packet (OPTIONAL); note this is
  176. a fragment of the SAME STRING as pszName; i.e. ptr compare
  177. NOT strcmp is done to determine if at domain name
  178. wDomainOffset - offset in packet of domain name; MUST include this
  179. if pszDomain is given
  180. fUnicodeName -- pszName is unicode string
  181. TRUE -- name is unicode
  182. FALSE -- name is UTF8
  183. Return Value:
  184. Ptr to next position in packet buffer.
  185. NULL on error.
  186. --*/
  187. {
  188. CHAR ch;
  189. PCHAR pchlabelStart;
  190. UCHAR countLabel = 0;
  191. ULONG countName = 0;
  192. PSTR pnameWire;
  193. PWSTR pnameUnicode;
  194. CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
  195. WCHAR nameWideBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
  196. // protect message buffer overrun
  197. if ( pch >= pchStop )
  198. {
  199. return( NULL );
  200. }
  201. // allow root to be indicated by NULL
  202. if ( !pszName )
  203. {
  204. *pch++ = 0;
  205. return( pch );
  206. }
  207. //
  208. // protect stack buffers from bogus names
  209. //
  210. if ( fUnicodeName )
  211. {
  212. countName = wcslen( (LPWSTR) pszName );
  213. }
  214. else
  215. {
  216. countName = strlen( pszName );
  217. }
  218. if ( countName >= DNS_MAX_NAME_BUFFER_LENGTH )
  219. {
  220. return NULL;
  221. }
  222. countName = 0;
  223. //
  224. // UTF8 name with extended chars?
  225. // - then must go up to unicode for canonicalizing
  226. //
  227. // DCR: shouldn't be sending in un-canonical UTF8
  228. // should
  229. // - stay in unicode all the way
  230. // - using canon unicode all the way
  231. // - use canon wire names all the way
  232. //
  233. if ( !fUnicodeName )
  234. {
  235. if ( !Dns_IsStringAscii( pszName ) )
  236. {
  237. DWORD bufLength = DNS_MAX_NAME_BUFFER_LENGTH_UNICODE;
  238. if ( ! Dns_NameCopy(
  239. (PCHAR) nameWideBuffer,
  240. & bufLength,
  241. pszName,
  242. 0, // length unknown
  243. DnsCharSetUtf8,
  244. DnsCharSetUnicode
  245. ) )
  246. {
  247. return( NULL );
  248. }
  249. if ( ! Dns_MakeCanonicalNameInPlaceW(
  250. nameWideBuffer,
  251. 0 ) )
  252. {
  253. return( NULL );
  254. }
  255. pnameUnicode = (PWSTR) nameWideBuffer;
  256. fUnicodeName = TRUE;
  257. }
  258. }
  259. //
  260. // unicode name -- if extended, canonicalize first
  261. //
  262. // DCR_FIX0: should functionalize -- raw unicode to wire
  263. //
  264. else
  265. {
  266. pnameUnicode = (PWSTR) pszName;
  267. if ( !Dns_IsWideStringAscii( pnameUnicode ) )
  268. {
  269. if ( ! Dns_MakeCanonicalNameW(
  270. nameWideBuffer,
  271. //DNS_MAX_NAME_BUFFER_LENGTH_UNICODE,
  272. DNS_MAX_NAME_BUFFER_LENGTH,
  273. pnameUnicode,
  274. 0 ) )
  275. {
  276. return NULL;
  277. }
  278. pnameUnicode = nameWideBuffer;
  279. }
  280. }
  281. //
  282. // convert unicode name to UTF8
  283. // - if extended chars, then downcase before hit the wire
  284. //
  285. if ( fUnicodeName )
  286. {
  287. if ( ! Dns_NameCopyUnicodeToWire(
  288. nameBuffer,
  289. pnameUnicode ) )
  290. {
  291. return( NULL );
  292. }
  293. pnameWire = nameBuffer;
  294. }
  295. else
  296. {
  297. pnameWire = pszName;
  298. }
  299. //
  300. // special case "." root name
  301. // - allows us to fail all other zero length labels cleanly
  302. //
  303. if ( *pnameWire == '.' )
  304. {
  305. if ( *(pnameWire+1) != 0 )
  306. {
  307. return( NULL );
  308. }
  309. *pch++ = 0;
  310. return( pch );
  311. }
  312. //
  313. // write lookup name
  314. // - leave
  315. pchlabelStart = pch++;
  316. while( ch = *pnameWire++ )
  317. {
  318. // out of space
  319. if ( pch >= pchStop )
  320. {
  321. return( NULL );
  322. }
  323. // not at end of label -- just copy character
  324. if ( ch != '.' )
  325. {
  326. *pch++ = ch;
  327. countLabel++;
  328. countName++;
  329. continue;
  330. }
  331. //
  332. // at end of label
  333. // - write label count
  334. // - reset counter
  335. // - if reached domain name, write compression and quit
  336. //
  337. if ( countLabel > DNS_MAX_LABEL_LENGTH ||
  338. countLabel == 0 ||
  339. countName > DNS_MAX_NAME_LENGTH )
  340. {
  341. return( NULL );
  342. }
  343. *pchlabelStart = countLabel;
  344. countLabel = 0;
  345. countName++;
  346. pchlabelStart = pch++;
  347. if ( pnameWire == pszDomain )
  348. {
  349. if ( ++pch >= pchStop )
  350. {
  351. return( NULL );
  352. }
  353. *(UNALIGNED WORD *)pchlabelStart =
  354. htons( (WORD)(wDomainOffset | (WORD)0xC000) );
  355. return( pch );
  356. }
  357. }
  358. if ( countLabel > DNS_MAX_LABEL_LENGTH ||
  359. countName > DNS_MAX_NAME_LENGTH )
  360. {
  361. return( NULL );
  362. }
  363. //
  364. // NULL terminate
  365. // - if no terminating ".", do end of label processing also
  366. // - return ptr to char after terminating NULL
  367. if ( countLabel )
  368. {
  369. *pchlabelStart = countLabel;
  370. *pch++ = 0;
  371. }
  372. else
  373. {
  374. DNS_ASSERT( pch == pchlabelStart + 1 );
  375. *pchlabelStart = 0;
  376. }
  377. return( pch );
  378. }
  379. PCHAR
  380. _fastcall
  381. Dns_WriteStringToPacket(
  382. IN OUT PCHAR pch,
  383. IN PCHAR pchStop,
  384. IN PSTR pszString,
  385. IN BOOL fUnicodeString
  386. )
  387. /*++
  388. Routine Description:
  389. Write string to packet.
  390. Arguments:
  391. pch -- ptr to current position in packet buffer
  392. pchStop -- end of packet buffer
  393. pszString - string to write
  394. fUnicodeString -- pszString is unicode string
  395. Return Value:
  396. Ptr to next position in packet buffer.
  397. NULL on error.
  398. --*/
  399. {
  400. DWORD length;
  401. //
  402. // handle NULL string
  403. //
  404. if ( !pszString )
  405. {
  406. if ( pch >= pchStop )
  407. {
  408. return( NULL );
  409. }
  410. *pch++ = 0;
  411. return( pch );
  412. }
  413. //
  414. // get string length
  415. // - get required buf length, then whack whack off space
  416. // for terminating NULL
  417. // - zero error case, becomes very large number and is
  418. // caught by length>MAXCHAR test
  419. //
  420. length = Dns_GetBufferLengthForStringCopy(
  421. pszString,
  422. 0,
  423. fUnicodeString ? DnsCharSetUnicode : DnsCharSetUtf8,
  424. DnsCharSetUtf8 );
  425. length--;
  426. //
  427. // set length byte
  428. //
  429. if ( length > MAXUCHAR )
  430. {
  431. SetLastError( ERROR_INVALID_DATA );
  432. return( NULL );
  433. }
  434. *pch++ = (UCHAR) length;
  435. if ( pch + length > pchStop )
  436. {
  437. SetLastError( ERROR_MORE_DATA );
  438. return( NULL );
  439. }
  440. //
  441. // copy string
  442. //
  443. // note unicode conversion will write NULL terminator, so
  444. // test again for space in packet
  445. //
  446. if ( fUnicodeString )
  447. {
  448. if ( pch + length + 1 > pchStop )
  449. {
  450. SetLastError( ERROR_MORE_DATA );
  451. return( NULL );
  452. }
  453. Dns_StringCopy(
  454. pch,
  455. NULL,
  456. pszString,
  457. length,
  458. DnsCharSetUnicode,
  459. DnsCharSetUtf8 );
  460. }
  461. else
  462. {
  463. memcpy(
  464. pch,
  465. pszString,
  466. length );
  467. }
  468. return( pch+length );
  469. }
  470. PCHAR
  471. Dns_WriteQuestionToMessage(
  472. IN OUT PDNS_MSG_BUF pMsg,
  473. IN PDNS_NAME pszName,
  474. IN WORD wType,
  475. IN BOOL fUnicodeName
  476. )
  477. /*++
  478. Routine Description:
  479. Write question to packet.
  480. Note: Routine DOES NOT clear message info or message header.
  481. This is optimized for use immediately following Dns_CreateMessage().
  482. Arguments:
  483. pMsg - message info
  484. pszName - DNS name of question
  485. wType - question type
  486. fUnicodeName - name is in unicode
  487. Return Value:
  488. Ptr to next char in buffer, if successful.
  489. NULL if error writing question name.
  490. --*/
  491. {
  492. PCHAR pch;
  493. // use recursion, as default
  494. pMsg->MessageHead.RecursionDesired = TRUE;
  495. // restart write at message header
  496. pch = pMsg->MessageBody;
  497. // write question name
  498. pch = Dns_WriteDottedNameToPacket(
  499. pch,
  500. pMsg->pBufferEnd,
  501. (PCHAR) pszName,
  502. NULL,
  503. 0,
  504. fUnicodeName );
  505. if ( !pch )
  506. {
  507. return( NULL );
  508. }
  509. // write question structure
  510. *(UNALIGNED WORD *) pch = htons( wType );
  511. pch += sizeof(WORD);
  512. *(UNALIGNED WORD *) pch = DNS_RCLASS_INTERNET;
  513. pch += sizeof(WORD);
  514. // set question RR section count
  515. pMsg->MessageHead.QuestionCount = 1;
  516. // header fields in host order
  517. pMsg->fSwapped = FALSE;
  518. // reset current ptr
  519. pMsg->pCurrent = pch;
  520. IF_DNSDBG( INIT )
  521. {
  522. DnsDbg_Message(
  523. "Packet after question write:",
  524. pMsg );
  525. }
  526. return( pch );
  527. }
  528. DNS_STATUS
  529. Dns_WriteRecordStructureToMessage(
  530. IN OUT PDNS_MSG_BUF pMsg,
  531. IN WORD wType,
  532. IN WORD wClass,
  533. IN DWORD dwTtl,
  534. IN WORD wDataLength
  535. )
  536. /*++
  537. Routine Description:
  538. No data RR cases:
  539. This includes prereqs and deletes except for specific record cases.
  540. Arguments:
  541. pch - ptr to next byte in packet buffer
  542. pchStop - end of packet buffer
  543. wClass - class
  544. wType - desired RR type
  545. dwTtl - time to live
  546. wDataLength - data length
  547. Return Value:
  548. Ptr to next postion in buffer, if successful.
  549. NULL on error.
  550. --*/
  551. {
  552. PDNS_WIRE_RECORD pdnsRR;
  553. PCHAR pchdata;
  554. IF_DNSDBG( WRITE2 )
  555. {
  556. DNS_PRINT(( "Dns_WriteRecordStructureToMessage(%p).\n", pMsg ));
  557. }
  558. //
  559. // out of space
  560. //
  561. pdnsRR = (PDNS_WIRE_RECORD) pMsg->pCurrent;
  562. pchdata = (PCHAR) pdnsRR + sizeof( DNS_WIRE_RECORD );
  563. if ( pchdata + wDataLength >= pMsg->pBufferEnd )
  564. {
  565. DNS_PRINT(( "ERROR out of space writing record to packet.\n" ));
  566. return( ERROR_MORE_DATA );
  567. }
  568. //
  569. // write RR wire structure
  570. //
  571. *(UNALIGNED WORD *) &pdnsRR->RecordType = htons( wType );
  572. *(UNALIGNED WORD *) &pdnsRR->RecordClass = htons( wClass );
  573. *(UNALIGNED DWORD *) &pdnsRR->TimeToLive = htonl( dwTtl );
  574. *(UNALIGNED WORD *) &pdnsRR->DataLength = htons( wDataLength );
  575. //
  576. // update current ptr
  577. //
  578. pMsg->pCurrent = pchdata;
  579. return( ERROR_SUCCESS );
  580. }
  581. DNS_STATUS
  582. Dns_WriteRecordStructureToPacket(
  583. IN OUT PCHAR pchBuf,
  584. IN PDNS_RECORD pRecord,
  585. IN BOOL fUpdatePacket
  586. )
  587. /*++
  588. Routine Description:
  589. Write wire record structure for given record.
  590. Arguments:
  591. pchBuf - ptr to next byte in packet buffer
  592. pRecord - record to write
  593. fUpdatePacket -- TRUE if building update message;
  594. for update the section flags in the pRecords are interpreted
  595. for update; otherwise query semantics are used
  596. Return Value:
  597. None
  598. --*/
  599. {
  600. PDNS_WIRE_RECORD pwireRecord;
  601. WORD class;
  602. DWORD ttl;
  603. IF_DNSDBG( WRITE2 )
  604. {
  605. DNS_PRINT((
  606. "Writing RR struct (%p) to packet buffer at %p.\n",
  607. pRecord,
  608. pchBuf
  609. ));
  610. DnsDbg_Record(
  611. "Record being written:",
  612. pRecord );
  613. }
  614. //
  615. // get TTL, it will be set to zero for several of the update cases
  616. //
  617. ttl = pRecord->dwTtl;
  618. //
  619. // determine class
  620. // - class variable is in net order (for perf)
  621. // - default is class IN, but may be ANY or NONE for certain updates
  622. //
  623. if ( fUpdatePacket )
  624. {
  625. switch( pRecord->Flags.S.Section )
  626. {
  627. case DNSREC_PREREQ:
  628. class = PrereqClassArray
  629. [ pRecord->wDataLength == 0 ][ pRecord->Flags.S.Delete ];
  630. ttl = 0;
  631. break;
  632. case DNSREC_UPDATE:
  633. case DNSREC_ADDITIONAL:
  634. class = UpdateClassArray
  635. [ pRecord->wDataLength == 0 ][ pRecord->Flags.S.Delete ];
  636. if ( class != DNS_RCLASS_INTERNET )
  637. {
  638. ttl = 0;
  639. }
  640. break;
  641. default:
  642. DNS_PRINT(( "ERROR: invalid RR section.\n" ));
  643. return( ERROR_INVALID_DATA );
  644. }
  645. if ( class == 0 )
  646. {
  647. DNS_PRINT(( "ERROR: no update class corresponding to RR flags.\n" ));
  648. return( ERROR_INVALID_DATA );
  649. }
  650. }
  651. else
  652. {
  653. class = DNS_RCLASS_INTERNET;
  654. }
  655. //
  656. // write RR wire structure
  657. // - zero datalength to handle no data case
  658. //
  659. pwireRecord = (PDNS_WIRE_RECORD) pchBuf;
  660. *(UNALIGNED WORD *) &pwireRecord->RecordType = htons( pRecord->wType );
  661. *(UNALIGNED WORD *) &pwireRecord->RecordClass = class;
  662. *(UNALIGNED DWORD *) &pwireRecord->TimeToLive = htonl( ttl );
  663. *(UNALIGNED WORD *) &pwireRecord->DataLength = 0;
  664. return( ERROR_SUCCESS );
  665. }
  666. PCHAR
  667. Dns_WriteRecordStructureToPacketEx(
  668. IN OUT PCHAR pchBuf,
  669. IN WORD wType,
  670. IN WORD wClass,
  671. IN DWORD dwTtl,
  672. IN WORD wDataLength
  673. )
  674. /*++
  675. Routine Description:
  676. Write wire record structure for given record.
  677. Arguments:
  678. pchBuf - ptr to next byte in packet buffer
  679. Return Value:
  680. Ptr to data section of record.
  681. --*/
  682. {
  683. PDNS_WIRE_RECORD pwireRecord;
  684. // DCR_PERF: optimize RR write to packet?
  685. pwireRecord = (PDNS_WIRE_RECORD) pchBuf;
  686. *(UNALIGNED WORD *) &pwireRecord->RecordType = htons( wType );
  687. *(UNALIGNED WORD *) &pwireRecord->RecordClass = htons( wClass );
  688. *(UNALIGNED DWORD *) &pwireRecord->TimeToLive = htonl( dwTtl );
  689. *(UNALIGNED WORD *) &pwireRecord->DataLength = htons( wDataLength );
  690. return( pchBuf + sizeof(DNS_WIRE_RECORD) );
  691. }
  692. VOID
  693. Dns_SetRecordDatalength(
  694. IN OUT PDNS_WIRE_RECORD pRecord,
  695. IN WORD wDataLength
  696. )
  697. /*++
  698. Routine Description:
  699. Reset record datalength.
  700. Arguments:
  701. pRecord - wire record to reset
  702. wDataLength - data length
  703. Return Value:
  704. Ptr to data section of record.
  705. --*/
  706. {
  707. WORD flippedWord;
  708. INLINE_WORD_FLIP( flippedWord, wDataLength );
  709. *(UNALIGNED WORD *) &pRecord->DataLength = flippedWord;
  710. }
  711. DNS_STATUS
  712. Dns_WriteOptToMessage(
  713. IN OUT PDNS_MSG_BUF pMsg,
  714. IN WORD wPayload,
  715. IN DWORD Rcode,
  716. IN BYTE Version,
  717. IN PBYTE pData,
  718. IN WORD wDataLength
  719. )
  720. /*++
  721. Routine Description:
  722. Write OPT record to message.
  723. Arguments:
  724. pMsg -- message
  725. wPayload -- max length client can receive in UDP
  726. Rcode -- RCODE, if extended some of this ends up in OPT
  727. Version -- EDNS version
  728. pData -- ptr to data buffer of OPT data
  729. wDataLength -- length of pData
  730. Return Value:
  731. ERROR_SUCCESS if successfully writen.
  732. ErrorCode on failure.
  733. --*/
  734. {
  735. DNS_STATUS status;
  736. PCHAR pstart;
  737. //
  738. // DCR: use variable OPT fields
  739. //
  740. //
  741. // save existing pCurrent
  742. // - this allows dual wire write
  743. //
  744. ASSERT( !pMsg->pPreOptEnd );
  745. pstart = pMsg->pCurrent;
  746. //
  747. // write OPT record name (root)
  748. //
  749. *pstart = 0;
  750. pMsg->pCurrent++;
  751. //
  752. // write OPT -- basic info, no options
  753. // - if OPT didn't fit, clear pPreOptEnd pointer
  754. // which serves as signal that OPT exists
  755. //
  756. status = Dns_WriteRecordStructureToMessage(
  757. pMsg,
  758. DNS_TYPE_OPT,
  759. (WORD) g_RecvBufSize, // recv buffer size (in Class)
  760. 0, // no flags\extended RCODE (in TTL)
  761. 0 // no data length
  762. );
  763. if ( status == ERROR_SUCCESS )
  764. {
  765. // increment message record count
  766. SET_TO_WRITE_ADDITIONAL_RECORDS(pMsg);
  767. CURRENT_RR_COUNT_FIELD(pMsg)++;
  768. pMsg->pPreOptEnd = pstart;
  769. }
  770. else
  771. {
  772. // on failure, reset current
  773. pMsg->pCurrent = pstart;
  774. }
  775. return( status );
  776. }
  777. DNS_STATUS
  778. Dns_WriteStandardRequestOptToMessage(
  779. IN OUT PDNS_MSG_BUF pMsg
  780. )
  781. /*++
  782. Routine Description:
  783. Write standard OPT record to message.
  784. This contains just the buffer size and version info,
  785. no error code or options.
  786. Arguments:
  787. pMsg -- message
  788. Return Value:
  789. ERROR_SUCCESS if successfully writen.
  790. ErrorCode on failure.
  791. --*/
  792. {
  793. if ( g_UseEdns == 0 )
  794. {
  795. return( ERROR_REQUEST_REFUSED );
  796. }
  797. return Dns_WriteOptToMessage(
  798. pMsg,
  799. (WORD) g_RecvBufSize,
  800. 0, // no rcode
  801. 0, // standard version
  802. NULL, // no data
  803. 0 // no data length
  804. );
  805. }
  806. DNS_STATUS
  807. Dns_AddRecordsToMessage(
  808. IN OUT PDNS_MSG_BUF pMsg,
  809. IN PDNS_RECORD pRecord,
  810. IN BOOL fUpdateMessage
  811. )
  812. /*++
  813. Routine Description:
  814. Add record or list of records to message.No data RR cases:
  815. This includes prereqs and deletes except for specific record cases.
  816. EXPORTED: resolver, mcast
  817. Arguments:
  818. pMsg - message buffer to write to
  819. pRecord - ptr to record (or first of list of records) to write to packet
  820. fUpdateMessage -- If TRUE, the message is going to contain an update.
  821. Therefore the section flags in the pRecord
  822. should be interpreted for update. Otherwise this is
  823. for a query message and section flags should be
  824. interpreted for query.
  825. Return Value:
  826. ERROR_SUCCESS if successful.
  827. Error code on failure.
  828. --*/
  829. {
  830. PCHAR pch = pMsg->pCurrent;
  831. PCHAR pendBuffer = pMsg->pBufferEnd;
  832. WORD currentSection = 0;
  833. WORD section;
  834. PSTR pnamePrevious = NULL;
  835. PSTR pnameRecord;
  836. WORD compressedPreviousName;
  837. WORD offsetPreviousName;
  838. PDNS_WIRE_RECORD pwireRecord;
  839. PCHAR pchnext;
  840. WORD index;
  841. DNS_STATUS status = ERROR_SUCCESS;
  842. BOOL funicode = FALSE;
  843. //
  844. // write each record in list
  845. //
  846. while ( pRecord )
  847. {
  848. //
  849. // determine section for record
  850. // - may not write to previous section
  851. section = (WORD) pRecord->Flags.S.Section;
  852. if ( section < currentSection )
  853. {
  854. DNS_PRINT((
  855. "ERROR: Attempt to write record at %p, with section %d\n"
  856. "\tless than previous section written %d.\n",
  857. pRecord,
  858. pRecord->Flags.S.Section,
  859. currentSection ));
  860. return( ERROR_INVALID_DATA );
  861. }
  862. else if ( section > currentSection )
  863. {
  864. currentSection = section;
  865. SET_CURRENT_RR_COUNT_SECTION( pMsg, section );
  866. }
  867. //
  868. // write record name
  869. // - if same as previous, write compressed name
  870. // - if first write from pRecord
  871. // - write full name
  872. // - clear reserved field for offsetting
  873. //
  874. pnameRecord = (PCHAR) pRecord->pName;
  875. if ( pnamePrevious &&
  876. ( !pnameRecord ||
  877. ( funicode
  878. ? !wcscmp( (PWSTR)pnamePrevious, (PWSTR)pnameRecord )
  879. : !strcmp( pnamePrevious, pnameRecord ) ) ) )
  880. {
  881. // compression should always be BACK ptr
  882. DNS_ASSERT( offsetPreviousName < pch - (PCHAR)&pMsg->MessageHead );
  883. if ( pendBuffer <= pch + sizeof(WORD) )
  884. {
  885. return( ERROR_MORE_DATA );
  886. }
  887. if ( ! compressedPreviousName )
  888. {
  889. compressedPreviousName = htons( (WORD)(0xC000 | offsetPreviousName) );
  890. }
  891. *(UNALIGNED WORD *)pch = compressedPreviousName;
  892. pch += sizeof( WORD );
  893. }
  894. else
  895. {
  896. offsetPreviousName = (WORD)(pch - (PCHAR)&pMsg->MessageHead);
  897. compressedPreviousName = 0;
  898. pnamePrevious = pnameRecord;
  899. funicode = (RECORD_CHARSET(pRecord) == DnsCharSetUnicode);
  900. pch = Dns_WriteDottedNameToPacket(
  901. pch,
  902. pendBuffer,
  903. pnamePrevious,
  904. NULL,
  905. 0,
  906. funicode );
  907. if ( !pch )
  908. {
  909. // DCR: distinguish out of space errors from name errors during write
  910. return( DNS_ERROR_INVALID_NAME );
  911. }
  912. }
  913. //
  914. // write record structure
  915. //
  916. if ( pch + sizeof(DNS_WIRE_RECORD) >= pendBuffer )
  917. {
  918. return( ERROR_MORE_DATA );
  919. }
  920. status = Dns_WriteRecordStructureToPacket(
  921. pch,
  922. pRecord,
  923. fUpdateMessage );
  924. if ( status != ERROR_SUCCESS )
  925. {
  926. return( status );
  927. }
  928. pwireRecord = (PDNS_WIRE_RECORD) pch;
  929. pch += sizeof( DNS_WIRE_RECORD );
  930. //
  931. // record data
  932. //
  933. if ( pRecord->wDataLength )
  934. {
  935. index = INDEX_FOR_TYPE( pRecord->wType );
  936. DNS_ASSERT( index <= MAX_RECORD_TYPE_INDEX );
  937. if ( index && RR_WriteTable[ index ] )
  938. {
  939. pchnext = RR_WriteTable[ index ](
  940. pRecord,
  941. pch,
  942. pendBuffer
  943. );
  944. if ( ! pchnext )
  945. {
  946. status = GetLastError();
  947. DNS_PRINT((
  948. "ERROR: Record write routine failure for record type %d.\n\n"
  949. "\tstatus = %d\n",
  950. pRecord->wType,
  951. status ));
  952. return( status );
  953. }
  954. }
  955. else
  956. {
  957. // write unknown types -- as RAW data only
  958. DNS_PRINT((
  959. "WARNING: Writing unknown type %d to message\n",
  960. pRecord->wType ));
  961. if ( pendBuffer - pch <= pRecord->wDataLength )
  962. {
  963. return( ERROR_MORE_DATA );
  964. }
  965. memcpy(
  966. pch,
  967. (PCHAR) &pRecord->Data,
  968. pRecord->wDataLength );
  969. pchnext = pch + pRecord->wDataLength;
  970. }
  971. //
  972. // set packet record data length
  973. //
  974. DNS_ASSERT( (pchnext - pch) < MAXWORD );
  975. *(UNALIGNED WORD *) &pwireRecord->DataLength =
  976. htons( (WORD)(pchnext - pch) );
  977. pch = pchnext;
  978. }
  979. // increment message record count
  980. CURRENT_RR_COUNT_FIELD(pMsg)++;
  981. pRecord = pRecord->pNext;
  982. }
  983. //
  984. // resest message current ptr
  985. //
  986. pMsg->pCurrent = pch;
  987. IF_DNSDBG( INIT )
  988. {
  989. DnsDbg_Message(
  990. "Packet after adding records:",
  991. pMsg );
  992. }
  993. return( status );
  994. }
  995. PDNS_MSG_BUF
  996. Dns_BuildPacket(
  997. IN PDNS_HEADER pHeader,
  998. IN BOOL fNoHeaderCounts,
  999. IN PDNS_NAME pszQuestionName,
  1000. IN WORD wQuestionType,
  1001. IN PDNS_RECORD pRecords,
  1002. IN DWORD dwFlags,
  1003. IN BOOL fUpdatePacket
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. Build packet.
  1008. Arguments:
  1009. pHeader -- DNS header to send
  1010. fNoHeaderCounts - do NOT include record counts in copying header
  1011. pszName -- DNS name to query
  1012. wType -- query type
  1013. pRecords -- address to receive ptr to record list returned from query
  1014. dwFlags -- query flags
  1015. fUpdatePacket -- If TRUE, the packet is going to contain an update.
  1016. Therefore the section flags in the pRecords
  1017. should be interpreted for update. Otherwise this is
  1018. for a query and section flags will be interpreted for
  1019. query.
  1020. Return Value:
  1021. ERROR_SUCCESS if successful.
  1022. Error code on failure.
  1023. --*/
  1024. {
  1025. PDNS_MSG_BUF pmsg;
  1026. DWORD length;
  1027. DNS_STATUS status;
  1028. DNSDBG( WRITE, (
  1029. "Dns_BuildPacket()\n"
  1030. "\tname %s\n"
  1031. "\ttype %d\n"
  1032. "\theader %p\n"
  1033. "\t - counts %d\n"
  1034. "\trecords %p\n"
  1035. "\tflags %08x\n"
  1036. "\tfUpdatePacket %d\n",
  1037. pszQuestionName,
  1038. wQuestionType,
  1039. pHeader,
  1040. fNoHeaderCounts,
  1041. pRecords,
  1042. dwFlags,
  1043. fUpdatePacket ));
  1044. //
  1045. // allocate packet
  1046. // - if just a question, standard UDP will do it
  1047. // - if contains records, then use TCP buffer
  1048. //
  1049. length = 0;
  1050. if ( pRecords )
  1051. {
  1052. length = DNS_TCP_DEFAULT_PACKET_LENGTH;
  1053. }
  1054. pmsg = Dns_AllocateMsgBuf( (WORD)length );
  1055. if ( !pmsg )
  1056. {
  1057. status = DNS_ERROR_NO_MEMORY;
  1058. goto Failed;
  1059. }
  1060. //
  1061. // write question?
  1062. //
  1063. if ( pszQuestionName )
  1064. {
  1065. if ( ! Dns_WriteQuestionToMessage(
  1066. pmsg,
  1067. (PDNS_NAME) pszQuestionName,
  1068. wQuestionType,
  1069. (BOOL)!!(dwFlags & DNSQUERY_UNICODE_NAME)
  1070. ) )
  1071. {
  1072. status = ERROR_INVALID_NAME;
  1073. goto Failed;
  1074. }
  1075. }
  1076. //
  1077. // build packet records
  1078. //
  1079. if ( pRecords )
  1080. {
  1081. status = Dns_AddRecordsToMessage(
  1082. pmsg,
  1083. pRecords,
  1084. fUpdatePacket );
  1085. if ( status != ERROR_SUCCESS )
  1086. {
  1087. DNS_PRINT((
  1088. "ERROR: failure writing records to message.\n" ));
  1089. goto Failed;
  1090. }
  1091. }
  1092. //
  1093. // append standard request OPT -- if possible
  1094. //
  1095. // DCR: currently no OPT for update
  1096. //
  1097. if ( !fUpdatePacket )
  1098. {
  1099. Dns_WriteStandardRequestOptToMessage( pmsg );
  1100. }
  1101. //
  1102. // overwrite header?
  1103. //
  1104. if ( pHeader )
  1105. {
  1106. length = sizeof(DNS_HEADER);
  1107. if ( fNoHeaderCounts )
  1108. {
  1109. length = sizeof(DWORD);
  1110. }
  1111. RtlCopyMemory(
  1112. & pmsg->MessageHead,
  1113. pHeader,
  1114. length );
  1115. }
  1116. // override recursion default, if desired
  1117. if ( dwFlags & DNS_QUERY_NO_RECURSION )
  1118. {
  1119. pmsg->MessageHead.RecursionDesired = FALSE;
  1120. }
  1121. // init XID if not set
  1122. if ( pmsg->MessageHead.Xid == 0 )
  1123. {
  1124. pmsg->MessageHead.Xid = Dns_GetRandomXid( pmsg );
  1125. }
  1126. return( pmsg );
  1127. Failed:
  1128. SetLastError( status );
  1129. FREE_HEAP( pmsg );
  1130. return( NULL );
  1131. }
  1132. //
  1133. // Reading from packet
  1134. //
  1135. PCHAR
  1136. _fastcall
  1137. Dns_SkipPacketName(
  1138. IN PCHAR pch,
  1139. IN PCHAR pchEnd
  1140. )
  1141. /*++
  1142. Routine Description:
  1143. Skips over name in packet
  1144. Arguments:
  1145. pch - ptr to start of name to skip
  1146. pchEnd - ptr to byte after end of packet
  1147. Return Value:
  1148. Ptr to next byte in buffer
  1149. NULL if bad name
  1150. --*/
  1151. {
  1152. register UCHAR cch;
  1153. register UCHAR cflag;
  1154. //
  1155. // Loop until end of name
  1156. //
  1157. while ( pch < pchEnd )
  1158. {
  1159. cch = *pch++;
  1160. cflag = cch & 0xC0;
  1161. //
  1162. // normal label
  1163. // - skip to next label and continue
  1164. // - stop only if at 0 (root) label
  1165. //
  1166. if ( cflag == 0 )
  1167. {
  1168. if ( cch )
  1169. {
  1170. pch += cch;
  1171. continue;
  1172. }
  1173. return( pch );
  1174. }
  1175. //
  1176. // compression
  1177. // - skip second byte in compression and return
  1178. //
  1179. else if ( cflag == 0xC0 )
  1180. {
  1181. pch++;
  1182. return( pch );
  1183. }
  1184. else
  1185. {
  1186. DNSDBG( READ, (
  1187. "ERROR: bad packet name label byte %02 at 0x%p\n",
  1188. cch,
  1189. pch - 1 ));
  1190. return( NULL );
  1191. }
  1192. }
  1193. DNSDBG( READ, (
  1194. "ERROR: packet name at %p reads past end of packet at %p\n",
  1195. pch,
  1196. pchEnd ));
  1197. return( NULL );
  1198. }
  1199. BOOL
  1200. Dns_IsSamePacketQuestion(
  1201. IN PDNS_MSG_BUF pMsg1,
  1202. IN PDNS_MSG_BUF pMsg2
  1203. )
  1204. /*++
  1205. Routine Description:
  1206. Compares questions in two messages.
  1207. Arguments:
  1208. pMsg1 -- first message
  1209. pMsg2 -- second message
  1210. Return Value:
  1211. TRUE if message questions equal.
  1212. FALSE if questions not equal.
  1213. --*/
  1214. {
  1215. PCHAR pquestion1;
  1216. PCHAR pquestion2;
  1217. PCHAR pnameEnd;
  1218. DWORD questionLength;
  1219. //
  1220. // validate and size the question fields
  1221. // - size must match
  1222. //
  1223. pquestion1 = pMsg1->MessageBody;
  1224. pnameEnd = Dns_SkipPacketName(
  1225. pquestion1,
  1226. pMsg1->pBufferEnd );
  1227. if ( !pnameEnd )
  1228. {
  1229. return FALSE;
  1230. }
  1231. questionLength = (DWORD)( pnameEnd - pquestion1 );
  1232. pquestion2 = pMsg2->MessageBody;
  1233. pnameEnd = Dns_SkipPacketName(
  1234. pquestion2,
  1235. pMsg2->pBufferEnd );
  1236. if ( !pnameEnd ||
  1237. questionLength != (DWORD)(pnameEnd - pquestion2) )
  1238. {
  1239. return FALSE;
  1240. }
  1241. //
  1242. // for speed, first do flat mem compare
  1243. // - this will hit 99% case as rarely would
  1244. // a server rewrite the question name
  1245. //
  1246. if ( RtlEqualMemory(
  1247. pquestion1,
  1248. pquestion2,
  1249. questionLength ) )
  1250. {
  1251. return TRUE;
  1252. }
  1253. //
  1254. // then do case sensitive compare
  1255. // - note, we do simple ANSI casing
  1256. // assume UTF8 extended chars MUST be downcased on the
  1257. // wire per spec
  1258. //
  1259. return !_strnicmp( pquestion1, pquestion2, questionLength );
  1260. }
  1261. PCHAR
  1262. _fastcall
  1263. Dns_SkipPacketRecord(
  1264. IN PCHAR pchRecord,
  1265. IN PCHAR pchMsgEnd
  1266. )
  1267. /*++
  1268. Routine Description:
  1269. Skips over packet RR.
  1270. This is RR structure and data, not the owner name.
  1271. Arguments:
  1272. pchRecord - ptr to start of RR structure.
  1273. pchMsgEnd - end of message
  1274. Return Value:
  1275. Ptr to next record in packet.
  1276. NULL if RR outside packet or invalid.
  1277. --*/
  1278. {
  1279. //
  1280. // skip RR struct
  1281. //
  1282. pchRecord += sizeof(DNS_WIRE_RECORD);
  1283. if ( pchRecord > pchMsgEnd )
  1284. {
  1285. return( NULL );
  1286. }
  1287. // read datalength and skip data
  1288. // datalength field is a WORD, at end of record header
  1289. pchRecord += InlineFlipUnalignedWord( pchRecord - sizeof(WORD) );
  1290. if ( pchRecord > pchMsgEnd )
  1291. {
  1292. return( NULL );
  1293. }
  1294. return( pchRecord );
  1295. }
  1296. PCHAR
  1297. Dns_SkipToRecord(
  1298. IN PDNS_HEADER pMsgHead,
  1299. IN PCHAR pMsgEnd,
  1300. IN INT iCount
  1301. )
  1302. /*++
  1303. Routine Description:
  1304. Skips over some number of DNS records.
  1305. Arguments:
  1306. pMsgHead -- ptr to begining of DNS message.
  1307. pMsgEnd -- ptr to end of DNS message
  1308. iCount -- if > 0, number of records to skip
  1309. if <= 0, number of records from end of packet
  1310. Return Value:
  1311. Ptr to next
  1312. NULL if bad packet.
  1313. --*/
  1314. {
  1315. PCHAR pch;
  1316. INT i;
  1317. WORD recordCount;
  1318. //
  1319. // determine how many records to skip
  1320. //
  1321. recordCount = pMsgHead->QuestionCount
  1322. + pMsgHead->AnswerCount
  1323. + pMsgHead->NameServerCount
  1324. + pMsgHead->AdditionalCount;
  1325. // iCount > 0 is skip count, MUST not be larger than
  1326. // actual count
  1327. if ( iCount > 0 )
  1328. {
  1329. if ( iCount > recordCount )
  1330. {
  1331. return( NULL );
  1332. }
  1333. }
  1334. // iCount <= 0 then (-iCount) is number of records
  1335. // from the last record
  1336. else
  1337. {
  1338. iCount += recordCount;
  1339. if ( iCount < 0 )
  1340. {
  1341. return( NULL );
  1342. }
  1343. }
  1344. // skip message header
  1345. pch = (PCHAR) (pMsgHead + 1);
  1346. if ( iCount == 0 )
  1347. {
  1348. return( pch );
  1349. }
  1350. //
  1351. // skip records
  1352. //
  1353. for ( i=0; i<iCount; i++ )
  1354. {
  1355. pch = Dns_SkipPacketName( pch, pMsgEnd );
  1356. if ( !pch )
  1357. {
  1358. return pch;
  1359. }
  1360. // skip question or RR
  1361. if ( i < pMsgHead->QuestionCount )
  1362. {
  1363. pch += sizeof(DNS_WIRE_QUESTION);
  1364. if ( pch > pMsgEnd )
  1365. {
  1366. return( NULL );
  1367. }
  1368. }
  1369. else
  1370. {
  1371. pch = Dns_SkipPacketRecord( pch, pMsgEnd );
  1372. if ( !pch )
  1373. {
  1374. return pch;
  1375. }
  1376. }
  1377. }
  1378. DNSDBG( READ, (
  1379. "Leaving SkipToRecord, current ptr = %p, offset = %04x\n"
  1380. "\tskipped %d records\n",
  1381. pch,
  1382. (WORD) (pch - (PCHAR)pMsgHead),
  1383. iCount ));
  1384. return( pch );
  1385. }
  1386. PCHAR
  1387. _fastcall
  1388. Dns_ReadPacketName(
  1389. IN OUT PCHAR pchNameBuffer,
  1390. OUT PWORD pwNameLength,
  1391. IN OUT PWORD pwNameOffset, OPTIONAL
  1392. OUT PBOOL pfNameSameAsPrevious, OPTIONAL
  1393. IN PCHAR pchName,
  1394. IN PCHAR pchStart,
  1395. IN PCHAR pchEnd
  1396. )
  1397. /*++
  1398. Routine Description:
  1399. Reads packet name and converts it to DNS-dotted format.
  1400. Arguments:
  1401. pchNameBuffer - buffer to write name into; contains previous name, if any
  1402. pwNameLength - length of name written to buffer; does not include
  1403. terminating NULL
  1404. pwNameOffset - addr with previous names offset (zero if no previous name);
  1405. on return, contains this name's offset
  1406. OPTIONAL but must exist if fNameSameAsPrevious exists
  1407. pfNameSameAsPrevious - addr of flag set if this name is same as previous;
  1408. OPTIONAL but must exist if pwNameOffset exists
  1409. pchName - ptr to name in packet
  1410. pchStart - start of DNS message
  1411. pchEnd - ptr to byte after end of DNS message
  1412. Return Value:
  1413. Ptr to next byte in packet.
  1414. NULL on error.
  1415. --*/
  1416. {
  1417. register PUCHAR pch = pchName;
  1418. register UCHAR cch;
  1419. register UCHAR cflag;
  1420. PCHAR pchdotted;
  1421. PCHAR pbufferEnd;
  1422. PCHAR pchreturn = NULL;
  1423. DNS_ASSERT( pch > pchStart && pchEnd > pchStart );
  1424. DNS_ASSERT( (pwNameOffset && pfNameSameAsPrevious) ||
  1425. (!pwNameOffset && !pfNameSameAsPrevious) );
  1426. //
  1427. // read through labels and/or compression until reach end of name
  1428. //
  1429. pbufferEnd = pchNameBuffer + DNS_MAX_NAME_LENGTH;
  1430. pchdotted = pchNameBuffer;
  1431. while ( pch < pchEnd )
  1432. {
  1433. cch = *pch++;
  1434. //
  1435. // at root label
  1436. // - if root name, write single '.'
  1437. // - otherwise strip trailing dot from last label
  1438. // - save length written
  1439. // - NULL teminate name
  1440. // - set same as previous FALSE
  1441. // - save packet offset to this name
  1442. // - return next byte in buffer
  1443. //
  1444. if ( cch == 0 )
  1445. {
  1446. if ( pchdotted == pchNameBuffer )
  1447. {
  1448. *pchdotted++ = '.';
  1449. }
  1450. else
  1451. {
  1452. pchdotted--;
  1453. }
  1454. *pwNameLength = (WORD)(pchdotted - pchNameBuffer);
  1455. *pchdotted = 0;
  1456. if ( pwNameOffset )
  1457. {
  1458. *pfNameSameAsPrevious = FALSE;
  1459. *pwNameOffset = (WORD)(pchName - pchStart);
  1460. }
  1461. return( pchreturn ? pchreturn : pch );
  1462. }
  1463. cflag = cch & 0xC0;
  1464. //
  1465. // regular label
  1466. // - copy label to buffer
  1467. // - jump to next label
  1468. if ( cflag == 0 )
  1469. {
  1470. PCHAR pchnext = pch + cch;
  1471. if ( pchnext >= pchEnd )
  1472. {
  1473. DNS_PRINT((
  1474. "ERROR: Packet name at %p extends past end of buffer\n",
  1475. pchName ));
  1476. goto Failed;
  1477. }
  1478. if ( pchdotted + cch + 1 >= pbufferEnd )
  1479. {
  1480. DNS_PRINT((
  1481. "ERROR: Packet name at %p exceeds max length\n",
  1482. pchName ));
  1483. goto Failed;
  1484. }
  1485. memcpy(
  1486. pchdotted,
  1487. pch,
  1488. cch );
  1489. pchdotted += cch;
  1490. *pchdotted++ = '.';
  1491. pch = pchnext;
  1492. continue;
  1493. }
  1494. //
  1495. // offset
  1496. // - get offset
  1497. // - if offset at start of name compare to previous name offset
  1498. // - otherwise follow offset to build new name
  1499. //
  1500. if ( cflag == 0xC0 )
  1501. {
  1502. WORD offset;
  1503. PCHAR pchoffset;
  1504. offset = (cch ^ 0xC0);
  1505. offset <<= 8;
  1506. offset |= *pch;
  1507. pchoffset = --pch;
  1508. //
  1509. // first offset
  1510. // - save return pointer
  1511. //
  1512. // if name is entirely offset
  1513. // - same as previous offset -- done
  1514. // - if not still save this offset rather than offset
  1515. // to name itself (first answer is usually just offset
  1516. // to question, subsequent answer RRs continue to reference
  1517. // question offset, not first answer)
  1518. //
  1519. if ( !pchreturn )
  1520. {
  1521. DNS_ASSERT( pch >= pchName );
  1522. pchreturn = pch+2;
  1523. if ( pchoffset == pchName && pwNameOffset )
  1524. {
  1525. if ( *pwNameOffset == offset )
  1526. {
  1527. *pfNameSameAsPrevious = TRUE;
  1528. return( pchreturn );
  1529. }
  1530. else
  1531. {
  1532. // save offset that comprises name
  1533. // then kill out copy of return ptr so don't
  1534. // return offset to pchName when finish copy
  1535. *pwNameOffset = offset;
  1536. *pfNameSameAsPrevious = FALSE;
  1537. pwNameOffset = NULL;
  1538. }
  1539. }
  1540. }
  1541. //
  1542. // make jump to new bytes and continue
  1543. // - verify offset is BEFORE current name
  1544. // and BEFORE current ptr
  1545. pch = pchStart + offset;
  1546. if ( pch >= pchName || pch >= pchoffset )
  1547. {
  1548. DNS_PRINT((
  1549. "ERROR: Bogus name offset %d, encountered at %p\n"
  1550. "\tto location %p past current position or original name.\n",
  1551. offset,
  1552. pchoffset,
  1553. pch ));
  1554. goto Failed;
  1555. }
  1556. continue;
  1557. }
  1558. // any other label byte is bogus
  1559. else
  1560. {
  1561. DNS_PRINT((
  1562. "ERROR: bogus name label byte %02x at %p\n",
  1563. cch,
  1564. pch - 1 ));
  1565. goto Failed;
  1566. }
  1567. }
  1568. DNS_PRINT((
  1569. "ERROR: packet name at %p reads to ptr %p past end of packet at %p\n",
  1570. pchName,
  1571. pch,
  1572. pchEnd ));
  1573. //
  1574. // failed
  1575. // - return NULL
  1576. // - set OUT params, keeps prefix happy on higher level calls
  1577. //
  1578. Failed:
  1579. *pwNameLength = 0;
  1580. if ( pwNameOffset )
  1581. {
  1582. *pwNameOffset = 0;
  1583. }
  1584. if ( pfNameSameAsPrevious )
  1585. {
  1586. *pfNameSameAsPrevious = FALSE;
  1587. }
  1588. return ( NULL );
  1589. }
  1590. PCHAR
  1591. _fastcall
  1592. Dns_ReadPacketNameAllocate(
  1593. IN OUT PCHAR * ppchName,
  1594. OUT PWORD pwNameLength,
  1595. IN OUT PWORD pwPrevNameOffset, OPTIONAL
  1596. OUT PBOOL pfNameSameAsPrevious, OPTIONAL
  1597. IN PCHAR pchPacketName,
  1598. IN PCHAR pchStart,
  1599. IN PCHAR pchEnd
  1600. )
  1601. /*++
  1602. Routine Description:
  1603. Reads packet name and creates (allocates) a copy in DNS-dotted format.
  1604. Arguments:
  1605. ppchName - addr to recv resulting name ptr
  1606. pwNameLength - length of name written to buffer
  1607. pwNameOffset - addr with previous names offset (zero if no previous name);
  1608. on return, contains this name's offset
  1609. OPTIONAL but must exist if fNameSameAsPrevious exists
  1610. fNameSameAsPrevious - addr of flag set if this name is same as previous;
  1611. OPTIONAL but must exist if pwNameOffset exists
  1612. pchPacketName - pch to name in packet
  1613. pchStart - start of DNS message
  1614. pchEnd - ptr to byte after end of DNS message
  1615. Return Value:
  1616. Ptr to next byte in packet.
  1617. NULL on error.
  1618. --*/
  1619. {
  1620. PCHAR pch;
  1621. PCHAR pallocName;
  1622. CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
  1623. WORD nameLength = DNS_MAX_NAME_BUFFER_LENGTH;
  1624. //
  1625. // read packet name into buffer
  1626. //
  1627. pch = Dns_ReadPacketName(
  1628. nameBuffer,
  1629. & nameLength,
  1630. pwPrevNameOffset,
  1631. pfNameSameAsPrevious,
  1632. pchPacketName,
  1633. pchStart,
  1634. pchEnd );
  1635. if ( !pch )
  1636. {
  1637. return( pch );
  1638. }
  1639. //
  1640. // allocate buffer for packet name
  1641. // - nameLength does not include terminating NULL
  1642. //
  1643. nameLength++;
  1644. pallocName = (PCHAR) ALLOCATE_HEAP( nameLength );
  1645. if ( !pallocName )
  1646. {
  1647. return( NULL );
  1648. }
  1649. RtlCopyMemory(
  1650. pallocName,
  1651. nameBuffer,
  1652. nameLength );
  1653. *ppchName = pallocName;
  1654. *pwNameLength = --nameLength;
  1655. DNSDBG( READ, (
  1656. "Allocated copy of packet name %s length %d\n",
  1657. pallocName,
  1658. nameLength ));
  1659. return( pch );
  1660. }
  1661. DNS_STATUS
  1662. Dns_ExtractRecordsFromMessage(
  1663. IN PDNS_MSG_BUF pMsg,
  1664. IN BOOL fUnicode,
  1665. OUT PDNS_RECORD * ppRecord
  1666. )
  1667. /*++
  1668. Routine Description:
  1669. Extract records from packet.
  1670. Arguments:
  1671. pMsg - message buffer to write to
  1672. fUnicode - flag indicating strings in record should be unicode
  1673. Return Value:
  1674. Ptr to parsed record list if any.
  1675. NULL if no record list or error.
  1676. --*/
  1677. {
  1678. PDNS_MESSAGE_BUFFER pDnsBuffer = (PDNS_MESSAGE_BUFFER) &pMsg->MessageHead;
  1679. return Dns_ExtractRecordsFromBuffer(
  1680. pDnsBuffer,
  1681. pMsg->MessageLength,
  1682. fUnicode,
  1683. ppRecord );
  1684. }
  1685. DNS_STATUS
  1686. Dns_ParseMessage(
  1687. OUT PDNS_PARSED_MESSAGE pParse,
  1688. IN PDNS_MESSAGE_BUFFER pDnsBuffer,
  1689. IN WORD wMessageLength,
  1690. IN DWORD Flags,
  1691. IN DNS_CHARSET OutCharSet
  1692. )
  1693. /*++
  1694. Routine Description:
  1695. Parse DNS message.
  1696. Arguments:
  1697. pParse - ptr to blob to receive parsed message
  1698. pDnsBuffer - message buffer to read from
  1699. wMessageLength -- message length
  1700. Flags - parsing options
  1701. OutCharSet - DNS character set; only UTF8 and unicode supported
  1702. Return Value:
  1703. RCODE error status on successful parse (including NO_ERROR)
  1704. DNS_INFO_NO_RECORDS -- on auth-empty response
  1705. // referral
  1706. DNS_ERROR_BAD_PACKET -- on bad packet
  1707. Note: even on failure caller must free data
  1708. --*/
  1709. {
  1710. register PCHAR pch;
  1711. PDNS_HEADER pwireMsg = (PDNS_HEADER) pDnsBuffer;
  1712. PCHAR pchpacketEnd;
  1713. DNS_PARSED_RR parsedRR;
  1714. PSTR pnameOwner;
  1715. PSTR pnameNew = NULL;
  1716. PWORD pCurrentCountField = NULL;
  1717. WORD countRR;
  1718. WORD countSection;
  1719. WORD typePrevious = 0;
  1720. WORD nameOffset = 0;
  1721. WORD nameLength;
  1722. WORD type;
  1723. WORD index;
  1724. BYTE section;
  1725. BOOL fnameSameAsPrevious;
  1726. PDNS_RECORD pnewRR;
  1727. DNS_RRSET rrset;
  1728. DNS_RRSET rrsetAlias;
  1729. DNS_RRSET rrsetSig;
  1730. DNS_STATUS status;
  1731. DNS_STATUS rcodeStatus;
  1732. CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
  1733. DNS_RECORD recordTemp;
  1734. DNSDBG( READ, (
  1735. "Dns_ParseMessage( %p, len=%d )\n",
  1736. pDnsBuffer,
  1737. wMessageLength
  1738. ));
  1739. //
  1740. // clear parsing blob
  1741. //
  1742. RtlZeroMemory(
  1743. pParse,
  1744. sizeof(DNS_PARSED_MESSAGE) );
  1745. //
  1746. // only UTF8 or unicode is supported directly
  1747. //
  1748. if ( OutCharSet != DnsCharSetUnicode &&
  1749. OutCharSet != DnsCharSetUtf8 )
  1750. {
  1751. ASSERT( FALSE );
  1752. return( ERROR_INVALID_PARAMETER );
  1753. }
  1754. //
  1755. // error code
  1756. // - map RCODE to DNS error
  1757. // - if other than NAME_ERROR, don't bother parsing
  1758. //
  1759. // DCR: option to parse with other errors
  1760. //
  1761. rcodeStatus = pwireMsg->ResponseCode;
  1762. if ( rcodeStatus != 0 )
  1763. {
  1764. rcodeStatus = Dns_MapRcodeToStatus( pwireMsg->ResponseCode );
  1765. if ( rcodeStatus != DNS_ERROR_RCODE_NAME_ERROR &&
  1766. !(Flags & DNS_PARSE_FLAG_RCODE_ALL) )
  1767. {
  1768. DNSDBG( READ, (
  1769. "No records extracted from response\n"
  1770. "\tresponse code = %d\n",
  1771. pwireMsg->ResponseCode ));
  1772. return( rcodeStatus );
  1773. }
  1774. }
  1775. //
  1776. // clear record holders
  1777. // - do now so safe in bad packet cleanup
  1778. //
  1779. DNS_RRSET_INIT( rrset );
  1780. DNS_RRSET_INIT( rrsetAlias );
  1781. DNS_RRSET_INIT( rrsetSig );
  1782. //
  1783. // copy message header
  1784. //
  1785. RtlCopyMemory(
  1786. & pParse->Header,
  1787. pwireMsg,
  1788. sizeof(DNS_HEADER) );
  1789. //
  1790. // read RRs in list of records
  1791. //
  1792. // loop through all resource records
  1793. // - skip question
  1794. // - build DNS_RECORD structure for other records
  1795. //
  1796. pchpacketEnd = (PCHAR)pwireMsg + wMessageLength;
  1797. pch = pDnsBuffer->MessageBody;
  1798. section = DNSREC_QUESTION;
  1799. pCurrentCountField = &pwireMsg->QuestionCount;
  1800. countSection = pwireMsg->QuestionCount;
  1801. countRR = 0;
  1802. while( 1 )
  1803. {
  1804. //
  1805. // changing sections
  1806. // save section number and RR count for current section
  1807. // note need immediate loop back to handle empty section
  1808. //
  1809. countRR++;
  1810. if ( countRR > countSection )
  1811. {
  1812. if ( section == DNSREC_QUESTION )
  1813. {
  1814. // no-op
  1815. }
  1816. else if ( section == DNSREC_ANSWER )
  1817. {
  1818. pParse->pAnswerRecords = rrset.pFirstRR;
  1819. }
  1820. else if ( section == DNSREC_AUTHORITY )
  1821. {
  1822. pParse->pAuthorityRecords = rrset.pFirstRR;
  1823. }
  1824. else if ( section == DNSREC_ADDITIONAL )
  1825. {
  1826. pParse->pAdditionalRecords = rrset.pFirstRR;
  1827. break;
  1828. }
  1829. section++;
  1830. pCurrentCountField++;
  1831. countSection = *(pCurrentCountField);
  1832. countRR = 0;
  1833. typePrevious = 0; // force new RR set
  1834. DNS_RRSET_INIT( rrset );
  1835. continue;
  1836. }
  1837. // validity check next RR
  1838. if ( pch >= pchpacketEnd )
  1839. {
  1840. DNS_PRINT((
  1841. "ERROR: reading bad packet %p.\n"
  1842. "\tat end of packet length with more records to process\n"
  1843. "\tpacket length = %ld\n"
  1844. "\tcurrent offset = %ld\n",
  1845. wMessageLength,
  1846. pch - (PCHAR)pwireMsg
  1847. ));
  1848. goto PacketError;
  1849. }
  1850. //
  1851. // read name, determining if same as previous name
  1852. //
  1853. IF_DNSDBG( READ2 )
  1854. {
  1855. DnsDbg_Lock();
  1856. DNS_PRINT((
  1857. "Reading record at offset %x\n",
  1858. (WORD)(pch - (PCHAR)pwireMsg) ));
  1859. DnsDbg_PacketName(
  1860. "Record name ",
  1861. pch,
  1862. pwireMsg,
  1863. pchpacketEnd,
  1864. "\n" );
  1865. DnsDbg_Unlock();
  1866. }
  1867. pch = Dns_ReadPacketName(
  1868. nameBuffer,
  1869. & nameLength,
  1870. & nameOffset,
  1871. & fnameSameAsPrevious,
  1872. pch,
  1873. (PCHAR) pwireMsg,
  1874. pchpacketEnd );
  1875. if ( ! pch )
  1876. {
  1877. DNS_PRINT(( "ERROR: bad packet name.\n" ));
  1878. goto PacketError;
  1879. }
  1880. IF_DNSDBG( READ2 )
  1881. {
  1882. DNS_PRINT((
  1883. "Owner name of record %s\n"
  1884. "\tlength = %d\n"
  1885. "\toffset = %d\n"
  1886. "\tfSameAsPrevious = %d\n",
  1887. nameBuffer,
  1888. nameLength,
  1889. nameOffset,
  1890. fnameSameAsPrevious ));
  1891. }
  1892. //
  1893. // question
  1894. //
  1895. if ( section == DNSREC_QUESTION )
  1896. {
  1897. PSTR pnameQuestion = NULL;
  1898. if ( !(Flags & DNS_PARSE_FLAG_NO_QUESTION) )
  1899. {
  1900. pnameQuestion = Dns_NameCopyAllocate(
  1901. nameBuffer,
  1902. (UCHAR) nameLength,
  1903. DnsCharSetUtf8, // UTF8 in
  1904. OutCharSet
  1905. );
  1906. }
  1907. pParse->pQuestionName = (LPTSTR) pnameQuestion;
  1908. if ( pch + sizeof(DNS_WIRE_QUESTION) > pchpacketEnd )
  1909. {
  1910. DNS_PRINT(( "ERROR: question exceeds packet length.\n" ));
  1911. goto PacketError;
  1912. }
  1913. pParse->QuestionType = InlineFlipUnalignedWord( pch );
  1914. pch += sizeof(WORD);
  1915. pParse->QuestionClass = InlineFlipUnalignedWord( pch );
  1916. pch += sizeof(WORD);
  1917. if ( Flags & DNS_PARSE_FLAG_ONLY_QUESTION )
  1918. {
  1919. break;
  1920. }
  1921. continue;
  1922. }
  1923. //
  1924. // extract RR info, type, datalength
  1925. // - verify RR within message
  1926. //
  1927. pch = Dns_ReadRecordStructureFromPacket(
  1928. pch,
  1929. pchpacketEnd,
  1930. & parsedRR );
  1931. if ( !pch )
  1932. {
  1933. DNS_PRINT(( "ERROR: bad RR struct out of packet.\n" ));
  1934. goto PacketError;
  1935. }
  1936. type = parsedRR.Type;
  1937. //
  1938. // type change -- then have new RR set
  1939. // - setup for new name
  1940. // - check and see if first non-alias answer
  1941. //
  1942. if ( type != typePrevious )
  1943. {
  1944. fnameSameAsPrevious = FALSE;
  1945. typePrevious = type;
  1946. }
  1947. //
  1948. // screen out OPT
  1949. //
  1950. // DCR: make screening configurable for API
  1951. //
  1952. if ( type == DNS_TYPE_OPT )
  1953. {
  1954. continue;
  1955. }
  1956. //
  1957. // screen out SIGs -- if not desired
  1958. //
  1959. #if 0
  1960. if ( type == DNS_TYPE_SIG &&
  1961. flag & NOSIG )
  1962. {
  1963. continue;
  1964. }
  1965. #endif
  1966. //
  1967. // make copy of new name
  1968. //
  1969. // DCR_FIX0: name same as previous
  1970. // flag indicates only that name not compressed to previous
  1971. // name (or previous compression)
  1972. // actually need abolute ingnore case compare
  1973. // with last records name to be sure that name not previous
  1974. //
  1975. if ( !fnameSameAsPrevious )
  1976. {
  1977. pnameNew = Dns_NameCopyAllocate(
  1978. nameBuffer,
  1979. (UCHAR) nameLength,
  1980. DnsCharSetUtf8, // UTF8 string in
  1981. OutCharSet
  1982. );
  1983. if ( !pnameNew )
  1984. {
  1985. status = DNS_ERROR_NO_MEMORY;
  1986. goto Failed;
  1987. }
  1988. pnameOwner = pnameNew;
  1989. DNSDBG( OFF, (
  1990. "Copy of owner name of record being read from packet %s\n",
  1991. nameBuffer ));
  1992. }
  1993. DNS_ASSERT( pnameOwner );
  1994. DNS_ASSERT( pnameNew || fnameSameAsPrevious );
  1995. //
  1996. // TSIG record requires owner name for versioning
  1997. //
  1998. recordTemp.pName = (PTCHAR) pnameOwner;
  1999. //
  2000. // read RR data for type
  2001. //
  2002. index = INDEX_FOR_TYPE( type );
  2003. DNS_ASSERT( index <= MAX_RECORD_TYPE_INDEX );
  2004. if ( !index || !RR_ReadTable[ index ] )
  2005. {
  2006. // unknown types -- index to NULL type to use
  2007. // FlatRecordRead()
  2008. DNS_PRINT((
  2009. "WARNING: Reading unknown record type %d from message\n",
  2010. parsedRR.Type ));
  2011. index = DNS_TYPE_NULL;
  2012. }
  2013. pnewRR = RR_ReadTable[ index ](
  2014. &recordTemp,
  2015. OutCharSet,
  2016. (PCHAR) pDnsBuffer,
  2017. parsedRR.pchData,
  2018. pch // end of record data
  2019. );
  2020. if ( ! pnewRR )
  2021. {
  2022. status = GetLastError();
  2023. ASSERT( status != ERROR_SUCCESS );
  2024. DNS_PRINT((
  2025. "ERROR: RR_ReadTable routine failure for type %d.\n"
  2026. "\tstatus = %d\n"
  2027. "\tpchdata = %p\n"
  2028. "\tpchend = %p\n",
  2029. parsedRR.Type,
  2030. status,
  2031. parsedRR.pchData,
  2032. pch ));
  2033. if ( status == ERROR_SUCCESS )
  2034. {
  2035. status = DNS_ERROR_NO_MEMORY;
  2036. }
  2037. goto Failed;
  2038. }
  2039. //
  2040. // write record info
  2041. // - first RR in set gets new name allocation
  2042. // and is responsible for cleanup
  2043. // - no data cleanup necessary as all data is
  2044. // contained in the RR allocation
  2045. //
  2046. pnewRR->pName = (PTCHAR) pnameOwner;
  2047. pnewRR->wType = type;
  2048. pnewRR->dwTtl = parsedRR.Ttl;
  2049. pnewRR->Flags.S.Section = section;
  2050. pnewRR->Flags.S.CharSet = OutCharSet;
  2051. FLAG_FreeOwner( pnewRR ) = !fnameSameAsPrevious;
  2052. FLAG_FreeData( pnewRR ) = FALSE;
  2053. //
  2054. // add RR to list
  2055. //
  2056. if ( type == DNS_TYPE_SIG &&
  2057. pParse->QuestionType != DNS_TYPE_SIG )
  2058. {
  2059. DNS_RRSET_ADD( rrsetSig, pnewRR );
  2060. }
  2061. else if ( type == DNS_TYPE_CNAME &&
  2062. pParse->QuestionType != DNS_TYPE_ALL &&
  2063. pParse->QuestionType != DNS_TYPE_CNAME &&
  2064. section == DNSREC_ANSWER )
  2065. {
  2066. DNS_RRSET_ADD( rrsetAlias, pnewRR );
  2067. }
  2068. else
  2069. {
  2070. DNS_RRSET_ADD( rrset, pnewRR );
  2071. }
  2072. // clear new ptr, as name now part of record
  2073. // this is strictly used to determine when pnameOwner
  2074. // must be cleaned up on failure
  2075. pnameNew = NULL;
  2076. } // end loop through packet's records
  2077. //
  2078. // set response info
  2079. //
  2080. // DCR: if don't want single SIG, easy to break out by section
  2081. //
  2082. pParse->pAliasRecords = rrsetAlias.pFirstRR;
  2083. pParse->pSigRecords = rrsetSig.pFirstRR;
  2084. //
  2085. // break out various query NO_ERROR responses
  2086. // - empty response
  2087. // - referral
  2088. // - garbage
  2089. //
  2090. if ( pwireMsg->AnswerCount == 0 &&
  2091. rcodeStatus == 0 &&
  2092. pwireMsg->Opcode == DNS_OPCODE_QUERY &&
  2093. pwireMsg->IsResponse )
  2094. {
  2095. PDNS_RECORD prrAuth = pParse->pAuthorityRecords;
  2096. if ( (prrAuth && prrAuth->wType == DNS_TYPE_SOA) ||
  2097. (!prrAuth && pwireMsg->Authoritative) )
  2098. {
  2099. rcodeStatus = DNS_INFO_NO_RECORDS;
  2100. DNSDBG( READ, ( "Empty-auth response at %p.\n", pwireMsg ));
  2101. }
  2102. else if ( prrAuth &&
  2103. prrAuth->wType == DNS_TYPE_NS &&
  2104. !pwireMsg->Authoritative &&
  2105. (!pwireMsg->RecursionAvailable || !pwireMsg->RecursionDesired) )
  2106. {
  2107. rcodeStatus = DNS_ERROR_REFERRAL_RESPONSE;
  2108. DNSDBG( READ, ( "Referral response at %p.\n", pwireMsg ));
  2109. }
  2110. else
  2111. {
  2112. rcodeStatus = DNS_ERROR_BAD_PACKET;
  2113. DNSDBG( ANY, ( "Bogus NO_ERROR response at %p.\n", pwireMsg ));
  2114. DNS_ASSERT( FALSE );
  2115. }
  2116. }
  2117. // verify never turn RCODE result into SUCCESS
  2118. ASSERT( pwireMsg->ResponseCode == 0 || rcodeStatus != ERROR_SUCCESS );
  2119. ASSERT( pnameNew == NULL );
  2120. pParse->Status = rcodeStatus;
  2121. IF_DNSDBG( RECV )
  2122. {
  2123. DnsDbg_ParsedMessage(
  2124. "Parsed message:\n",
  2125. pParse );
  2126. }
  2127. return( rcodeStatus );
  2128. PacketError:
  2129. DNS_PRINT(( "ERROR: bad packet in buffer.\n" ));
  2130. status = DNS_ERROR_BAD_PACKET;
  2131. Failed:
  2132. FREE_HEAP( pnameNew );
  2133. Dns_RecordListFree( rrset.pFirstRR );
  2134. Dns_RecordListFree( rrsetAlias.pFirstRR );
  2135. Dns_RecordListFree( rrsetSig.pFirstRR );
  2136. pParse->Status = status;
  2137. return( status );
  2138. }
  2139. VOID
  2140. Dns_FreeParsedMessageFields(
  2141. IN OUT PDNS_PARSED_MESSAGE pParse
  2142. )
  2143. /*++
  2144. Routine Description:
  2145. Free a parsed DNS message struct.
  2146. Arguments:
  2147. pParse - ptr to blob to receive parsed message
  2148. Return Value:
  2149. None
  2150. --*/
  2151. {
  2152. DNSDBG( TRACE, (
  2153. "Dns_FreeParsedMessageFields( %p )\n",
  2154. pParse ));
  2155. // question name
  2156. FREE_HEAP( pParse->pQuestionName );
  2157. // records
  2158. Dns_RecordListFree( pParse->pAliasRecords );
  2159. Dns_RecordListFree( pParse->pAnswerRecords );
  2160. Dns_RecordListFree( pParse->pAdditionalRecords );
  2161. Dns_RecordListFree( pParse->pAuthorityRecords );
  2162. Dns_RecordListFree( pParse->pSigRecords );
  2163. // clear to avoid confusion or double free
  2164. RtlZeroMemory(
  2165. pParse,
  2166. sizeof(DNS_PARSED_MESSAGE) );
  2167. }
  2168. DNS_STATUS
  2169. Dns_ExtractRecordsFromBuffer(
  2170. IN PDNS_MESSAGE_BUFFER pDnsBuffer,
  2171. IN WORD wMessageLength,
  2172. IN BOOL fUnicode,
  2173. OUT PDNS_RECORD * ppRecord
  2174. )
  2175. /*++
  2176. Routine Description:
  2177. Extract records from packet buffer.
  2178. Arguments:
  2179. pDnsBuffer - message buffer to read from
  2180. fUnicode - flag indicating strings in record should be unicode
  2181. Return Value:
  2182. Ptr to parsed record list if any.
  2183. NULL if no record list or error.
  2184. --*/
  2185. {
  2186. PDNS_RECORD prr;
  2187. DNS_STATUS status;
  2188. DNS_PARSED_MESSAGE parseBlob;
  2189. DNSDBG( READ, (
  2190. "Dns_ExtractRecordsFromBuffer( %p, len=%d )\n",
  2191. pDnsBuffer,
  2192. wMessageLength
  2193. ));
  2194. //
  2195. // call real parsing function
  2196. //
  2197. status = Dns_ParseMessage(
  2198. & parseBlob,
  2199. pDnsBuffer,
  2200. wMessageLength,
  2201. DNS_PARSE_FLAG_NO_QUESTION,
  2202. fUnicode
  2203. ? DnsCharSetUnicode
  2204. : DnsCharSetUtf8
  2205. );
  2206. //
  2207. // concatentate into one blob
  2208. // - work backwards so only touch each record once
  2209. //
  2210. // DCR: we have no real support for returning SIG records
  2211. // DCR: should append SIGs also?
  2212. //
  2213. prr = Dns_RecordListAppend(
  2214. parseBlob.pAuthorityRecords,
  2215. parseBlob.pAdditionalRecords
  2216. );
  2217. prr = Dns_RecordListAppend(
  2218. parseBlob.pAnswerRecords,
  2219. prr
  2220. );
  2221. prr = Dns_RecordListAppend(
  2222. parseBlob.pAliasRecords,
  2223. prr
  2224. );
  2225. *ppRecord = prr;
  2226. //
  2227. // cleanup
  2228. // - clear what we pick up
  2229. // - then free rest of blob
  2230. //
  2231. parseBlob.pAuthorityRecords = NULL;
  2232. parseBlob.pAdditionalRecords = NULL;
  2233. parseBlob.pAnswerRecords = NULL;
  2234. parseBlob.pAliasRecords = NULL;
  2235. Dns_FreeParsedMessageFields( &parseBlob );
  2236. IF_DNSDBG( RECV )
  2237. {
  2238. DnsDbg_RecordSet(
  2239. "Extracted records:\n",
  2240. prr );
  2241. }
  2242. return( status );
  2243. }
  2244. #if 0
  2245. DNS_STATUS
  2246. Dns_ExtractRecordsFromBuffer(
  2247. IN PDNS_MESSAGE_BUFFER pDnsBuffer,
  2248. IN WORD wMessageLength,
  2249. IN BOOL fUnicode,
  2250. OUT PDNS_RECORD * ppRecord
  2251. )
  2252. /*++
  2253. Routine Description:
  2254. Extract records from packet buffer.
  2255. Arguments:
  2256. pDnsBuffer - message buffer to read from
  2257. fUnicode - flag indicating strings in record should be unicode
  2258. Return Value:
  2259. Ptr to parsed record list if any.
  2260. NULL if no record list or error.
  2261. --*/
  2262. {
  2263. register PCHAR pch;
  2264. PDNS_HEADER pwireMsg = (PDNS_HEADER) pDnsBuffer;
  2265. PCHAR pchpacketEnd;
  2266. DNS_PARSED_RR parsedRR;
  2267. PSTR pnameOwner;
  2268. PSTR pnameNew = NULL;
  2269. DNS_CHARSET outCharSet;
  2270. WORD countRR;
  2271. WORD countSection;
  2272. WORD typePrevious = 0;
  2273. WORD nameOffset = 0;
  2274. WORD nameLength;
  2275. WORD index;
  2276. BYTE section;
  2277. BOOL fnameSameAsPrevious;
  2278. PDNS_RECORD pnewRR;
  2279. DNS_RRSET rrset;
  2280. DNS_STATUS status;
  2281. DNS_STATUS rcodeStatus;
  2282. CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
  2283. DNS_RECORD recordTemp;
  2284. PWORD pCurrentCountField = NULL;
  2285. DNSDBG( READ, (
  2286. "Dns_ExtractRecordsFromBuffer( %p, len=%d )\n",
  2287. pDnsBuffer,
  2288. wMessageLength
  2289. ));
  2290. //
  2291. // error code
  2292. // - map RCODE to DNS error
  2293. // - if other than NAME_ERROR, don't bother parsing
  2294. //
  2295. rcodeStatus = pwireMsg->ResponseCode;
  2296. if ( rcodeStatus != 0 )
  2297. {
  2298. rcodeStatus = Dns_MapRcodeToStatus( pwireMsg->ResponseCode );
  2299. if ( rcodeStatus != DNS_ERROR_RCODE_NAME_ERROR )
  2300. {
  2301. DNSDBG( READ, (
  2302. "No records extracted from response\n"
  2303. "\tresponse code = %d\n",
  2304. pwireMsg->ResponseCode ));
  2305. return( rcodeStatus );
  2306. }
  2307. }
  2308. DNS_RRSET_INIT( rrset );
  2309. //
  2310. // detemine char set
  2311. //
  2312. if ( fUnicode )
  2313. {
  2314. outCharSet = DnsCharSetUnicode;
  2315. }
  2316. else
  2317. {
  2318. outCharSet = DnsCharSetUtf8;
  2319. }
  2320. //
  2321. // read RRs in list of records
  2322. //
  2323. // loop through all resource records
  2324. // - skip question
  2325. // - build DNS_RECORD structure for other records
  2326. //
  2327. pchpacketEnd = (PCHAR)pwireMsg + wMessageLength;
  2328. pch = pDnsBuffer->MessageBody;
  2329. section = DNSREC_QUESTION;
  2330. pCurrentCountField = &pwireMsg->QuestionCount;
  2331. countSection = pwireMsg->QuestionCount;
  2332. countRR = 0;
  2333. while( 1 )
  2334. {
  2335. //
  2336. // changing sections
  2337. // save section number and RR count for current section
  2338. // note need immediate loop back to handle empty section
  2339. //
  2340. countRR++;
  2341. if ( countRR > countSection )
  2342. {
  2343. if ( section == DNSREC_ADDITIONAL )
  2344. {
  2345. break;
  2346. }
  2347. section++;
  2348. pCurrentCountField++;
  2349. countSection = *(pCurrentCountField);
  2350. countRR = 0;
  2351. continue;
  2352. }
  2353. // validity check next RR
  2354. if ( pch >= pchpacketEnd )
  2355. {
  2356. DNS_PRINT((
  2357. "ERROR: reading bad packet %p.\n"
  2358. "\tat end of packet length with more records to process\n"
  2359. "\tpacket length = %ld\n"
  2360. "\tcurrent offset = %ld\n",
  2361. pDnsBuffer,
  2362. wMessageLength,
  2363. pch - (PCHAR)pwireMsg
  2364. ));
  2365. goto PacketError;
  2366. }
  2367. //
  2368. // skip question
  2369. //
  2370. if ( section == DNSREC_QUESTION )
  2371. {
  2372. pch = Dns_SkipPacketName(
  2373. pch,
  2374. pchpacketEnd );
  2375. if ( !pch )
  2376. {
  2377. DNS_PRINT(( "ERROR: bad question name.\n" ));
  2378. goto PacketError;
  2379. }
  2380. pch += sizeof(DNS_WIRE_QUESTION);
  2381. if ( pch > pchpacketEnd )
  2382. {
  2383. DNS_PRINT(( "ERROR: question exceeds packet length.\n" ));
  2384. goto PacketError;
  2385. }
  2386. continue;
  2387. }
  2388. //
  2389. // read name, determining if same as previous name
  2390. //
  2391. IF_DNSDBG( READ2 )
  2392. {
  2393. DnsDbg_Lock();
  2394. DNS_PRINT((
  2395. "Reading record at offset %x\n",
  2396. (WORD)(pch - (PCHAR)pwireMsg) ));
  2397. DnsDbg_PacketName(
  2398. "Record name ",
  2399. pch,
  2400. pwireMsg,
  2401. pchpacketEnd,
  2402. "\n" );
  2403. DnsDbg_Unlock();
  2404. }
  2405. pch = Dns_ReadPacketName(
  2406. nameBuffer,
  2407. & nameLength,
  2408. & nameOffset,
  2409. & fnameSameAsPrevious,
  2410. pch,
  2411. (PCHAR) pwireMsg,
  2412. pchpacketEnd );
  2413. if ( ! pch )
  2414. {
  2415. DNS_PRINT(( "ERROR: bad packet name.\n" ));
  2416. goto PacketError;
  2417. }
  2418. IF_DNSDBG( READ2 )
  2419. {
  2420. DNS_PRINT((
  2421. "Owner name of record %s\n"
  2422. "\tlength = %d\n"
  2423. "\toffset = %d\n"
  2424. "\tfSameAsPrevious = %d\n",
  2425. nameBuffer,
  2426. nameLength,
  2427. nameOffset,
  2428. fnameSameAsPrevious ));
  2429. }
  2430. //
  2431. // extract RR info, type, datalength
  2432. // - verify RR within message
  2433. //
  2434. pch = Dns_ReadRecordStructureFromPacket(
  2435. pch,
  2436. pchpacketEnd,
  2437. & parsedRR );
  2438. if ( !pch )
  2439. {
  2440. DNS_PRINT(( "ERROR: bad RR struct out of packet.\n" ));
  2441. goto PacketError;
  2442. }
  2443. //
  2444. // on type change, always have new RR set
  2445. // - setup for new name
  2446. //
  2447. if ( parsedRR.Type != typePrevious )
  2448. {
  2449. fnameSameAsPrevious = FALSE;
  2450. typePrevious = parsedRR.Type;
  2451. }
  2452. //
  2453. // screen out OPT
  2454. //
  2455. // DCR: make screening configurable for API
  2456. //
  2457. if ( parsedRR.Type == DNS_TYPE_OPT )
  2458. {
  2459. continue;
  2460. }
  2461. //
  2462. // make copy of new name
  2463. //
  2464. // DCR_FIX0: name same as previous
  2465. // flag indicates only that name not compressed to previous
  2466. // name (or previous compression)
  2467. // actually need abolute ingnore case compare
  2468. // with last records name to be sure that name not previous
  2469. //
  2470. if ( !fnameSameAsPrevious )
  2471. {
  2472. pnameNew = Dns_NameCopyAllocate(
  2473. nameBuffer,
  2474. (UCHAR) nameLength,
  2475. DnsCharSetUtf8, // UTF8 string in
  2476. outCharSet
  2477. );
  2478. pnameOwner = pnameNew;
  2479. DNSDBG( READ2, (
  2480. "Copy of owner name of record being read from packet %s\n",
  2481. pnameOwner ));
  2482. }
  2483. DNS_ASSERT( pnameOwner );
  2484. DNS_ASSERT( pnameNew || fnameSameAsPrevious );
  2485. //
  2486. // TSIG record requires owner name for versioning
  2487. //
  2488. recordTemp.pName = pnameOwner;
  2489. //
  2490. // read RR data for type
  2491. //
  2492. index = INDEX_FOR_TYPE( parsedRR.Type );
  2493. DNS_ASSERT( index <= MAX_RECORD_TYPE_INDEX );
  2494. if ( !index || !RR_ReadTable[ index ] )
  2495. {
  2496. // unknown types -- index to NULL type to use
  2497. // FlatRecordRead()
  2498. DNS_PRINT((
  2499. "WARNING: Reading unknown record type %d from message\n",
  2500. parsedRR.Type ));
  2501. index = DNS_TYPE_NULL;
  2502. }
  2503. pnewRR = RR_ReadTable[ index ](
  2504. &recordTemp,
  2505. outCharSet,
  2506. (PCHAR) pDnsBuffer,
  2507. parsedRR.pchData,
  2508. pch // end of record data
  2509. );
  2510. if ( ! pnewRR )
  2511. {
  2512. status = GetLastError();
  2513. ASSERT( status != ERROR_SUCCESS );
  2514. DNS_PRINT((
  2515. "ERROR: RR_ReadTable routine failure for type %d.\n"
  2516. "\tstatus = %d\n"
  2517. "\tpchdata = %p\n"
  2518. "\tpchend = %p\n",
  2519. parsedRR.Type,
  2520. status,
  2521. parsedRR.pchData,
  2522. pch ));
  2523. if ( status == ERROR_SUCCESS )
  2524. {
  2525. status = DNS_ERROR_NO_MEMORY;
  2526. }
  2527. goto Failed;
  2528. }
  2529. //
  2530. // write record info
  2531. // - first RR in set gets new name allocation
  2532. // and is responsible for cleanup
  2533. // - no data cleanup necessary as all data is
  2534. // contained in the RR allocation
  2535. //
  2536. pnewRR->pName = pnameOwner;
  2537. pnewRR->wType = parsedRR.Type;
  2538. pnewRR->dwTtl = parsedRR.Ttl;
  2539. pnewRR->Flags.S.Section = section;
  2540. pnewRR->Flags.S.CharSet = outCharSet;
  2541. FLAG_FreeOwner( pnewRR ) = !fnameSameAsPrevious;
  2542. FLAG_FreeData( pnewRR ) = FALSE;
  2543. // add RR to list
  2544. DNS_RRSET_ADD( rrset, pnewRR );
  2545. // clear new ptr, as name now part of record
  2546. // this is strictly used to determine when pnameOwner
  2547. // must be cleaned up on failure
  2548. pnameNew = NULL;
  2549. } // end loop through packet's records
  2550. //
  2551. // return parsed record list
  2552. // - return DNS error for RCODE
  2553. // - set special return code to differentiate empty response
  2554. //
  2555. // DCR: should have special REFERRAL response
  2556. // - could overload NOTAUTH rcode
  2557. // DCR: should have special EMPTY_AUTH response
  2558. // - could have empty-auth overload NXRRSET
  2559. //
  2560. // DCR: best check on distinguishing EMPTY_AUTH from REFERRAL
  2561. //
  2562. if ( pwireMsg->AnswerCount == 0 && rcodeStatus == 0 )
  2563. {
  2564. if ( !rrset.pFirstRR || rrset.pFirstRR->wType == DNS_TYPE_SOA )
  2565. {
  2566. rcodeStatus = DNS_INFO_NO_RECORDS;
  2567. DNSDBG( READ, ( "Empty-auth response at %p.\n", pwireMsg ));
  2568. }
  2569. #if 0
  2570. else if ( rrset.pFirstRR->wType == DNS_TYPE_NS &&
  2571. !pwireMsg->Authoritative )
  2572. {
  2573. rcodeStatus = DNS_INFO_REFERRAL;
  2574. DNSDBG( READ, ( "Referral response at %p.\n", pwireMsg ));
  2575. }
  2576. else
  2577. {
  2578. rcodeStatus = DNS_ERROR_BAD_PACKET;
  2579. DNSDBG( READ, ( "Bogus NO_ERROR response at %p.\n", pwireMsg ));
  2580. }
  2581. #endif
  2582. }
  2583. // verify never turn RCODE result into SUCCESS
  2584. ASSERT( pwireMsg->ResponseCode == 0 || rcodeStatus != ERROR_SUCCESS );
  2585. ASSERT( pnameNew == NULL );
  2586. *ppRecord = rrset.pFirstRR;
  2587. IF_DNSDBG( RECV )
  2588. {
  2589. DnsDbg_RecordSet(
  2590. "Extracted records:\n",
  2591. *ppRecord );
  2592. }
  2593. return( rcodeStatus );
  2594. PacketError:
  2595. DNS_PRINT(( "ERROR: bad packet in buffer.\n" ));
  2596. status = DNS_ERROR_BAD_PACKET;
  2597. Failed:
  2598. FREE_HEAP( pnameNew );
  2599. Dns_RecordListFree( rrset.pFirstRR );
  2600. return( status );
  2601. }
  2602. #endif
  2603. VOID
  2604. Dns_NormalizeAllRecordTtls(
  2605. IN OUT PDNS_RECORD pRecord
  2606. )
  2607. /*++
  2608. Routine Description:
  2609. Finds the lowest TTL value in RR set and the sets all
  2610. records to that value.
  2611. Arguments:
  2612. pRecord - record set to normalize ttl values of.
  2613. Return Value:
  2614. None
  2615. --*/
  2616. {
  2617. PDNS_RECORD pTemp = pRecord;
  2618. DWORD dwTtl;
  2619. WORD wType;
  2620. //
  2621. // Get the Ttl of the first record (if there is one)
  2622. //
  2623. if ( pTemp )
  2624. {
  2625. dwTtl = pTemp->dwTtl;
  2626. wType = pTemp->wType;
  2627. pTemp = pTemp->pNext;
  2628. }
  2629. //
  2630. // Walk any remaining records looking for an even lower ttl value
  2631. //
  2632. while ( pTemp &&
  2633. pTemp->wType == wType &&
  2634. pTemp->Flags.S.Section == DNSREC_ANSWER )
  2635. {
  2636. if ( pTemp->dwTtl < dwTtl )
  2637. {
  2638. dwTtl = pTemp->dwTtl;
  2639. }
  2640. pTemp = pTemp->pNext;
  2641. }
  2642. //
  2643. // Set all records to this lowest ttl value
  2644. //
  2645. pTemp = pRecord;
  2646. while ( pTemp &&
  2647. pTemp->wType == wType &&
  2648. pTemp->Flags.S.Section == DNSREC_ANSWER )
  2649. {
  2650. pTemp->dwTtl = dwTtl;
  2651. pTemp = pTemp->pNext;
  2652. }
  2653. }
  2654. PCHAR
  2655. Dns_ReadRecordStructureFromPacket(
  2656. IN PCHAR pchPacket,
  2657. IN PCHAR pchMsgEnd,
  2658. IN OUT PDNS_PARSED_RR pParsedRR
  2659. )
  2660. /*++
  2661. Routine Description:
  2662. Read record structure from packet.
  2663. Arguments:
  2664. pchPacket - ptr to record structure in packet
  2665. pchMsgEnd - end of message
  2666. pParsedRR - ptr to struct to receive parsed RR
  2667. Return Value:
  2668. Ptr to next record in packet -- based on datalength.
  2669. Null on error.
  2670. --*/
  2671. {
  2672. PCHAR pch = pchPacket;
  2673. DNSDBG( READ2, (
  2674. "Dns_ReadRecordStructureFromPacket(%p).\n",
  2675. pch ));
  2676. //
  2677. // verify record structure within packet
  2678. //
  2679. if ( pch + sizeof(DNS_WIRE_RECORD) > pchMsgEnd )
  2680. {
  2681. DNS_PRINT((
  2682. "ERROR: record structure at %p is not within packet!.\n",
  2683. pchPacket ));
  2684. return( 0 );
  2685. }
  2686. //
  2687. // flip fields and write to aligned struct
  2688. //
  2689. pParsedRR->pchRR = pch;
  2690. pParsedRR->Type = InlineFlipUnalignedWord( pch );
  2691. pch += sizeof(WORD);
  2692. pParsedRR->Class = InlineFlipUnalignedWord( pch );
  2693. pch += sizeof(WORD);
  2694. pParsedRR->Ttl = InlineFlipUnalignedDword( pch );
  2695. pch += sizeof(DWORD);
  2696. pParsedRR->DataLength = InlineFlipUnalignedWord( pch );
  2697. pch += sizeof(WORD);
  2698. pParsedRR->pchData = pch;
  2699. //
  2700. // verify datalength does not extend beyond packet end
  2701. //
  2702. pch += pParsedRR->DataLength;
  2703. pParsedRR->pchNextRR = pch;
  2704. if ( pch > pchMsgEnd )
  2705. {
  2706. DNS_PRINT((
  2707. "ERROR: record data at %p (length %d) is not within packet!.\n",
  2708. pch - pParsedRR->DataLength,
  2709. pParsedRR->DataLength ));
  2710. return( 0 );
  2711. }
  2712. //
  2713. // return ptr to next record in packet
  2714. //
  2715. return( pch );
  2716. }
  2717. PCHAR
  2718. Dns_ParsePacketRecord(
  2719. IN PCHAR pchPacket,
  2720. IN PCHAR pchMsgEnd,
  2721. IN OUT PDNS_PARSED_RR pParsedRR
  2722. )
  2723. /*++
  2724. Routine Description:
  2725. Read record from packet.
  2726. Arguments:
  2727. pchPacket - ptr to record structure in packet
  2728. pchMsgEnd - end of message
  2729. pParsedRR - ptr to struct to receive parsed RR
  2730. Return Value:
  2731. Ptr to next record in packet -- based on datalength.
  2732. Null on error.
  2733. --*/
  2734. {
  2735. PCHAR pch;
  2736. DNSDBG( READ2, (
  2737. "Dns_ParsePacketRecord().\n"
  2738. "\tpRecordStart = %p\n"
  2739. "\tpMsgEnd = %p\n",
  2740. pchPacket,
  2741. pchMsgEnd ));
  2742. //
  2743. // save and skip name
  2744. //
  2745. pch = Dns_SkipPacketName(
  2746. pchPacket,
  2747. pchMsgEnd );
  2748. if ( !pch )
  2749. {
  2750. return( pch );
  2751. }
  2752. pParsedRR->pchName = pchPacket;
  2753. //
  2754. // parse record structure
  2755. //
  2756. pch = Dns_ReadRecordStructureFromPacket(
  2757. pch,
  2758. pchMsgEnd,
  2759. pParsedRR );
  2760. return( pch );
  2761. }
  2762. //
  2763. // XID utilities
  2764. //
  2765. // Max increase in XID space, used in mod() op
  2766. // so pick nice prime number
  2767. #define MAX_XID_BUMP (487)
  2768. // XID seed
  2769. WORD g_XidSeed = 0;
  2770. // last XID for process
  2771. WORD g_LastXid = 0;
  2772. // XID mask
  2773. WORD g_XidMask = 0;
  2774. WORD
  2775. Dns_GetRandomXid(
  2776. IN PVOID pSeed
  2777. )
  2778. /*++
  2779. Routine Description:
  2780. Generate "random" XID.
  2781. By "random" what we really mean is an XID that's not the same as previous XIDs
  2782. and is not immediately guessable from the outside.
  2783. Arguments:
  2784. pSeed -- seed ptr; from stack or heap, provides differentiation beyond time
  2785. Return Value:
  2786. XID generated
  2787. --*/
  2788. {
  2789. WORD xid;
  2790. //
  2791. // build "bump" off
  2792. //
  2793. // may have multiple sessions to different processes\threads
  2794. //
  2795. // use tick count (unpredictability)
  2796. // seed counter (non-repetition of jumps and MT separation)
  2797. // seed ptr (MT separation)
  2798. // note, ptr is first pushed down to count 64-bit boundaries, so lack of
  2799. // randomness in last 6bits is not preserved
  2800. //
  2801. xid = (WORD) (GetTickCount() + (PtrToUlong(pSeed) >> 6) + g_XidSeed++);
  2802. if ( g_XidMask == 0 )
  2803. {
  2804. g_XidMask = xid ;
  2805. }
  2806. //
  2807. // XID is bump off last XID
  2808. // - the limiting this bump limits possibility of XID reuse
  2809. // in less than 64K/max-bump XIDs
  2810. // - don't use zero XID
  2811. // - flip just to generate more confusion, hackers will have the code
  2812. // and can generate XIDs so the real protection here is the MAX_XID_BUMP
  2813. // which means MAX_XID_BUMP packets need to be generated -- it's not 64K
  2814. // but it's a bunch
  2815. //
  2816. xid = (xid % MAX_XID_BUMP) + 1 + g_LastXid;
  2817. if ( xid == 0 )
  2818. {
  2819. xid = 5;
  2820. }
  2821. g_LastXid = xid;
  2822. return htons( xid ^ g_XidMask );
  2823. }
  2824. //
  2825. // End packet.c
  2826. //