Source code of Windows XP (NT5)
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.

895 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. Dns_OpenHostFile(
  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. "Dns_OpenHostFile()\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. Dns_CloseHostFile(
  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. "Dns_CloseHostFile()\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. pHostInfo->pHostName,
  123. & pHostInfo->Ip,
  124. HOSTFILE_RECORD_TTL,
  125. DnsCharSetAnsi,
  126. DnsCharSetUnicode );
  127. pHostInfo->pForwardRR = prr;
  128. if ( prr )
  129. {
  130. SET_RR_HOSTS_FILE( prr );
  131. prr->Flags.S.Section = DnsSectionAnswer;
  132. }
  133. //
  134. // build aliases into list of CNAME records
  135. // - append forward lookup answer with each CNAME
  136. //
  137. DNS_LIST_STRUCT_INIT( aliasList );
  138. for( paliasEntry = pHostInfo->AliasArray;
  139. palias = *paliasEntry;
  140. paliasEntry++ )
  141. {
  142. PDNS_RECORD prrForward = pHostInfo->pForwardRR;
  143. PDNS_RECORD prrAnswer;
  144. DNSDBG( INIT, (
  145. "Building for alias %s for hostname %s\n",
  146. palias,
  147. pHostInfo->pHostName ));
  148. prr = Dns_CreatePtrTypeRecord(
  149. palias,
  150. TRUE, // make name copy
  151. pHostInfo->pHostName,
  152. DNS_TYPE_CNAME,
  153. HOSTFILE_RECORD_TTL,
  154. DnsCharSetAnsi,
  155. DnsCharSetUnicode );
  156. if ( prr )
  157. {
  158. SET_RR_HOSTS_FILE( prr );
  159. prr->Flags.S.Section = DnsSectionAnswer;
  160. DNS_LIST_STRUCT_ADD( aliasList, prr );
  161. // append forward record
  162. if ( prrForward &&
  163. (prrAnswer = Dns_RecordCopy_W(prrForward)) )
  164. {
  165. DNS_LIST_STRUCT_ADD( aliasList, prrAnswer );
  166. }
  167. }
  168. }
  169. pHostInfo->pAliasRR = aliasList.pFirst;
  170. //
  171. // PTR points only to name
  172. //
  173. prr = Dns_CreatePtrRecordEx(
  174. & pHostInfo->Ip,
  175. pHostInfo->pHostName, // target name
  176. HOSTFILE_RECORD_TTL,
  177. DnsCharSetAnsi,
  178. DnsCharSetUnicode );
  179. pHostInfo->pReverseRR = prr;
  180. if ( prr )
  181. {
  182. SET_RR_HOSTS_FILE( prr );
  183. prr->Flags.S.Section = DnsSectionAnswer;
  184. }
  185. IF_DNSDBG( QUERY )
  186. {
  187. DnsDbg_RecordSet(
  188. "HostFile forward record:",
  189. pHostInfo->pForwardRR );
  190. DnsDbg_RecordSet(
  191. "HostFile reverse record:",
  192. pHostInfo->pReverseRR );
  193. if ( pHostInfo->pAliasRR )
  194. {
  195. DnsDbg_RecordSet(
  196. "HostFile alias records:",
  197. pHostInfo->pAliasRR );
  198. }
  199. }
  200. }
  201. BOOL
  202. TokenizeHostFileLine(
  203. IN OUT PHOST_FILE_INFO pHostInfo
  204. )
  205. /*++
  206. Routine Description:
  207. Reads an entry from hosts file.
  208. Arguments:
  209. pHostInfo -- ptr to host info;
  210. if hFile is NULL, first attempts host file open
  211. other fields are filled with info from next hostfile line
  212. Return Value:
  213. TRUE if successfully tokenized line.
  214. FALSE on empty or bad line
  215. --*/
  216. {
  217. PCHAR pch;
  218. PCHAR ptoken;
  219. DWORD countAlias = 0;
  220. DWORD count = 0;
  221. DNSDBG( TRACE, ( "TokenizeHostFileLine()\n" ));
  222. //
  223. // tokenize line
  224. //
  225. pch = pHostInfo->HostLineBuf;
  226. while( pch )
  227. {
  228. // strip leading whitespace
  229. while( *pch == ' ' || *pch == '\t' )
  230. {
  231. pch++;
  232. }
  233. ptoken = pch;
  234. //
  235. // NULL terminate token
  236. // - NULL pch serves as signal to stop after this token
  237. //
  238. pch = strpbrk( pch, " \t#\n\r" );
  239. if ( pch != NULL )
  240. {
  241. // empty (zero-length) token => done now
  242. if ( pch == ptoken )
  243. {
  244. break;
  245. }
  246. // terminated by whitespace -- may be another token
  247. if ( *pch == ' ' || *pch == '\t' )
  248. {
  249. *pch++ = '\0';
  250. }
  251. // terminated by EOL -- no more tokens
  252. else // #\r\n
  253. {
  254. *pch = '\0';
  255. pch = NULL;
  256. }
  257. }
  258. count++;
  259. //
  260. // save address, name or alias
  261. //
  262. if ( count == 1 )
  263. {
  264. pHostInfo->pAddrString = ptoken;
  265. }
  266. else if ( count == 2 )
  267. {
  268. pHostInfo->pHostName = ptoken;
  269. }
  270. else
  271. {
  272. if ( countAlias >= MAXALIASES )
  273. {
  274. break;
  275. }
  276. pHostInfo->AliasArray[ countAlias++ ] = ptoken;
  277. }
  278. }
  279. // NULL terminate alias array
  280. pHostInfo->AliasArray[ countAlias ] = NULL;
  281. IF_DNSDBG( INIT )
  282. {
  283. if ( count >= 2 )
  284. {
  285. PSTR palias;
  286. DnsDbg_Printf(
  287. "Parsed host file line:\n"
  288. "\tAddress = %s\n"
  289. "\tHostname = %s\n",
  290. pHostInfo->pAddrString,
  291. pHostInfo->pHostName );
  292. countAlias = 0;
  293. while ( palias = pHostInfo->AliasArray[countAlias] )
  294. {
  295. DnsDbg_Printf(
  296. "\tAlias = %s\n",
  297. palias );
  298. countAlias++;
  299. }
  300. }
  301. }
  302. return( count >= 2 );
  303. }
  304. BOOL
  305. Dns_ReadHostFileLine(
  306. IN OUT PHOST_FILE_INFO pHostInfo
  307. )
  308. /*++
  309. Routine Description:
  310. Reads an entry from hosts file.
  311. Arguments:
  312. pHostInfo -- ptr to host info;
  313. if hFile is NULL, first attempts host file open
  314. other fields are filled with info from next hostfile line
  315. Return Value:
  316. TRUE if successfully reads a host entry.
  317. FALSE if on EOF or no hosts file found.
  318. --*/
  319. {
  320. IP4_ADDRESS ip4;
  321. DNS_IP6_ADDRESS ip6;
  322. DNSDBG( TRACE, (
  323. "Dns_ReadHostFileLine()\n" ));
  324. //
  325. // open hosts file if not open
  326. //
  327. if ( pHostInfo->hFile == NULL )
  328. {
  329. Dns_OpenHostFile( pHostInfo );
  330. if ( pHostInfo->hFile == NULL )
  331. {
  332. return FALSE;
  333. }
  334. }
  335. //
  336. // loop until successfully read IP address
  337. //
  338. while( 1 )
  339. {
  340. // setup for next line
  341. pHostInfo->pForwardRR = NULL;
  342. pHostInfo->pReverseRR = NULL;
  343. pHostInfo->pAliasRR = NULL;
  344. // read line, quit on EOF
  345. if ( ! fgets(
  346. pHostInfo->HostLineBuf,
  347. sizeof(pHostInfo->HostLineBuf) - 1,
  348. pHostInfo->hFile ) )
  349. {
  350. return FALSE;
  351. }
  352. // tokenize line
  353. if ( !TokenizeHostFileLine( pHostInfo ) )
  354. {
  355. continue;
  356. }
  357. //
  358. // read address
  359. // - try IP4
  360. // - try IP6
  361. // - otherwise skip
  362. //
  363. ip4 = inet_addr( pHostInfo->pAddrString );
  364. if ( ip4 != INADDR_NONE ||
  365. _strnicmp( "255.255.255.255", pHostInfo->pAddrString, 15 ) == 0 )
  366. {
  367. IPUNION_SET_IP4( &pHostInfo->Ip, ip4 );
  368. break;
  369. }
  370. // not valid IP4 -- check IP6
  371. if ( Dns_Ip6StringToAddress_A(
  372. & ip6,
  373. pHostInfo->pAddrString
  374. ) )
  375. {
  376. IPUNION_SET_IP6( &pHostInfo->Ip, ip6 );
  377. break;
  378. }
  379. // invalid address, ignore line
  380. DNSDBG( INIT, (
  381. "Error parsing host file address %s\n",
  382. pHostInfo->pAddrString ));
  383. continue;
  384. }
  385. //
  386. // build records for line if desired
  387. //
  388. if ( pHostInfo->fBuildRecords )
  389. {
  390. BuildHostfileRecords( pHostInfo );
  391. }
  392. return TRUE;
  393. }
  394. BOOL
  395. QueryHostFile(
  396. IN OUT PQUERY_BLOB pBlob
  397. )
  398. /*++
  399. Routine Description:
  400. Lookup query in host file.
  401. Arguments:
  402. Return Value:
  403. TRUE if found host file entry.
  404. FALSE otherwise.
  405. --*/
  406. {
  407. HOST_FILE_INFO hostInfo;
  408. BOOL fip6 = FALSE;
  409. BOOL fptr = FALSE;
  410. IP_UNION ipUnion;
  411. WORD wtype;
  412. WORD buildType;
  413. PCHAR pcnameHost = NULL;
  414. PDNS_RECORD prrAlias = NULL;
  415. PDNS_RECORD prr = NULL;
  416. DNS_LIST forwardList;
  417. DWORD bufLength;
  418. PSTR pnameAnsi = (PCHAR) pBlob->NameBufferWide;
  419. DNSDBG( INIT, ( "QueryHostFile()\n" ));
  420. //
  421. // determine if host file type
  422. //
  423. wtype = pBlob->wType;
  424. if ( wtype == DNS_TYPE_A ||
  425. wtype == DNS_TYPE_PTR ||
  426. wtype == DNS_TYPE_ALL )
  427. {
  428. // no op
  429. }
  430. else if ( wtype == DNS_TYPE_AAAA )
  431. {
  432. fip6 = TRUE;
  433. }
  434. else
  435. {
  436. return FALSE;
  437. }
  438. //
  439. // open hosts file -- if fails, we're done
  440. //
  441. RtlZeroMemory(
  442. &hostInfo,
  443. sizeof(hostInfo) );
  444. if ( !Dns_OpenHostFile( &hostInfo ) )
  445. {
  446. return( FALSE );
  447. }
  448. //
  449. // convert name to ANSI
  450. // - validate and select IP4\IP6 for PTR
  451. //
  452. bufLength = DNS_MAX_NAME_BUFFER_LENGTH;
  453. if ( ! Dns_NameCopy(
  454. pnameAnsi,
  455. & bufLength,
  456. pBlob->pNameWire,
  457. 0,
  458. DnsCharSetWire,
  459. DnsCharSetAnsi ) )
  460. {
  461. goto Cleanup;
  462. }
  463. //
  464. // reverse name check
  465. // - validate and select IP 4\6
  466. // - PTR lookup MUST be valid reverse name
  467. // - ALL may be reverse name
  468. //
  469. if ( wtype == DNS_TYPE_PTR ||
  470. wtype == DNS_TYPE_ALL )
  471. {
  472. DWORD bufferLength = sizeof(IP6_ADDRESS);
  473. BOOL family = 0;
  474. if ( Dns_ReverseNameToAddress_A(
  475. (PCHAR) & ipUnion.Addr,
  476. & bufferLength,
  477. pnameAnsi,
  478. & family // either address type
  479. ) )
  480. {
  481. fptr = TRUE;
  482. ipUnion.IsIp6 = (family == AF_INET6);
  483. }
  484. else if ( wtype == DNS_TYPE_PTR )
  485. {
  486. // bad reverse name
  487. goto Cleanup;
  488. }
  489. }
  490. //
  491. // forward build type
  492. // - matches query type
  493. // - EXCEPT all which currently builds
  494. // AAAA for IP6, A for IP4
  495. //
  496. if ( !fptr )
  497. {
  498. buildType = wtype;
  499. DNS_LIST_STRUCT_INIT( forwardList );
  500. }
  501. //
  502. // read entries from host file until exhausted
  503. // - cache A record for each name and alias
  504. // - cache PTR to name
  505. //
  506. while ( Dns_ReadHostFileLine( &hostInfo ) )
  507. {
  508. //
  509. // reverse
  510. // - match IP
  511. // - success is terminal as reverse mapping is one-to-one
  512. //
  513. // DCR_QUESTION: parse hosts for multiple reverse mappings?
  514. //
  515. if ( fptr )
  516. {
  517. // DCR: extract as genericIP comparison
  518. if ( ! Dns_EqualIpUnion( &ipUnion, &hostInfo.Ip ) )
  519. {
  520. continue;
  521. }
  522. // create RR
  523. // - don't need to use IP conversion version
  524. // as we already have reverse lookup name
  525. DNSDBG( QUERY, (
  526. "Build PTR record for name %s to %s\n",
  527. pnameAnsi,
  528. hostInfo.pHostName ));
  529. prr = Dns_CreatePtrTypeRecord(
  530. pnameAnsi,
  531. TRUE, // copy name
  532. hostInfo.pHostName,
  533. DNS_TYPE_PTR,
  534. HOSTFILE_RECORD_TTL,
  535. DnsCharSetAnsi,
  536. DnsCharSetUnicode );
  537. if ( !prr )
  538. {
  539. SetLastError( DNS_ERROR_NO_MEMORY );
  540. }
  541. break;
  542. }
  543. //
  544. // forward lookup
  545. //
  546. else
  547. {
  548. PCHAR pnameHost;
  549. // type ALL builds on any match
  550. // - build type appropriate for IP
  551. //
  552. // other query types must match address type
  553. if ( wtype == DNS_TYPE_ALL )
  554. {
  555. buildType = IPUNION_IS_IP6(&hostInfo.Ip)
  556. ? DNS_TYPE_AAAA
  557. : DNS_TYPE_A;
  558. }
  559. else if ( fip6 != IPUNION_IS_IP6(&hostInfo.Ip) )
  560. {
  561. continue;
  562. }
  563. //
  564. // check name match
  565. //
  566. // DCR: use unicode name? or UTF8 name directly
  567. pnameHost = NULL;
  568. if ( Dns_NameCompare_A(
  569. hostInfo.pHostName,
  570. pnameAnsi ) )
  571. {
  572. pnameHost = pnameAnsi;
  573. }
  574. //
  575. // check match to previous CNAME
  576. //
  577. else if ( pcnameHost )
  578. {
  579. if ( Dns_NameCompare_A(
  580. hostInfo.pHostName,
  581. pcnameHost ) )
  582. {
  583. pnameHost = pcnameHost;
  584. }
  585. }
  586. //
  587. // aliases
  588. //
  589. // DCR_QUESTION: build aliases even if name hit?
  590. //
  591. // currently:
  592. // - don't allow alias if already have direct record
  593. // - limit to one alias (CNAME)
  594. //
  595. // if find alias:
  596. // - build CNAME record
  597. // - save CNAME target (in ANSI for faster compares)
  598. // - check CNAME target for subsequent address records (above)
  599. //
  600. else if ( IS_DNS_LIST_STRUCT_EMPTY( forwardList )
  601. &&
  602. !prrAlias )
  603. {
  604. PCHAR * paliasEntry;
  605. PCHAR palias;
  606. for( paliasEntry = hostInfo.AliasArray;
  607. palias = *paliasEntry;
  608. paliasEntry++ )
  609. {
  610. if ( Dns_NameCompare_A(
  611. palias,
  612. pnameAnsi ) )
  613. {
  614. DNSDBG( QUERY, (
  615. "Build CNAME record for name %s to CNAME %s\n",
  616. pnameAnsi,
  617. hostInfo.pHostName ));
  618. prrAlias = Dns_CreatePtrTypeRecord(
  619. pnameAnsi,
  620. TRUE, // copy name
  621. hostInfo.pHostName,
  622. DNS_TYPE_CNAME,
  623. HOSTFILE_RECORD_TTL,
  624. DnsCharSetAnsi,
  625. DnsCharSetUnicode );
  626. if ( prrAlias )
  627. {
  628. pcnameHost = Dns_NameCopyAllocate(
  629. hostInfo.pHostName,
  630. 0,
  631. DnsCharSetAnsi,
  632. DnsCharSetAnsi );
  633. pnameHost = pcnameHost;
  634. }
  635. break;
  636. }
  637. }
  638. }
  639. // add address record for this hostline
  640. if ( pnameHost )
  641. {
  642. DNSDBG( QUERY, (
  643. "Build address record for name %s\n",
  644. pnameHost ));
  645. prr = Dns_CreateForwardRecord(
  646. pnameHost,
  647. & hostInfo.Ip,
  648. HOSTFILE_RECORD_TTL,
  649. DnsCharSetAnsi,
  650. DnsCharSetUnicode );
  651. if ( prr )
  652. {
  653. DNS_LIST_STRUCT_ADD( forwardList, prr );
  654. }
  655. }
  656. }
  657. }
  658. //
  659. // build response
  660. //
  661. // DCR: new multiple section response
  662. //
  663. if ( !fptr )
  664. {
  665. prr = forwardList.pFirst;
  666. if ( prrAlias )
  667. {
  668. prrAlias->pNext = prr;
  669. prr = prrAlias;
  670. }
  671. }
  672. IF_DNSDBG( QUERY )
  673. {
  674. DnsDbg_RecordSet(
  675. "HostFile Answers:",
  676. prr );
  677. }
  678. pBlob->pRecords = prr;
  679. Cleanup:
  680. //
  681. // cleanup
  682. //
  683. Dns_CloseHostFile( &hostInfo );
  684. if ( pcnameHost )
  685. {
  686. FREE_HEAP( pcnameHost );
  687. }
  688. DNSDBG( TRACE, (
  689. "Leave QueryHostFile() -> %d\n"
  690. "\tprr = %p\n",
  691. prr ? TRUE : FALSE,
  692. prr ));
  693. return( prr ? TRUE : FALSE );
  694. }
  695. //
  696. // End hostfile.c
  697. //