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.

1802 lines
42 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. rrread.c
  5. Abstract:
  6. Domain Name System (DNS) Library
  7. Read resource record from packet routines.
  8. Author:
  9. Jim Gilroy (jamesg) January, 1997
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. PDNS_RECORD
  14. A_RecordRead(
  15. IN OUT PDNS_RECORD pRR,
  16. IN DNS_CHARSET OutCharSet,
  17. IN OUT PCHAR pchStart,
  18. IN PCHAR pchData,
  19. IN PCHAR pchEnd
  20. )
  21. /*++
  22. Routine Description:
  23. Read A record data from packet.
  24. Arguments:
  25. pRR - RR context
  26. pchStart - start of DNS message
  27. pchData - ptr to packet RR data
  28. wLength - length of RR data in packet
  29. Return Value:
  30. Ptr to new record if successful.
  31. NULL on failure.
  32. --*/
  33. {
  34. PDNS_RECORD precord;
  35. if ( pchEnd - pchData != sizeof(IP4_ADDRESS) )
  36. {
  37. SetLastError( ERROR_INVALID_DATA );
  38. return( NULL );
  39. }
  40. precord = Dns_AllocateRecord( sizeof(IP4_ADDRESS) );
  41. if ( !precord )
  42. {
  43. return( NULL );
  44. }
  45. precord->Data.A.IpAddress = *(UNALIGNED DWORD *) pchData;
  46. return( precord );
  47. }
  48. PDNS_RECORD
  49. Ptr_RecordRead(
  50. IN OUT PDNS_RECORD pRR,
  51. IN DNS_CHARSET OutCharSet,
  52. IN OUT PCHAR pchStart,
  53. IN PCHAR pchData,
  54. IN PCHAR pchEnd
  55. )
  56. /*++
  57. Routine Description:
  58. Process PTR compatible record from wire.
  59. Includes: NS, PTR, CNAME, MB, MR, MG, MD, MF
  60. Arguments:
  61. pRR - ptr to record with RR set context
  62. pchStart - start of DNS message
  63. pchData - ptr to RR data field
  64. pchEnd - ptr to byte after data field
  65. Return Value:
  66. Ptr to new record if successful.
  67. NULL on failure.
  68. --*/
  69. {
  70. PDNS_RECORD precord;
  71. WORD bufLength;
  72. WORD nameLength;
  73. CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
  74. //
  75. // PTR data is another domain name
  76. //
  77. pchData = Dns_ReadPacketName(
  78. nameBuffer,
  79. & nameLength,
  80. NULL,
  81. NULL,
  82. pchData,
  83. pchStart,
  84. pchEnd );
  85. if ( pchData != pchEnd )
  86. {
  87. DNS_PRINT(( "ERROR: bad packet name.\n" ));
  88. SetLastError( DNS_ERROR_INVALID_NAME );
  89. return( NULL );
  90. }
  91. //
  92. // determine required buffer length and allocate
  93. //
  94. bufLength = sizeof( DNS_PTR_DATA );
  95. bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength, OutCharSet );
  96. precord = Dns_AllocateRecord( bufLength );
  97. if ( !precord )
  98. {
  99. return( NULL );
  100. }
  101. //
  102. // write hostname into buffer, immediately following PTR data struct
  103. //
  104. precord->Data.PTR.pNameHost = (PCHAR)&precord->Data + sizeof( DNS_PTR_DATA );
  105. Dns_NameCopy(
  106. precord->Data.PTR.pNameHost,
  107. NULL, // no buffer length
  108. nameBuffer,
  109. nameLength,
  110. DnsCharSetWire,
  111. OutCharSet
  112. );
  113. return( precord );
  114. }
  115. PDNS_RECORD
  116. Soa_RecordRead(
  117. IN OUT PDNS_RECORD pRR,
  118. IN DNS_CHARSET OutCharSet,
  119. IN OUT PCHAR pchStart,
  120. IN PCHAR pchData,
  121. IN PCHAR pchEnd
  122. )
  123. /*++
  124. Routine Description:
  125. Read SOA record from wire.
  126. Arguments:
  127. pRR - ptr to record with RR set context
  128. pchStart - start of DNS message
  129. pchData - ptr to RR data field
  130. pchEnd - ptr to byte after data field
  131. Return Value:
  132. Ptr to new record if successful.
  133. NULL on failure.
  134. --*/
  135. {
  136. PDNS_RECORD precord;
  137. WORD bufLength;
  138. PCHAR pchendFixed;
  139. PDWORD pdword;
  140. WORD nameLength1;
  141. WORD nameLength2;
  142. CHAR nameBuffer1[ DNS_MAX_NAME_BUFFER_LENGTH ];
  143. CHAR nameBuffer2[ DNS_MAX_NAME_BUFFER_LENGTH ];
  144. //
  145. // read DNS names
  146. //
  147. pchData = Dns_ReadPacketName(
  148. nameBuffer1,
  149. & nameLength1,
  150. NULL,
  151. NULL,
  152. pchData,
  153. pchStart,
  154. pchEnd );
  155. if ( !pchData || pchData >= pchEnd )
  156. {
  157. DNS_PRINT(( "ERROR: bad packet name.\n" ));
  158. SetLastError( DNS_ERROR_INVALID_NAME );
  159. return( NULL );
  160. }
  161. pchData = Dns_ReadPacketName(
  162. nameBuffer2,
  163. & nameLength2,
  164. NULL,
  165. NULL,
  166. pchData,
  167. pchStart,
  168. pchEnd );
  169. pchendFixed = pchData + SIZEOF_SOA_FIXED_DATA;
  170. if ( pchendFixed != pchEnd )
  171. {
  172. DNS_PRINT(( "ERROR: bad packet name.\n" ));
  173. SetLastError( DNS_ERROR_INVALID_NAME );
  174. return( NULL );
  175. }
  176. //
  177. // determine required buffer length and allocate
  178. //
  179. bufLength = sizeof( DNS_SOA_DATA );
  180. bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength1, OutCharSet );
  181. bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength2, OutCharSet );
  182. precord = Dns_AllocateRecord( bufLength );
  183. if ( !precord )
  184. {
  185. return( NULL );
  186. }
  187. //
  188. // copy fixed fields
  189. //
  190. pdword = &precord->Data.SOA.dwSerialNo;
  191. while ( pchData < pchendFixed )
  192. {
  193. *pdword++ = FlipUnalignedDword( pchData );
  194. pchData += sizeof(DWORD);
  195. }
  196. //
  197. // copy names into RR buffer
  198. // - primary server immediately follows SOA data struct
  199. // - responsible party follows primary server
  200. //
  201. precord->Data.SOA.pNamePrimaryServer =
  202. (PCHAR)&precord->Data + sizeof(DNS_SOA_DATA);
  203. precord->Data.SOA.pNameAdministrator =
  204. precord->Data.SOA.pNamePrimaryServer +
  205. Dns_NameCopy(
  206. precord->Data.SOA.pNamePrimaryServer,
  207. NULL, // no buffer length
  208. nameBuffer1,
  209. nameLength1,
  210. DnsCharSetWire,
  211. OutCharSet );
  212. Dns_NameCopy(
  213. precord->Data.SOA.pNameAdministrator,
  214. NULL, // no buffer length
  215. nameBuffer2,
  216. nameLength2,
  217. DnsCharSetWire,
  218. OutCharSet
  219. );
  220. return( precord );
  221. }
  222. PDNS_RECORD
  223. Txt_RecordRead(
  224. IN OUT PDNS_RECORD pRR,
  225. IN DNS_CHARSET OutCharSet,
  226. IN OUT PCHAR pchStart,
  227. IN PCHAR pchData,
  228. IN PCHAR pchEnd
  229. )
  230. /*++
  231. Routine Description:
  232. Read TXT compatible record from wire.
  233. Includes: TXT, X25, HINFO, ISDN
  234. Arguments:
  235. pRR - ptr to record with RR set context
  236. pchStart - start of DNS message
  237. pchData - ptr to RR data field
  238. pchEnd - ptr to byte after data field
  239. Return Value:
  240. Ptr to new record if successful.
  241. NULL on failure.
  242. --*/
  243. {
  244. PDNS_RECORD precord;
  245. WORD bufLength;
  246. WORD length;
  247. INT count;
  248. PCHAR pch;
  249. PCHAR pchbuffer;
  250. PCHAR * ppstring;
  251. //
  252. // determine required buffer length and allocate
  253. // - allocate space for each string
  254. // - and ptr for each string
  255. //
  256. bufLength = 0;
  257. count = 0;
  258. pch = pchData;
  259. while ( pch < pchEnd )
  260. {
  261. length = (UCHAR) *pch++;
  262. pch += length;
  263. count++;
  264. bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( length, OutCharSet );
  265. }
  266. if ( pch != pchEnd )
  267. {
  268. DNS_PRINT((
  269. "ERROR: Invalid packet string data.\n"
  270. "\tpch = %p\n"
  271. "\tpchEnd = %p\n"
  272. "\tcount = %d\n"
  273. "\tlength = %d\n",
  274. pch, pchEnd, count, length
  275. ));
  276. SetLastError( ERROR_INVALID_DATA );
  277. return( NULL );
  278. }
  279. // allocate
  280. bufLength += (WORD) DNS_TEXT_RECORD_LENGTH(count);
  281. precord = Dns_AllocateRecord( bufLength );
  282. if ( !precord )
  283. {
  284. return( NULL );
  285. }
  286. precord->Data.TXT.dwStringCount = count;
  287. //
  288. // DCR: if separate HINFO type -- handle this here
  289. // - set pointer differently
  290. // - validate string count found
  291. //
  292. //
  293. // go back through list copying strings to buffer
  294. // - ptrs to strings are saved to argv like data section
  295. // ppstring walks through this section
  296. // - first string written immediately following data section
  297. // - each subsequent string immediately follows predecessor
  298. // pchbuffer keeps ptr to position to write strings
  299. //
  300. pch = pchData;
  301. ppstring = (PCHAR *) precord->Data.TXT.pStringArray;
  302. pchbuffer = (PBYTE)ppstring + (count * sizeof(PCHAR));
  303. while ( pch < pchEnd )
  304. {
  305. length = (UCHAR) *pch++;
  306. #if DBG
  307. DNS_PRINT((
  308. "Reading text at %p (len %d), to buffer at %p\n"
  309. "\tsave text ptr[%d] at %p in precord (%p)\n",
  310. pch,
  311. length,
  312. pchbuffer,
  313. (PCHAR *) ppstring - (PCHAR *) precord->Data.TXT.pStringArray,
  314. ppstring,
  315. precord ));
  316. #endif
  317. *ppstring++ = pchbuffer;
  318. pchbuffer += Dns_StringCopy(
  319. pchbuffer,
  320. NULL,
  321. pch,
  322. length,
  323. DnsCharSetWire,
  324. OutCharSet );
  325. pch += length;
  326. #if DBG
  327. DNS_PRINT((
  328. "Read text string %s\n",
  329. * (ppstring - 1)
  330. ));
  331. count--;
  332. #endif
  333. }
  334. DNS_ASSERT( pch == pchEnd && count == 0 );
  335. return( precord );
  336. }
  337. PDNS_RECORD
  338. Minfo_RecordRead(
  339. IN OUT PDNS_RECORD pRR,
  340. IN DNS_CHARSET OutCharSet,
  341. IN OUT PCHAR pchStart,
  342. IN PCHAR pchData,
  343. IN PCHAR pchEnd
  344. )
  345. /*++
  346. Routine Description:
  347. Read MINFO record from wire.
  348. Arguments:
  349. pRR - ptr to record with RR set context
  350. pchStart - start of DNS message
  351. pchData - ptr to RR data field
  352. pchEnd - ptr to byte after data field
  353. Return Value:
  354. Ptr to new record if successful.
  355. NULL on failure.
  356. --*/
  357. {
  358. PDNS_RECORD precord;
  359. WORD bufLength;
  360. WORD nameLength1;
  361. WORD nameLength2;
  362. CHAR nameBuffer1[ DNS_MAX_NAME_BUFFER_LENGTH ];
  363. CHAR nameBuffer2[ DNS_MAX_NAME_BUFFER_LENGTH ];
  364. //
  365. // read DNS names
  366. //
  367. pchData = Dns_ReadPacketName(
  368. nameBuffer1,
  369. & nameLength1,
  370. NULL,
  371. NULL,
  372. pchData,
  373. pchStart,
  374. pchEnd );
  375. if ( !pchData || pchData >= pchEnd )
  376. {
  377. DNS_PRINT(( "ERROR: bad packet name.\n" ));
  378. SetLastError( DNS_ERROR_INVALID_NAME );
  379. return( NULL );
  380. }
  381. pchData = Dns_ReadPacketName(
  382. nameBuffer2,
  383. & nameLength2,
  384. NULL,
  385. NULL,
  386. pchData,
  387. pchStart,
  388. pchEnd );
  389. if ( pchData != pchEnd )
  390. {
  391. DNS_PRINT(( "ERROR: bad packet name.\n" ));
  392. SetLastError( DNS_ERROR_INVALID_NAME );
  393. return( NULL );
  394. }
  395. //
  396. // determine required buffer length and allocate
  397. //
  398. bufLength = sizeof( DNS_MINFO_DATA );
  399. bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength1, OutCharSet );
  400. bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength2, OutCharSet );
  401. precord = Dns_AllocateRecord( bufLength );
  402. if ( !precord )
  403. {
  404. return( NULL );
  405. }
  406. //
  407. // copy names into RR buffer
  408. // - primary server immediately follows MINFO data struct
  409. // - responsible party follows primary server
  410. //
  411. precord->Data.MINFO.pNameMailbox =
  412. (PCHAR)&precord->Data + sizeof( DNS_MINFO_DATA );
  413. precord->Data.MINFO.pNameErrorsMailbox =
  414. precord->Data.MINFO.pNameMailbox +
  415. Dns_NameCopy(
  416. precord->Data.MINFO.pNameMailbox,
  417. NULL, // no buffer length
  418. nameBuffer1,
  419. nameLength1,
  420. DnsCharSetWire,
  421. OutCharSet );
  422. Dns_NameCopy(
  423. precord->Data.MINFO.pNameErrorsMailbox,
  424. NULL, // no buffer length
  425. nameBuffer2,
  426. nameLength2,
  427. DnsCharSetWire,
  428. OutCharSet
  429. );
  430. return( precord );
  431. }
  432. PDNS_RECORD
  433. Mx_RecordRead(
  434. IN OUT PDNS_RECORD pRR,
  435. IN DNS_CHARSET OutCharSet,
  436. IN OUT PCHAR pchStart,
  437. IN PCHAR pchData,
  438. IN PCHAR pchEnd
  439. )
  440. /*++
  441. Routine Description:
  442. Read MX compatible record from wire.
  443. Includes: MX, RT, AFSDB
  444. Arguments:
  445. pRR - ptr to record with RR set context
  446. pchStart - start of DNS message
  447. pchData - ptr to RR data field
  448. pchEnd - ptr to byte after data field
  449. Return Value:
  450. Ptr to new record if successful.
  451. NULL on failure.
  452. --*/
  453. {
  454. PDNS_RECORD precord;
  455. WORD bufLength;
  456. WORD nameLength;
  457. WORD wpreference;
  458. CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
  459. // read preference value
  460. wpreference = FlipUnalignedWord( pchData );
  461. pchData += sizeof(WORD);
  462. // read mail exchange
  463. pchData = Dns_ReadPacketName(
  464. nameBuffer,
  465. & nameLength,
  466. NULL,
  467. NULL,
  468. pchData,
  469. pchStart,
  470. pchEnd );
  471. if ( pchData != pchEnd )
  472. {
  473. DNS_PRINT(( "ERROR: bad packet name.\n" ));
  474. SetLastError( DNS_ERROR_INVALID_NAME );
  475. return( NULL );
  476. }
  477. //
  478. // determine required buffer length and allocate
  479. //
  480. bufLength = sizeof( DNS_MX_DATA );
  481. bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength, OutCharSet );
  482. precord = Dns_AllocateRecord( bufLength );
  483. if ( !precord )
  484. {
  485. return( NULL );
  486. }
  487. // copy preference
  488. precord->Data.MX.wPreference = wpreference;
  489. //
  490. // write exchange name into buffer, immediately following MX data struct
  491. //
  492. precord->Data.MX.pNameExchange = (PCHAR)&precord->Data + sizeof( DNS_MX_DATA );
  493. Dns_NameCopy(
  494. precord->Data.MX.pNameExchange,
  495. NULL, // no buffer length
  496. nameBuffer,
  497. nameLength,
  498. DnsCharSetWire,
  499. OutCharSet
  500. );
  501. return( precord );
  502. }
  503. PDNS_RECORD
  504. Flat_RecordRead(
  505. IN OUT PDNS_RECORD pRR,
  506. IN DNS_CHARSET OutCharSet,
  507. IN OUT PCHAR pchStart,
  508. IN PCHAR pchData,
  509. IN PCHAR pchEnd
  510. )
  511. /*++
  512. Routine Description:
  513. Read memory copy compatible record from wire.
  514. Includes AAAA type.
  515. Arguments:
  516. pRR - ptr to record with RR set context
  517. pchStart - start of DNS message
  518. pchData - ptr to RR data field
  519. pchEnd - ptr to byte after data field
  520. Return Value:
  521. Ptr to new record if successful.
  522. NULL on failure.
  523. --*/
  524. {
  525. PDNS_RECORD precord;
  526. WORD bufLength;
  527. //
  528. // determine required buffer length and allocate
  529. //
  530. bufLength = (WORD)(pchEnd - pchData);
  531. precord = Dns_AllocateRecord( bufLength );
  532. if ( !precord )
  533. {
  534. return( NULL );
  535. }
  536. //
  537. // copy packet data to record
  538. //
  539. memcpy(
  540. & precord->Data,
  541. pchData,
  542. bufLength );
  543. return( precord );
  544. }
  545. PDNS_RECORD
  546. Srv_RecordRead(
  547. IN OUT PDNS_RECORD pRR,
  548. IN DNS_CHARSET OutCharSet,
  549. IN OUT PCHAR pchStart,
  550. IN PCHAR pchData,
  551. IN PCHAR pchEnd
  552. )
  553. /*++
  554. Routine Description:
  555. Read SRV record from wire.
  556. Arguments:
  557. pRR - ptr to record with RR set context
  558. pchStart - start of DNS message
  559. pchData - ptr to RR data field
  560. pchEnd - ptr to byte after data field
  561. Return Value:
  562. Ptr to new record if successful.
  563. NULL on failure.
  564. --*/
  565. {
  566. PDNS_RECORD precord;
  567. WORD bufLength;
  568. WORD nameLength;
  569. PCHAR pchstart;
  570. CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
  571. //
  572. // read SRV target name
  573. // - name is after fixed length integer data
  574. pchstart = pchData;
  575. pchData += SIZEOF_SRV_FIXED_DATA;
  576. pchData = Dns_ReadPacketName(
  577. nameBuffer,
  578. & nameLength,
  579. NULL,
  580. NULL,
  581. pchData,
  582. pchStart,
  583. pchEnd );
  584. if ( pchData != pchEnd )
  585. {
  586. DNS_PRINT(( "ERROR: bad packet name.\n" ));
  587. SetLastError( DNS_ERROR_INVALID_NAME );
  588. return( NULL );
  589. }
  590. //
  591. // determine required buffer length and allocate
  592. //
  593. bufLength = sizeof( DNS_SRV_DATA );
  594. bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength, OutCharSet );
  595. precord = Dns_AllocateRecord( bufLength );
  596. if ( !precord )
  597. {
  598. return( NULL );
  599. }
  600. //
  601. // copy integer fields
  602. //
  603. precord->Data.SRV.wPriority = FlipUnalignedWord( pchstart );
  604. pchstart += sizeof( WORD );
  605. precord->Data.SRV.wWeight = FlipUnalignedWord( pchstart );
  606. pchstart += sizeof( WORD );
  607. precord->Data.SRV.wPort = FlipUnalignedWord( pchstart );
  608. //
  609. // copy target host name into RR buffer
  610. // - write target host immediately following SRV data struct
  611. //
  612. precord->Data.SRV.pNameTarget = (PCHAR)&precord->Data + sizeof( DNS_SRV_DATA );
  613. Dns_NameCopy(
  614. precord->Data.SRV.pNameTarget,
  615. NULL, // no buffer length
  616. nameBuffer,
  617. nameLength,
  618. DnsCharSetWire,
  619. OutCharSet
  620. );
  621. return( precord );
  622. }
  623. PDNS_RECORD
  624. Atma_RecordRead(
  625. IN OUT PDNS_RECORD pRR,
  626. IN DNS_CHARSET OutCharSet,
  627. IN OUT PCHAR pchStart,
  628. IN PCHAR pchData,
  629. IN PCHAR pchEnd
  630. )
  631. /*++
  632. Routine Description:
  633. Read ATMA record from wire.
  634. Arguments:
  635. pRR - ptr to record with RR set context
  636. pchStart - start of DNS message
  637. pchData - ptr to RR data field
  638. pchEnd - ptr to byte after data field
  639. Return Value:
  640. Ptr to new record if successful.
  641. NULL on failure.
  642. --*/
  643. {
  644. PDNS_RECORD precord;
  645. PCHAR pchstart;
  646. WORD wLen = (WORD) (pchEnd - pchData);
  647. pchstart = pchData;
  648. precord = Dns_AllocateRecord( sizeof( DNS_ATMA_DATA ) +
  649. DNS_ATMA_MAX_ADDR_LENGTH );
  650. if ( !precord )
  651. {
  652. return( NULL );
  653. }
  654. //
  655. // copy ATMA integer fields
  656. //
  657. precord->Data.ATMA.AddressType = *pchstart;
  658. pchstart += sizeof( BYTE );
  659. if ( precord->Data.ATMA.AddressType == DNS_ATMA_FORMAT_E164 )
  660. {
  661. precord->wDataLength = wLen;
  662. if ( precord->wDataLength > DNS_ATMA_MAX_ADDR_LENGTH )
  663. precord->wDataLength = DNS_ATMA_MAX_ADDR_LENGTH;
  664. }
  665. else
  666. {
  667. precord->wDataLength = DNS_ATMA_MAX_ADDR_LENGTH;
  668. }
  669. //
  670. // copy ATMA address field
  671. //
  672. memcpy( (PCHAR)&precord->Data.ATMA.Address,
  673. pchstart,
  674. precord->wDataLength - sizeof( BYTE ) );
  675. return( precord );
  676. }
  677. PDNS_RECORD
  678. Wks_RecordRead(
  679. IN OUT PDNS_RECORD pRR,
  680. IN DNS_CHARSET OutCharSet,
  681. IN OUT PCHAR pchStart,
  682. IN PCHAR pchData,
  683. IN PCHAR pchEnd
  684. )
  685. /*++
  686. Routine Description:
  687. Read Wks record data from packet.
  688. Arguments:
  689. pRR - RR context
  690. pchStart - start of DNS message
  691. pchData - ptr to packet RR data field
  692. pchEnd - ptr to end of the data field
  693. Return Value:
  694. Ptr to new record if successful.
  695. NULL on failure.
  696. Author:
  697. Cameron Etezadi (camerone) - 1 May 1997
  698. - for NS Lookup purposes, must add this function
  699. NOTE:
  700. NONE of the getXXXbyYYY calls return unicode in their
  701. structures! If we want the returned record to be unicode,
  702. then we must translate. I am leaving it as char* for now,
  703. can go back later and fix this.
  704. --*/
  705. {
  706. PDNS_RECORD pRecord;
  707. WORD wLength;
  708. PCHAR pStart;
  709. UCHAR cProto;
  710. struct protoent * proto;
  711. struct servent * serv;
  712. IP4_ADDRESS ipAddress;
  713. char * szListOfServices;
  714. int nSize;
  715. char * szProtoName;
  716. BYTE cMask = 0x80; // is this right? Left to right?
  717. BYTE cByteToCheck;
  718. int i;
  719. int j = 0;
  720. int nPortNumToQuery;
  721. int nCurLength = 1;
  722. char * szTemp;
  723. pStart = pchData;
  724. if (! pStart)
  725. {
  726. DNS_PRINT(( "ERROR: WKS did not get a record.\n" ));
  727. SetLastError( ERROR_INVALID_DATA );
  728. return(NULL);
  729. }
  730. //
  731. // Check size. Must at least be an IP Address + a protocol
  732. //
  733. if ((pchEnd - pchData) < (sizeof(IP4_ADDRESS) + sizeof(UCHAR)))
  734. {
  735. DNS_PRINT(( "ERROR: WKS packet was too small for any data.\n" ));
  736. SetLastError( ERROR_INVALID_DATA );
  737. return(NULL);
  738. }
  739. //
  740. // Fill in the ip and protocol
  741. //
  742. ipAddress = *(UNALIGNED DWORD *)pStart;
  743. pStart += sizeof(IP4_ADDRESS);
  744. cProto = *(UCHAR *)pStart;
  745. pStart += sizeof(UCHAR);
  746. //
  747. // Redefined the WKS structure to contain a listing
  748. // of space separated monikers for the services
  749. //
  750. // Get the protocol
  751. //
  752. proto = getprotobynumber(cProto);
  753. if (!proto)
  754. {
  755. DNS_PRINT(( "ERROR: WKS failed to resolve protocol number to name.\n" ));
  756. SetLastError(ERROR_INVALID_DATA);
  757. return(NULL);
  758. }
  759. nSize = strlen(proto->p_name);
  760. szProtoName = ALLOCATE_HEAP((nSize + 1) * sizeof(char));
  761. if (!szProtoName)
  762. {
  763. DNS_PRINT(( "ERROR: WKS could not allocate space for proto name\n"));
  764. SetLastError(ERROR_OUTOFMEMORY);
  765. return(NULL);
  766. }
  767. strcpy(szProtoName, proto->p_name);
  768. //
  769. // Now, the tricky part. This is a bitmask.
  770. // I must translate to a string for each bit marked in the bitmask
  771. //
  772. DNS_PRINT(( "Now checking bitmask bits.\n"));
  773. szTemp = NULL;
  774. szListOfServices = ALLOCATE_HEAP(sizeof(char));
  775. if (!szListOfServices)
  776. {
  777. DNS_PRINT(( "ERROR: WKS could not allocate space for services name\n"));
  778. SetLastError(ERROR_OUTOFMEMORY);
  779. FREE_HEAP(szProtoName);
  780. return(NULL);
  781. }
  782. else
  783. {
  784. *szListOfServices = '\0';
  785. }
  786. while (pStart < pchEnd)
  787. {
  788. cByteToCheck = *(BYTE *)pStart;
  789. for (i = 0; i < 8; i++)
  790. {
  791. if (cByteToCheck & cMask)
  792. {
  793. // This is a service that is valid
  794. nPortNumToQuery = i + (8 * j);
  795. serv = getservbyport(htons((USHORT)nPortNumToQuery), szProtoName);
  796. if (! serv)
  797. {
  798. DNS_PRINT(( "ERROR: WKS found a port that could not be translated\n"));
  799. SetLastError(ERROR_INVALID_DATA);
  800. FREE_HEAP(szProtoName);
  801. FREE_HEAP(szListOfServices);
  802. return(NULL);
  803. }
  804. nSize = strlen(serv->s_name);
  805. nCurLength = nCurLength + nSize + 1;
  806. //
  807. // Allocate more memory. We need the + 1 here
  808. // because we will overwrite the existing null with a strcat
  809. // (removing the need) but use a space to separate items
  810. //
  811. szTemp = ALLOCATE_HEAP( nCurLength);
  812. if (! szTemp)
  813. {
  814. DNS_PRINT(( "ERROR: WKS alloc space for services name\n" ));
  815. SetLastError(ERROR_OUTOFMEMORY);
  816. FREE_HEAP(szProtoName);
  817. FREE_HEAP(szListOfServices);
  818. return(NULL);
  819. }
  820. else
  821. {
  822. strcpy( szTemp, szListOfServices );
  823. FREE_HEAP( szListOfServices );
  824. szListOfServices = szTemp;
  825. szTemp = NULL;
  826. }
  827. //
  828. // Append the retrieved service name to the end of the list
  829. //
  830. strcat(szListOfServices, serv->s_name);
  831. strcat(szListOfServices, " ");
  832. }
  833. cByteToCheck <<= 1;
  834. }
  835. //
  836. // Increment the "how many bytes have we done" offset counter
  837. //
  838. j++;
  839. pStart += sizeof(BYTE);
  840. }
  841. FREE_HEAP(szProtoName);
  842. //
  843. // Allocate a record and fill it in.
  844. //
  845. wLength = (WORD)(sizeof(IP4_ADDRESS) + sizeof(UCHAR) + sizeof(int)
  846. + (sizeof(char) * ++nCurLength));
  847. pRecord = Dns_AllocateRecord(wLength);
  848. if ( !pRecord )
  849. {
  850. DNS_PRINT(( "ERROR: WKS failed to allocate record\n" ));
  851. SetLastError(ERROR_OUTOFMEMORY);
  852. FREE_HEAP(szListOfServices);
  853. return(NULL);
  854. }
  855. pRecord->Data.WKS.IpAddress = ipAddress;
  856. pRecord->Data.WKS.chProtocol = cProto;
  857. strcpy((char *)pRecord->Data.WKS.BitMask, szListOfServices);
  858. FREE_HEAP(szListOfServices);
  859. return(pRecord);
  860. }
  861. PDNS_RECORD
  862. Tkey_RecordRead(
  863. IN OUT PDNS_RECORD pRR,
  864. IN DNS_CHARSET OutCharSet,
  865. IN OUT PCHAR pchStart,
  866. IN PCHAR pchData,
  867. IN PCHAR pchEnd
  868. )
  869. {
  870. PCHAR pch;
  871. PDNS_RECORD prr;
  872. WORD bufLength;
  873. WORD keyLength;
  874. PCHAR pchstart;
  875. CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
  876. //
  877. // allocate record
  878. //
  879. bufLength = sizeof( DNS_TKEY_DATA );
  880. prr = Dns_AllocateRecord( bufLength );
  881. if ( !prr )
  882. {
  883. return( NULL );
  884. }
  885. prr->wType = DNS_TYPE_TKEY;
  886. //
  887. // algorithm name
  888. //
  889. pch = Dns_SkipPacketName(
  890. pchData,
  891. pchEnd );
  892. if ( !pch )
  893. {
  894. goto Formerr;
  895. }
  896. prr->Data.TKEY.pAlgorithmPacket = (PDNS_NAME) pchData;
  897. prr->Data.TKEY.cAlgNameLength = (UCHAR)(pch - pchData);
  898. prr->Data.TKEY.pNameAlgorithm = NULL;
  899. #if 0
  900. //
  901. // DEVNOTE: currently not allocating data for TKEY, using internal pointers
  902. //
  903. // allocated version
  904. // note for this we won't have compression pointer which is fine
  905. // since no name compression in data
  906. // however function may need dummy to do the right thing
  907. // should perhaps just pass in pchStart which can be dummy to
  908. // real header
  909. //
  910. pch = Dns_ReadPacketNameAllocate(
  911. & prr->Data.TKEY.pNameAlgorithm,
  912. & nameLength,
  913. NULL, // no previous name
  914. NULL, // no previous name
  915. pchData,
  916. //pchStart, // have no packet context
  917. NULL,
  918. pchEnd );
  919. if ( !pch )
  920. {
  921. DNSDBG( SECURITY, (
  922. "WARNING: invalid TKEY algorithm name at %p.\n",
  923. pch ));
  924. goto Formerr;
  925. }
  926. #endif
  927. //
  928. // read fixed fields
  929. //
  930. if ( pch + SIZEOF_TKEY_FIXED_DATA >= pchEnd )
  931. {
  932. goto Formerr;
  933. }
  934. prr->Data.TKEY.dwCreateTime = InlineFlipUnalignedDword( pch );
  935. pch += sizeof(DWORD);
  936. prr->Data.TKEY.dwExpireTime = InlineFlipUnalignedDword( pch );
  937. pch += sizeof(DWORD);
  938. prr->Data.TKEY.wMode = InlineFlipUnalignedWord( pch );
  939. pch += sizeof(WORD);
  940. prr->Data.TKEY.wError = InlineFlipUnalignedWord( pch );
  941. pch += sizeof(WORD);
  942. prr->Data.TKEY.wKeyLength = keyLength = InlineFlipUnalignedWord( pch );
  943. pch += sizeof(WORD);
  944. // now have key and other length to read
  945. if ( pch + keyLength + sizeof(WORD) > pchEnd )
  946. {
  947. goto Formerr;
  948. }
  949. //
  950. // save ptr to key
  951. //
  952. prr->Data.TKEY.pKey = pch;
  953. pch += keyLength;
  954. #if 0
  955. //
  956. // copy key
  957. //
  958. pkey = ALLOCATE_HEAP( keyLength );
  959. if ( !pkey )
  960. {
  961. status = DNS_ERROR_NO_MEMORY;
  962. goto Failed;
  963. }
  964. RtlCopyMemory(
  965. pkey,
  966. pch,
  967. keyLength );
  968. pch += keyLength;
  969. #endif
  970. //
  971. // other data
  972. //
  973. prr->Data.TKEY.wOtherLength = keyLength = InlineFlipUnalignedWord( pch );
  974. pch += sizeof(WORD);
  975. if ( pch + keyLength > pchEnd )
  976. {
  977. goto Formerr;
  978. }
  979. if ( !keyLength )
  980. {
  981. prr->Data.TKEY.pOtherData = NULL;
  982. }
  983. else
  984. {
  985. prr->Data.TKEY.pOtherData = pch;
  986. }
  987. // DCR_ENHANCE: TKEY end-of-data verification
  988. // returning TKEY with packet pointers as only point is processing
  989. prr->Data.TKEY.bPacketPointers = TRUE;
  990. //
  991. // DCR_ENHANCE: copied subfields, best to get here with stack record, then
  992. // allocate RR containing subfields and copy everything
  993. return( prr );
  994. Formerr:
  995. DNSDBG( ANY, (
  996. "ERROR: FOMERR processing TKEY at %p in message\n",
  997. pchData ));
  998. // free record
  999. // if switch to allocated subfields need
  1000. FREE_HEAP( prr );
  1001. return( NULL );
  1002. }
  1003. PDNS_RECORD
  1004. Tsig_RecordRead(
  1005. IN OUT PDNS_RECORD pRR,
  1006. IN DNS_CHARSET OutCharSet,
  1007. IN OUT PCHAR pchStart,
  1008. IN PCHAR pchData,
  1009. IN PCHAR pchEnd
  1010. )
  1011. /*++
  1012. Routine Description:
  1013. Read SRV record from wire.
  1014. Arguments:
  1015. pRR - ptr to record with RR set context
  1016. pchStart - [OLD SEMANTICS, UNUSED] start of DNS message
  1017. OVERLOAD pchStart!!
  1018. Since we're stuck w/ this function signature, we'll overload
  1019. the unused param pchStart to get the iKeyVersion.
  1020. pchData - ptr to RR data field
  1021. pchEnd - ptr to byte after data field
  1022. Return Value:
  1023. Ptr to new record if successful.
  1024. NULL on failure.
  1025. --*/
  1026. {
  1027. PCHAR pch;
  1028. PDNS_RECORD prr;
  1029. WORD bufLength;
  1030. WORD sigLength;
  1031. PCHAR pchstart;
  1032. CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
  1033. #if 0
  1034. // currently do not need versioning info
  1035. // if had to do again, should extract version then pass
  1036. // in another pRR field; or send entire packet context
  1037. //
  1038. // extract current TSIG version (from key string)
  1039. //
  1040. ASSERT( pRR );
  1041. iKeyVersion = Dns_GetKeyVersion( pRR->pName );
  1042. #endif
  1043. //
  1044. // allocate record
  1045. //
  1046. bufLength = sizeof( DNS_TSIG_DATA );
  1047. prr = Dns_AllocateRecord( bufLength );
  1048. if ( !prr )
  1049. {
  1050. return( NULL );
  1051. }
  1052. prr->wType = DNS_TYPE_TSIG;
  1053. //
  1054. // algorithm name
  1055. //
  1056. pch = Dns_SkipPacketName(
  1057. pchData,
  1058. pchEnd );
  1059. if ( !pch )
  1060. {
  1061. DNSDBG( SECURITY, (
  1062. "WARNING: invalid TSIG RR algorithm name.\n" ));
  1063. goto Formerr;
  1064. }
  1065. prr->Data.TSIG.pAlgorithmPacket = (PDNS_NAME) pchData;
  1066. prr->Data.TSIG.cAlgNameLength = (UCHAR)(pch - pchData);
  1067. #if 0
  1068. // allocated version
  1069. // note for this we won't have compression pointer which is fine
  1070. // since no name compression in data
  1071. // however function may need dummy to do the right thing
  1072. // should perhaps just pass in pchStart which can be dummy
  1073. // to real header
  1074. //
  1075. pch = Dns_ReadPacketNameAllocate(
  1076. & prr->Data.TSIG.pNameAlgorithm,
  1077. & nameLength,
  1078. NULL, // no previous name
  1079. NULL, // no previous name
  1080. pchData,
  1081. //pchStart, // have no packet context
  1082. NULL,
  1083. pchEnd );
  1084. if ( !pch )
  1085. {
  1086. DNSDBG( SECURITY, (
  1087. "WARNING: invalid TSIG RR algorithm name at %p.\n",
  1088. pch ));
  1089. goto Formerr;
  1090. }
  1091. #endif
  1092. //
  1093. // read fixed fields
  1094. //
  1095. if ( pch + SIZEOF_TSIG_FIXED_DATA >= pchEnd )
  1096. {
  1097. DNSDBG( SECURITY, (
  1098. "ERROR: TSIG has inadequate length for fixed fields.\n" ));
  1099. goto Formerr;
  1100. }
  1101. //
  1102. // read time fields
  1103. // - 48 bit create time
  1104. // - 16 bit fudge
  1105. //
  1106. prr->Data.TSIG.i64CreateTime = InlineFlipUnaligned48Bits( pch );
  1107. pch += sizeof(DWORD) + sizeof(WORD);
  1108. prr->Data.TSIG.wFudgeTime = InlineFlipUnalignedWord( pch );
  1109. pch += sizeof(WORD);
  1110. //
  1111. // save sig length and sig pointer
  1112. //
  1113. prr->Data.TSIG.wSigLength = sigLength = InlineFlipUnalignedWord( pch );
  1114. pch += sizeof(WORD);
  1115. prr->Data.TSIG.pSignature = pch;
  1116. pch += sigLength;
  1117. //
  1118. // verify rest of fields within packet
  1119. // - signature
  1120. // - original XID
  1121. // - extended RCODE
  1122. // - other data length field
  1123. // - other data
  1124. //
  1125. if ( pch + SIZEOF_TSIG_POST_SIG_FIXED_DATA > pchEnd )
  1126. {
  1127. DNSDBG( SECURITY, (
  1128. "ERROR: TSIG has inadequate length for post-sig fixed fields.\n" ));
  1129. goto Formerr;
  1130. }
  1131. #if 0
  1132. //
  1133. // note: if this activated, would need to validate length pull
  1134. // sig ptr thing above and change validation to include sig length
  1135. //
  1136. // copy sig
  1137. //
  1138. psig = ALLOCATE_HEAP( sigLength );
  1139. if ( !psig )
  1140. {
  1141. status = DNS_ERROR_NO_MEMORY;
  1142. goto Failed;
  1143. }
  1144. RtlCopyMemory(
  1145. psig,
  1146. pch,
  1147. sigLength );
  1148. pch += sigLength;
  1149. #endif
  1150. // original XID
  1151. // - leave in net order, as just replace in message for signing
  1152. prr->Data.TSIG.wOriginalXid = READ_PACKET_NET_WORD( pch );
  1153. pch += sizeof(WORD);
  1154. DNSDBG( SECURITY, (
  1155. "Read original XID <== 0x%x.\n",
  1156. prr->Data.TSIG.wOriginalXid ));
  1157. // error field
  1158. prr->Data.TSIG.wError = InlineFlipUnalignedWord( pch );
  1159. pch += sizeof(WORD);
  1160. //
  1161. // other data
  1162. //
  1163. prr->Data.TSIG.wOtherLength = sigLength = InlineFlipUnalignedWord( pch );
  1164. pch += sizeof(WORD);
  1165. if ( pch + sigLength > pchEnd )
  1166. {
  1167. DNSDBG( SECURITY, (
  1168. "WARNING: invalid TSIG RR sigLength %p.\n",
  1169. pch ));
  1170. goto Formerr;
  1171. }
  1172. if ( !sigLength )
  1173. {
  1174. prr->Data.TSIG.pOtherData = NULL;
  1175. }
  1176. else
  1177. {
  1178. prr->Data.TSIG.pOtherData = pch;
  1179. }
  1180. // DCR_ENHANCE: TSIG end-of-data verification
  1181. // returning TSIG with packet pointers as only point is processing
  1182. prr->Data.TSIG.bPacketPointers = TRUE;
  1183. //
  1184. // DCR_ENHANCE: copied subfields, best to get here with stack record, then
  1185. // allocate RR containing subfields and copy everything
  1186. return( prr );
  1187. Formerr:
  1188. DNSDBG( ANY, (
  1189. "ERROR: FOMERR processing TSIG in message at %p\n" ));
  1190. // free record
  1191. // if switch to allocated subfields need
  1192. FREE_HEAP( prr );
  1193. return( NULL );
  1194. }
  1195. PDNS_RECORD
  1196. Wins_RecordRead(
  1197. IN OUT PDNS_RECORD pRR,
  1198. IN DNS_CHARSET OutCharSet,
  1199. IN OUT PCHAR pchStart,
  1200. IN PCHAR pchData,
  1201. IN PCHAR pchEnd
  1202. )
  1203. /*++
  1204. Routine Description:
  1205. Read WINS record from wire.
  1206. Arguments:
  1207. pRR - ptr to record with RR set context
  1208. pchStart - start of DNS message
  1209. pchData - ptr to RR data field
  1210. pchEnd - ptr to byte after data field
  1211. Return Value:
  1212. Ptr to new record if successful.
  1213. NULL on failure.
  1214. --*/
  1215. {
  1216. PDNS_RECORD precord;
  1217. WORD bufLength;
  1218. //
  1219. // determine required buffer length and allocate
  1220. //
  1221. bufLength = (WORD)(pchEnd - pchData);
  1222. precord = Dns_AllocateRecord( bufLength );
  1223. if ( !precord )
  1224. {
  1225. return( NULL );
  1226. }
  1227. //
  1228. // copy packet data to record
  1229. //
  1230. memcpy(
  1231. & precord->Data,
  1232. pchData,
  1233. bufLength );
  1234. precord->Data.WINS.dwMappingFlag =
  1235. FlipUnalignedDword( &precord->Data.Wins.dwMappingFlag );
  1236. precord->Data.WINS.dwLookupTimeout =
  1237. FlipUnalignedDword( &precord->Data.Wins.dwLookupTimeout );
  1238. precord->Data.WINS.dwCacheTimeout =
  1239. FlipUnalignedDword( &precord->Data.Wins.dwCacheTimeout );
  1240. precord->Data.WINS.cWinsServerCount =
  1241. FlipUnalignedDword( &precord->Data.Wins.cWinsServerCount );
  1242. return( precord );
  1243. }
  1244. PDNS_RECORD
  1245. Winsr_RecordRead(
  1246. IN OUT PDNS_RECORD pRR,
  1247. IN DNS_CHARSET OutCharSet,
  1248. IN OUT PCHAR pchStart,
  1249. IN PCHAR pchData,
  1250. IN PCHAR pchEnd
  1251. )
  1252. /*++
  1253. Routine Description:
  1254. Read WINSR record.
  1255. Arguments:
  1256. pRR - ptr to record with RR set context
  1257. pchStart - start of DNS message
  1258. pchData - ptr to RR data field
  1259. pchEnd - ptr to byte after data field
  1260. Return Value:
  1261. Ptr to new record if successful.
  1262. NULL on failure.
  1263. --*/
  1264. {
  1265. #define SIZEOF_WINSR_FIXED_DATA (sizeof(DNS_WINSR_DATA)-sizeof(PCHAR))
  1266. PDNS_RECORD precord;
  1267. WORD bufLength;
  1268. WORD nameLength;
  1269. CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ];
  1270. PCHAR pchstart;
  1271. //
  1272. // read WINSR domain name
  1273. // - name is after fixed length integer data
  1274. pchstart = pchData;
  1275. pchData += SIZEOF_WINSR_FIXED_DATA;
  1276. pchData = Dns_ReadPacketName(
  1277. nameBuffer,
  1278. & nameLength,
  1279. NULL,
  1280. NULL,
  1281. pchData,
  1282. pchStart,
  1283. pchEnd );
  1284. if ( pchData != pchEnd )
  1285. {
  1286. DNS_PRINT(( "ERROR: bad packet name.\n" ));
  1287. SetLastError( DNS_ERROR_INVALID_NAME );
  1288. return( NULL );
  1289. }
  1290. //
  1291. // determine required buffer length and allocate
  1292. //
  1293. bufLength = sizeof(DNS_WINSR_DATA);
  1294. bufLength += STR_BUF_SIZE_GIVEN_UTF8_LEN( nameLength, OutCharSet );
  1295. precord = Dns_AllocateRecord( bufLength );
  1296. if ( !precord )
  1297. {
  1298. return( NULL );
  1299. }
  1300. //
  1301. // copy fixed data
  1302. // - copy first so flipping is aligned
  1303. memcpy(
  1304. & precord->Data,
  1305. pchstart,
  1306. SIZEOF_WINSR_FIXED_DATA );
  1307. precord->Data.WINSR.dwMappingFlag = ntohl( precord->Data.WINSR.dwMappingFlag );
  1308. precord->Data.WINSR.dwLookupTimeout = ntohl( precord->Data.WINSR.dwLookupTimeout );
  1309. precord->Data.WINSR.dwCacheTimeout = ntohl( precord->Data.WINSR.dwCacheTimeout );
  1310. //
  1311. // write hostname into buffer, immediately following PTR data struct
  1312. //
  1313. precord->Data.WINSR.pNameResultDomain = (PCHAR)&precord->Data + sizeof(DNS_WINSR_DATA);
  1314. Dns_NameCopy(
  1315. precord->Data.WINSR.pNameResultDomain,
  1316. NULL, // no buffer length
  1317. nameBuffer,
  1318. nameLength,
  1319. DnsCharSetUtf8,
  1320. OutCharSet
  1321. );
  1322. return( precord );
  1323. }
  1324. //
  1325. // RR read to packet jump table
  1326. //
  1327. RR_READ_FUNCTION RR_ReadTable[] =
  1328. {
  1329. NULL, // ZERO
  1330. A_RecordRead, // A
  1331. Ptr_RecordRead, // NS
  1332. Ptr_RecordRead, // MD
  1333. Ptr_RecordRead, // MF
  1334. Ptr_RecordRead, // CNAME
  1335. Soa_RecordRead, // SOA
  1336. Ptr_RecordRead, // MB
  1337. Ptr_RecordRead, // MG
  1338. Ptr_RecordRead, // MR
  1339. Flat_RecordRead, // NULL
  1340. Wks_RecordRead, // WKS
  1341. Ptr_RecordRead, // PTR
  1342. Txt_RecordRead, // HINFO
  1343. Minfo_RecordRead, // MINFO
  1344. Mx_RecordRead, // MX
  1345. Txt_RecordRead, // TXT
  1346. Minfo_RecordRead, // RP
  1347. Mx_RecordRead, // AFSDB
  1348. Txt_RecordRead, // X25
  1349. Txt_RecordRead, // ISDN
  1350. Mx_RecordRead, // RT
  1351. NULL, // NSAP
  1352. NULL, // NSAPPTR
  1353. NULL, // SIG
  1354. NULL, // KEY
  1355. NULL, // PX
  1356. NULL, // GPOS
  1357. Flat_RecordRead, // AAAA
  1358. NULL, // LOC
  1359. NULL, // NXT
  1360. NULL, // EID
  1361. NULL, // NIMLOC
  1362. Srv_RecordRead, // SRV
  1363. Atma_RecordRead, // ATMA
  1364. NULL, // NAPTR
  1365. NULL, // KX
  1366. NULL, // CERT
  1367. NULL, // A6
  1368. NULL, // DNAME
  1369. NULL, // SINK
  1370. NULL, // OPT
  1371. NULL, // 42
  1372. NULL, // 43
  1373. NULL, // 44
  1374. NULL, // 45
  1375. NULL, // 46
  1376. NULL, // 47
  1377. NULL, // 48
  1378. //
  1379. // NOTE: last type indexed by type ID MUST be set
  1380. // as MAX_SELF_INDEXED_TYPE #define in record.h
  1381. // (see note above in record info table)
  1382. //
  1383. // Pseudo record types
  1384. //
  1385. Tkey_RecordRead, // TKEY
  1386. Tsig_RecordRead, // TSIG
  1387. //
  1388. // MS only types
  1389. //
  1390. Wins_RecordRead, // WINS
  1391. Winsr_RecordRead, // WINSR
  1392. };
  1393. //
  1394. // End rrread.c
  1395. //