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.

878 lines
19 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. hostfile.c
  5. Abstract:
  6. Read host file data.
  7. Author:
  8. Jim Gilroy (jamesg) October 2000
  9. Revision History:
  10. --*/
  11. #include "local.h"
  12. // sockreg.h includes "etc" directory file opens
  13. // sockreg.h is NT file so must define NTSTATUS first
  14. #ifndef NTSTATUS
  15. #define NTSTATUS LONG
  16. #endif
  17. #include <sockreg.h>
  18. //
  19. // Host file defs
  20. // Note, HOST_FILE_INFO blob defined in dnsapip.h
  21. //
  22. #define HOST_FILE_PATH_LENGTH (MAX_PATH + sizeof("\\hosts") + 1)
  23. //
  24. // Host file record TTL
  25. // (use a week)
  26. //
  27. #define HOSTFILE_RECORD_TTL (604800)
  28. BOOL
  29. HostsFile_Open(
  30. IN OUT PHOST_FILE_INFO pHostInfo
  31. )
  32. /*++
  33. Routine Description:
  34. Open hosts file or rewind existing file to beginning.
  35. Arguments:
  36. pHostInfo - ptr to host info;
  37. hFile - must be NULL if file not previously opened
  38. otherwise hFile is assumed to be existing FILE pointer
  39. pszFileName - NULL to open "hosts" file
  40. otherwise is name of file to open
  41. Return Value:
  42. None.
  43. --*/
  44. {
  45. CHAR hostFileNameBuffer[ HOST_FILE_PATH_LENGTH ];
  46. DNSDBG( TRACE, (
  47. "HostsFile_Open()\n" ));
  48. //
  49. // open host file OR rewind if already open
  50. //
  51. if ( pHostInfo->hFile == NULL )
  52. {
  53. PSTR pnameFile = pHostInfo->pszFileName;
  54. if ( !pnameFile )
  55. {
  56. pnameFile = "hosts";
  57. }
  58. pHostInfo->hFile = SockOpenNetworkDataBase(
  59. pnameFile,
  60. hostFileNameBuffer,
  61. HOST_FILE_PATH_LENGTH,
  62. "r" );
  63. }
  64. else
  65. {
  66. rewind( pHostInfo->hFile );
  67. }
  68. return ( pHostInfo->hFile ? TRUE : FALSE );
  69. }
  70. VOID
  71. HostsFile_Close(
  72. IN OUT PHOST_FILE_INFO pHostInfo
  73. )
  74. /*++
  75. Routine Description:
  76. Close hosts file.
  77. Arguments:
  78. pHostInfo -- ptr to host info; hFile assumed to contain file pointer
  79. Return Value:
  80. None.
  81. --*/
  82. {
  83. DNSDBG( TRACE, (
  84. "HostsFile_Close()\n" ));
  85. if ( pHostInfo->hFile )
  86. {
  87. fclose( pHostInfo->hFile );
  88. pHostInfo->hFile = NULL;
  89. }
  90. }
  91. VOID
  92. BuildHostfileRecords(
  93. IN OUT PHOST_FILE_INFO pHostInfo
  94. )
  95. /*++
  96. Routine Description:
  97. Build records from hostfile line.
  98. Arguments:
  99. pHostInfo -- ptr to host info
  100. Return Value:
  101. TRUE if successful.
  102. FALSE on error.
  103. --*/
  104. {
  105. DNS_LIST aliasList;
  106. PCHAR * paliasEntry;
  107. PCHAR palias;
  108. PDNS_RECORD prr;
  109. DNSDBG( TRACE, (
  110. "BuildHostfileRecords()\n" ));
  111. //
  112. // create all the records
  113. // - A or AAAA for name
  114. // - CNAMEs for aliases
  115. // - PTR
  116. //
  117. // for hosts file records
  118. // - section == ANSWER
  119. // - hostsfile flag set
  120. //
  121. prr = Dns_CreateForwardRecord(
  122. (PDNS_NAME) pHostInfo->pHostName,
  123. 0, // any type
  124. & pHostInfo->Addr,
  125. HOSTFILE_RECORD_TTL,
  126. DnsCharSetAnsi,
  127. DnsCharSetUnicode );
  128. pHostInfo->pForwardRR = prr;
  129. if ( prr )
  130. {
  131. SET_RR_HOSTS_FILE( prr );
  132. prr->Flags.S.Section = DnsSectionAnswer;
  133. }
  134. //
  135. // build aliases into list of CNAME records
  136. // - append forward lookup answer with each CNAME
  137. //
  138. DNS_LIST_STRUCT_INIT( aliasList );
  139. for( paliasEntry = pHostInfo->AliasArray;
  140. palias = *paliasEntry;
  141. paliasEntry++ )
  142. {
  143. PDNS_RECORD prrForward = pHostInfo->pForwardRR;
  144. PDNS_RECORD prrAnswer;
  145. DNSDBG( INIT, (
  146. "Building for alias %s for hostname %s\n",
  147. palias,
  148. pHostInfo->pHostName ));
  149. prr = Dns_CreatePtrTypeRecord(
  150. (PDNS_NAME) palias,
  151. TRUE, // make name copy
  152. (PDNS_NAME) pHostInfo->pHostName,
  153. DNS_TYPE_CNAME,
  154. HOSTFILE_RECORD_TTL,
  155. DnsCharSetAnsi,
  156. DnsCharSetUnicode );
  157. if ( prr )
  158. {
  159. SET_RR_HOSTS_FILE( prr );
  160. prr->Flags.S.Section = DnsSectionAnswer;
  161. DNS_LIST_STRUCT_ADD( aliasList, prr );
  162. // append forward record
  163. if ( prrForward &&
  164. (prrAnswer = Dns_RecordCopy_W(prrForward)) )
  165. {
  166. DNS_LIST_STRUCT_ADD( aliasList, prrAnswer );
  167. }
  168. }
  169. }
  170. pHostInfo->pAliasRR = aliasList.pFirst;
  171. //
  172. // PTR points only to name
  173. //
  174. prr = Dns_CreatePtrRecordEx(
  175. & pHostInfo->Addr,
  176. (PDNS_NAME) pHostInfo->pHostName, // target name
  177. HOSTFILE_RECORD_TTL,
  178. DnsCharSetAnsi,
  179. DnsCharSetUnicode );
  180. pHostInfo->pReverseRR = prr;
  181. if ( prr )
  182. {
  183. SET_RR_HOSTS_FILE( prr );
  184. prr->Flags.S.Section = DnsSectionAnswer;
  185. }
  186. IF_DNSDBG( QUERY )
  187. {
  188. DnsDbg_RecordSet(
  189. "HostFile forward record:",
  190. pHostInfo->pForwardRR );
  191. DnsDbg_RecordSet(
  192. "HostFile reverse record:",
  193. pHostInfo->pReverseRR );
  194. if ( pHostInfo->pAliasRR )
  195. {
  196. DnsDbg_RecordSet(
  197. "HostFile alias records:",
  198. pHostInfo->pAliasRR );
  199. }
  200. }
  201. }
  202. BOOL
  203. TokenizeHostFileLine(
  204. IN OUT PHOST_FILE_INFO pHostInfo
  205. )
  206. /*++
  207. Routine Description:
  208. Reads an entry from hosts file.
  209. Arguments:
  210. pHostInfo -- ptr to host info;
  211. if hFile is NULL, first attempts host file open
  212. other fields are filled with info from next hostfile line
  213. Return Value:
  214. TRUE if successfully tokenized line.
  215. FALSE on empty or bad line
  216. --*/
  217. {
  218. PCHAR pch;
  219. PCHAR ptoken;
  220. DWORD countAlias = 0;
  221. DWORD count = 0;
  222. DNSDBG( TRACE, ( "TokenizeHostFileLine()\n" ));
  223. //
  224. // tokenize line
  225. //
  226. pch = pHostInfo->HostLineBuf;
  227. while( pch )
  228. {
  229. // strip leading whitespace
  230. while( *pch == ' ' || *pch == '\t' )
  231. {
  232. pch++;
  233. }
  234. ptoken = pch;
  235. //
  236. // NULL terminate token
  237. // - NULL pch serves as signal to stop after this token
  238. //
  239. pch = strpbrk( pch, " \t#\n\r" );
  240. if ( pch != NULL )
  241. {
  242. // empty (zero-length) token => done now
  243. if ( pch == ptoken )
  244. {
  245. break;
  246. }
  247. // terminated by whitespace -- may be another token
  248. if ( *pch == ' ' || *pch == '\t' )
  249. {
  250. *pch++ = '\0';
  251. }
  252. // terminated by EOL -- no more tokens
  253. else // #\r\n
  254. {
  255. *pch = '\0';
  256. pch = NULL;
  257. }
  258. }
  259. count++;
  260. //
  261. // save address, name or alias
  262. //
  263. if ( count == 1 )
  264. {
  265. pHostInfo->pAddrString = ptoken;
  266. }
  267. else if ( count == 2 )
  268. {
  269. pHostInfo->pHostName = ptoken;
  270. }
  271. else
  272. {
  273. if ( countAlias >= MAXALIASES )
  274. {
  275. break;
  276. }
  277. pHostInfo->AliasArray[ countAlias++ ] = ptoken;
  278. }
  279. }
  280. // NULL terminate alias array
  281. pHostInfo->AliasArray[ countAlias ] = NULL;
  282. IF_DNSDBG( INIT )
  283. {
  284. if ( count >= 2 )
  285. {
  286. PSTR palias;
  287. DnsDbg_Printf(
  288. "Parsed host file line:\n"
  289. "\tAddress = %s\n"
  290. "\tHostname = %s\n",
  291. pHostInfo->pAddrString,
  292. pHostInfo->pHostName );
  293. countAlias = 0;
  294. while ( palias = pHostInfo->AliasArray[countAlias] )
  295. {
  296. DnsDbg_Printf(
  297. "\tAlias = %s\n",
  298. palias );
  299. countAlias++;
  300. }
  301. }
  302. }
  303. return( count >= 2 );
  304. }
  305. BOOL
  306. HostsFile_ReadLine(
  307. IN OUT PHOST_FILE_INFO pHostInfo
  308. )
  309. /*++
  310. Routine Description:
  311. Reads an entry from hosts file.
  312. Arguments:
  313. pHostInfo -- ptr to host info;
  314. if hFile is NULL, first attempts host file open
  315. other fields are filled with info from next hostfile line
  316. Return Value:
  317. TRUE if successfully reads a host entry.
  318. FALSE if on EOF or no hosts file found.
  319. --*/
  320. {
  321. IP4_ADDRESS ip4;
  322. IP6_ADDRESS ip6;
  323. DNSDBG( TRACE, (
  324. "HostsFile_ReadLine()\n" ));
  325. //
  326. // open hosts file if not open
  327. //
  328. if ( pHostInfo->hFile == NULL )
  329. {
  330. HostsFile_Open( pHostInfo );
  331. if ( pHostInfo->hFile == NULL )
  332. {
  333. return FALSE;
  334. }
  335. }
  336. //
  337. // loop until successfully read IP address
  338. //
  339. while( 1 )
  340. {
  341. // setup for next line
  342. pHostInfo->pForwardRR = NULL;
  343. pHostInfo->pReverseRR = NULL;
  344. pHostInfo->pAliasRR = NULL;
  345. // read line, quit on EOF
  346. if ( ! fgets(
  347. pHostInfo->HostLineBuf,
  348. sizeof(pHostInfo->HostLineBuf) - 1,
  349. pHostInfo->hFile ) )
  350. {
  351. return FALSE;
  352. }
  353. // tokenize line
  354. if ( !TokenizeHostFileLine( pHostInfo ) )
  355. {
  356. continue;
  357. }
  358. //
  359. // read address
  360. // - try IP4
  361. // - try IP6
  362. // - otherwise skip
  363. //
  364. if ( Dns_StringToDnsAddr_A(
  365. &pHostInfo->Addr,
  366. pHostInfo->pAddrString
  367. ) )
  368. {
  369. break;
  370. }
  371. // invalid address, ignore line
  372. DNSDBG( INIT, (
  373. "Error parsing host file address %s\n",
  374. pHostInfo->pAddrString ));
  375. continue;
  376. }
  377. //
  378. // build records for line if desired
  379. //
  380. if ( pHostInfo->fBuildRecords )
  381. {
  382. BuildHostfileRecords( pHostInfo );
  383. }
  384. return TRUE;
  385. }
  386. BOOL
  387. HostsFile_Query(
  388. IN OUT PQUERY_BLOB pBlob
  389. )
  390. /*++
  391. Routine Description:
  392. Lookup query in host file.
  393. Arguments:
  394. Return Value:
  395. TRUE if found host file entry.
  396. FALSE otherwise.
  397. --*/
  398. {
  399. HOST_FILE_INFO hostInfo;
  400. BOOL fptr = FALSE;
  401. DNS_ADDR reverseAddr;
  402. WORD wtype;
  403. WORD buildType;
  404. PCHAR pcnameHost = NULL;
  405. PDNS_RECORD prrAlias = NULL;
  406. PDNS_RECORD prr = NULL;
  407. DNS_LIST forwardList;
  408. DWORD bufLength;
  409. PSTR pnameAnsi = (PCHAR) pBlob->NameBufferAnsi;
  410. DNSDBG( INIT, ( "QueryHostFile()\n" ));
  411. //
  412. // determine if host file type
  413. //
  414. wtype = pBlob->wType;
  415. if ( wtype == DNS_TYPE_A ||
  416. wtype == DNS_TYPE_AAAA ||
  417. wtype == DNS_TYPE_PTR ||
  418. wtype == DNS_TYPE_ALL )
  419. {
  420. // no op
  421. }
  422. else
  423. {
  424. return FALSE;
  425. }
  426. //
  427. // open hosts file -- if fails, we're done
  428. //
  429. RtlZeroMemory(
  430. &hostInfo,
  431. sizeof(hostInfo) );
  432. if ( !HostsFile_Open( &hostInfo ) )
  433. {
  434. return( FALSE );
  435. }
  436. //
  437. // convert name to ANSI
  438. // - validate and select IP4\IP6 for PTR
  439. //
  440. bufLength = DNS_MAX_NAME_BUFFER_LENGTH;
  441. if ( ! Dns_NameCopy(
  442. pnameAnsi,
  443. & bufLength,
  444. (PCHAR) pBlob->pNameQuery,
  445. 0,
  446. DnsCharSetUnicode,
  447. DnsCharSetAnsi ) )
  448. {
  449. goto Cleanup;
  450. }
  451. //
  452. // reverse name check
  453. // - validate and select IP 4\6
  454. // - PTR lookup MUST be valid reverse name
  455. // - ALL may be reverse name
  456. //
  457. if ( wtype == DNS_TYPE_PTR ||
  458. wtype == DNS_TYPE_ALL )
  459. {
  460. DWORD bufferLength = sizeof(IP6_ADDRESS);
  461. BOOL family = 0;
  462. if ( Dns_ReverseNameToDnsAddr_A(
  463. &reverseAddr,
  464. pnameAnsi
  465. ) )
  466. {
  467. fptr = TRUE;
  468. }
  469. else if ( wtype == DNS_TYPE_PTR )
  470. {
  471. // bad reverse name
  472. goto Cleanup;
  473. }
  474. }
  475. //
  476. // forward build type
  477. // - matches query type
  478. // - EXCEPT all which currently builds
  479. // AAAA for IP6, A for IP4
  480. //
  481. if ( !fptr )
  482. {
  483. buildType = wtype;
  484. DNS_LIST_STRUCT_INIT( forwardList );
  485. }
  486. //
  487. // read entries from host file until exhausted
  488. // - cache A record for each name and alias
  489. // - cache PTR to name
  490. //
  491. while ( HostsFile_ReadLine( &hostInfo ) )
  492. {
  493. //
  494. // reverse
  495. // - match IP
  496. // - success is terminal as reverse mapping is one-to-one
  497. //
  498. // DCR_QUESTION: parse hosts for multiple reverse mappings?
  499. //
  500. if ( fptr )
  501. {
  502. if ( ! DnsAddr_IsEqual(
  503. &reverseAddr,
  504. &hostInfo.Addr,
  505. DNSADDR_MATCH_IP ) )
  506. {
  507. continue;
  508. }
  509. // create RR
  510. // - don't need to use IP conversion version
  511. // as we already have reverse lookup name
  512. DNSDBG( QUERY, (
  513. "Build PTR record for name %s to %s\n",
  514. pnameAnsi,
  515. hostInfo.pHostName ));
  516. prr = Dns_CreatePtrTypeRecord(
  517. (PDNS_NAME) pnameAnsi,
  518. TRUE, // copy name
  519. (PDNS_NAME) hostInfo.pHostName,
  520. DNS_TYPE_PTR,
  521. HOSTFILE_RECORD_TTL,
  522. DnsCharSetAnsi,
  523. DnsCharSetUnicode );
  524. if ( !prr )
  525. {
  526. SetLastError( DNS_ERROR_NO_MEMORY );
  527. }
  528. break;
  529. }
  530. //
  531. // forward lookup
  532. //
  533. else
  534. {
  535. PCHAR pnameHost;
  536. // type ALL builds on any match
  537. // - build type appropriate for IP
  538. //
  539. // other query types must match address type
  540. buildType = DnsAddr_DnsType( &hostInfo.Addr );
  541. if ( wtype != buildType &&
  542. wtype != DNS_TYPE_ALL )
  543. {
  544. continue;
  545. }
  546. //
  547. // check name match
  548. //
  549. // DCR: use unicode name?
  550. //
  551. pnameHost = NULL;
  552. if ( Dns_NameCompare_A(
  553. hostInfo.pHostName,
  554. pnameAnsi ) )
  555. {
  556. pnameHost = pnameAnsi;
  557. }
  558. //
  559. // check match to previous CNAME
  560. //
  561. else if ( pcnameHost )
  562. {
  563. if ( Dns_NameCompare_A(
  564. hostInfo.pHostName,
  565. pcnameHost ) )
  566. {
  567. pnameHost = pcnameHost;
  568. }
  569. }
  570. //
  571. // aliases
  572. //
  573. // DCR_QUESTION: build aliases even if name hit?
  574. //
  575. // currently:
  576. // - don't allow alias if already have direct record
  577. // - limit to one alias (CNAME)
  578. //
  579. // if find alias:
  580. // - build CNAME record
  581. // - save CNAME target (in ANSI for faster compares)
  582. // - check CNAME target for subsequent address records (above)
  583. //
  584. else if ( IS_DNS_LIST_STRUCT_EMPTY( forwardList )
  585. &&
  586. !prrAlias )
  587. {
  588. PCHAR * paliasEntry;
  589. PCHAR palias;
  590. for( paliasEntry = hostInfo.AliasArray;
  591. palias = *paliasEntry;
  592. paliasEntry++ )
  593. {
  594. if ( Dns_NameCompare_A(
  595. palias,
  596. pnameAnsi ) )
  597. {
  598. DNSDBG( QUERY, (
  599. "Build CNAME record for name %s to CNAME %s\n",
  600. pnameAnsi,
  601. hostInfo.pHostName ));
  602. prrAlias = Dns_CreatePtrTypeRecord(
  603. (PDNS_NAME) pnameAnsi,
  604. TRUE, // copy name
  605. (PDNS_NAME) hostInfo.pHostName,
  606. DNS_TYPE_CNAME,
  607. HOSTFILE_RECORD_TTL,
  608. DnsCharSetAnsi,
  609. DnsCharSetUnicode );
  610. if ( prrAlias )
  611. {
  612. pcnameHost = Dns_NameCopyAllocate(
  613. hostInfo.pHostName,
  614. 0,
  615. DnsCharSetAnsi,
  616. DnsCharSetAnsi );
  617. pnameHost = pcnameHost;
  618. }
  619. break;
  620. }
  621. }
  622. }
  623. // add address record for this hostline
  624. if ( pnameHost )
  625. {
  626. DNSDBG( QUERY, (
  627. "Build address record for name %s\n",
  628. pnameHost ));
  629. prr = Dns_CreateForwardRecord(
  630. (PDNS_NAME) pnameHost,
  631. buildType,
  632. & hostInfo.Addr,
  633. HOSTFILE_RECORD_TTL,
  634. DnsCharSetAnsi,
  635. DnsCharSetUnicode );
  636. if ( prr )
  637. {
  638. DNS_LIST_STRUCT_ADD( forwardList, prr );
  639. }
  640. }
  641. }
  642. }
  643. //
  644. // build response
  645. //
  646. // DCR: new multiple section response
  647. //
  648. if ( !fptr )
  649. {
  650. prr = forwardList.pFirst;
  651. if ( prrAlias )
  652. {
  653. prrAlias->pNext = prr;
  654. prr = prrAlias;
  655. }
  656. }
  657. IF_DNSDBG( QUERY )
  658. {
  659. DnsDbg_RecordSet(
  660. "HostFile Answers:",
  661. prr );
  662. }
  663. pBlob->pRecords = prr;
  664. Cleanup:
  665. //
  666. // cleanup
  667. //
  668. HostsFile_Close( &hostInfo );
  669. if ( pcnameHost )
  670. {
  671. FREE_HEAP( pcnameHost );
  672. }
  673. DNSDBG( TRACE, (
  674. "Leave QueryHostFile() -> %d\n"
  675. "\tprr = %p\n",
  676. prr ? TRUE : FALSE,
  677. prr ));
  678. return( prr ? TRUE : FALSE );
  679. }
  680. //
  681. // End hostfile.c
  682. //