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.

941 lines
20 KiB

  1. /*++
  2. Copyright (c) 2000-2002 Microsoft Corporation
  3. Module Name:
  4. localip.c
  5. Abstract:
  6. Local IP address routines.
  7. Author:
  8. Jim Gilroy October 2000
  9. Revision History:
  10. --*/
  11. #include "local.h"
  12. //
  13. // TTL on local records
  14. //
  15. // Use registration TTL
  16. //
  17. #define LOCAL_IP_TTL (g_RegistrationTtl)
  18. //
  19. // Test locality.
  20. //
  21. BOOL
  22. LocalIp_IsAddrLocal(
  23. IN PDNS_ADDR pAddr,
  24. IN PDNS_ADDR_ARRAY pLocalArray, OPTIONAL
  25. IN PDNS_NETINFO pNetInfo OPTIONAL
  26. )
  27. /*++
  28. Routine Description:
  29. Determine if IP is local.
  30. Arguments:
  31. pAddr -- ptr to IP to test
  32. pLocalArray -- local addresses to check
  33. pNetInfo -- network info to check
  34. Return Value:
  35. TRUE if local IP
  36. FALSE if remote
  37. --*/
  38. {
  39. BOOL bresult = FALSE;
  40. PADDR_ARRAY parray;
  41. //
  42. // test for loopback
  43. //
  44. if ( DnsAddr_IsLoopback(
  45. pAddr,
  46. 0 // any family
  47. ) )
  48. {
  49. return TRUE;
  50. }
  51. //
  52. // test against local addrs
  53. // - use addr list if provided
  54. // - use netinfo if provided
  55. // - otherwise query to get it
  56. //
  57. parray = pLocalArray;
  58. if ( !parray )
  59. {
  60. parray = NetInfo_GetLocalAddrArray(
  61. pNetInfo,
  62. NULL, // no specific adapter
  63. 0, // no specific family
  64. 0, // no flags
  65. FALSE // no force
  66. );
  67. }
  68. bresult = DnsAddrArray_ContainsAddr(
  69. parray,
  70. pAddr,
  71. DNSADDR_MATCH_IP );
  72. if ( parray != pLocalArray )
  73. {
  74. DnsAddrArray_Free( parray );
  75. }
  76. return bresult;
  77. }
  78. //
  79. // Local address list
  80. //
  81. BOOL
  82. local_ScreenLocalAddrNotCluster(
  83. IN PDNS_ADDR pAddr,
  84. IN PDNS_ADDR pScreenAddr OPTIONAL
  85. )
  86. /*++
  87. Routine Description:
  88. Screen cluster out of local addrs.
  89. This is DnsAddrArray_ContainsAddrEx() screening function
  90. for use by GetLocalPtrRecord() to avoid matching cluster
  91. addresses.
  92. Arguments:
  93. pAddr -- address to screen
  94. pScreenAddr -- screening info; ignored for this function
  95. Return Value:
  96. TRUE if local addr passes screen -- is not cluster IP.
  97. FALSE if cluster.
  98. --*/
  99. {
  100. // screen flags
  101. // - exact match on address type flag bits
  102. return ( !(pAddr->Flags & DNSADDR_FLAG_TRANSIENT) );
  103. }
  104. PDNS_RECORD
  105. local_GetLocalPtrRecord(
  106. IN OUT PQUERY_BLOB pBlob
  107. )
  108. /*++
  109. Routine Description:
  110. Get pointer record for local IP.
  111. Arguments:
  112. pBlob -- query blob
  113. Uses:
  114. pNameOrig
  115. wType
  116. pNetInfo
  117. Sets:
  118. NameBufferWide -- used as local storage
  119. Return Value:
  120. Ptr to record for query, if query name\type is IP.
  121. NULL if query not for IP.
  122. --*/
  123. {
  124. DNS_ADDR addr;
  125. PDNS_ADDR paddr = &addr;
  126. PDNS_RECORD prr;
  127. PWSTR pnameHost = NULL;
  128. PWSTR pnameDomain;
  129. PDNS_ADAPTER padapter = NULL;
  130. DWORD iter;
  131. PWSTR pnameQuery = pBlob->pNameOrig;
  132. PDNS_NETINFO pnetInfo = pBlob->pNetInfo;
  133. DNSDBG( TRACE, (
  134. "\nlocal_GetLocalPtrRecord( %S )\n",
  135. pnameQuery ));
  136. if ( !pnameQuery )
  137. {
  138. return NULL;
  139. }
  140. //
  141. // convert reverse name to IP
  142. //
  143. if ( ! Dns_ReverseNameToDnsAddr_W(
  144. paddr,
  145. pnameQuery ) )
  146. {
  147. DNSDBG( ANY, (
  148. "WARNING: Ptr lookup name %S is not reverse name!\n",
  149. pnameQuery ));
  150. return NULL;
  151. }
  152. //
  153. // check for generic IP match
  154. // - skip for mcast response
  155. // - accept loopback or any on normal query
  156. //
  157. if ( !(pBlob->Flags & DNSP_QUERY_NO_GENERIC_NAMES) )
  158. {
  159. if ( DnsAddr_IsLoopback( paddr, 0 ) )
  160. {
  161. DNSDBG( QUERY, (
  162. "Local PTR lookup matched loopback.\n" ));
  163. goto Matched;
  164. }
  165. else if ( DnsAddr_IsUnspec( paddr, 0 ) )
  166. {
  167. DNSDBG( QUERY, (
  168. "Local PTR lookup matched unspec.\n" ));
  169. goto Matched;
  170. }
  171. }
  172. //
  173. // check for specific IP match
  174. //
  175. NetInfo_AdapterLoopStart( pnetInfo );
  176. while( padapter = NetInfo_GetNextAdapter( pnetInfo ) )
  177. {
  178. //
  179. // have address match?
  180. // if server must use screening function to skip cluster IPs
  181. //
  182. // note: cluster IPs will be mapped back to virtual cluster
  183. // name by cache
  184. if ( DnsAddrArray_ContainsAddrEx(
  185. padapter->pLocalAddrs,
  186. paddr,
  187. DNSADDR_MATCH_IP,
  188. g_IsServer
  189. ? local_ScreenLocalAddrNotCluster
  190. : NULL,
  191. NULL // no screen address required
  192. ) )
  193. {
  194. goto Matched;
  195. }
  196. }
  197. //
  198. // no IP match
  199. //
  200. DNSDBG( QUERY, (
  201. "Leave local PTR lookup. No local IP match.\n"
  202. "\treverse name = %S\n",
  203. pnameQuery ));
  204. return NULL;
  205. Matched:
  206. //
  207. // create hostname
  208. // preference order:
  209. // - full PDN
  210. // - full adapter domain name from adapter with IP
  211. // - hostname (single label)
  212. // - "localhost"
  213. //
  214. {
  215. PWCHAR pnameBuf = pBlob->NameBuffer;
  216. pnameHost = pnetInfo->pszHostName;
  217. if ( !pnameHost )
  218. {
  219. pnameHost = L"localhost";
  220. goto Build;
  221. }
  222. pnameDomain = pnetInfo->pszDomainName;
  223. if ( !pnameDomain )
  224. {
  225. // use the adapter name even if NOT set for registration
  226. // if ( !padapter ||
  227. // !(padapter->InfoFlags & AINFO_FLAG_REGISTER_DOMAIN_NAME) )
  228. if ( !padapter )
  229. {
  230. goto Build;
  231. }
  232. pnameDomain = padapter->pszAdapterDomain;
  233. if ( !pnameDomain )
  234. {
  235. goto Build;
  236. }
  237. }
  238. if ( ! Dns_NameAppend_W(
  239. pnameBuf,
  240. DNS_MAX_NAME_BUFFER_LENGTH,
  241. pnameHost,
  242. pnameDomain ) )
  243. {
  244. DNS_ASSERT( FALSE );
  245. goto Build;
  246. }
  247. pnameHost = pnameBuf;
  248. Build:
  249. //
  250. // create record
  251. //
  252. prr = Dns_CreatePtrRecordEx(
  253. paddr,
  254. (PDNS_NAME) pnameHost,
  255. LOCAL_IP_TTL,
  256. DnsCharSetUnicode,
  257. DnsCharSetUnicode );
  258. if ( !prr )
  259. {
  260. DNSDBG( ANY, (
  261. "Local PTR record creation failed for name %S!\n",
  262. pnameHost ));
  263. return NULL;
  264. }
  265. }
  266. DNSDBG( QUERY, (
  267. "Created local PTR record %p with hostname %S.\n"
  268. "\treverse name = %S\n",
  269. prr,
  270. pnameHost,
  271. pnameQuery ));
  272. return prr;
  273. }
  274. VOID
  275. localip_BuildRRListFromArray(
  276. IN OUT PDNS_RRSET pRRSet,
  277. IN PWSTR pNameRecord,
  278. IN WORD wType,
  279. IN PDNS_ADDR_ARRAY pAddrArray
  280. )
  281. /*++
  282. Routine Description:
  283. Build address record lists for local IP.
  284. Helper function as this same logic is in multiple places
  285. due to the tedious way we must put this together.
  286. Arguments:
  287. Return Value:
  288. --*/
  289. {
  290. DWORD jter;
  291. PDNS_RECORD prr;
  292. INT fpass;
  293. DNSDBG( TRACE, (
  294. "localip_BuildRRListFromArray()\n"
  295. "\tpname = %S\n"
  296. "\twtype = %d\n"
  297. "\tparray = %p\n",
  298. pNameRecord,
  299. wType,
  300. pAddrArray ));
  301. //
  302. // validate array
  303. //
  304. if ( !pAddrArray )
  305. {
  306. DNSDBG( QUERY, (
  307. "No addrs for record build -- NULL array!!!\n" ));
  308. return;
  309. }
  310. //
  311. // loop through adapter addresses
  312. //
  313. if ( pRRSet->pFirstRR != NULL )
  314. {
  315. pNameRecord = NULL;
  316. }
  317. for ( jter = 0;
  318. jter < pAddrArray->AddrCount;
  319. jter++ )
  320. {
  321. prr = Dns_CreateForwardRecord(
  322. pNameRecord,
  323. wType,
  324. &pAddrArray->AddrArray[jter],
  325. LOCAL_IP_TTL,
  326. DnsCharSetUnicode,
  327. DnsCharSetUnicode );
  328. if ( prr )
  329. {
  330. DNS_RRSET_ADD( *pRRSet, prr );
  331. pNameRecord = NULL;
  332. }
  333. }
  334. }
  335. PDNS_RECORD
  336. local_GetLocalAddressRecord(
  337. IN OUT PQUERY_BLOB pBlob
  338. )
  339. /*++
  340. Routine Description:
  341. Get address record for local IP.
  342. Arguments:
  343. pBlob -- query blob
  344. Uses:
  345. pNameOrig
  346. wType
  347. pNetInfo
  348. fNoGenericNames
  349. Sets:
  350. fNoIpLocal
  351. TRUE -- no IP of type found, defaulted record
  352. FALSE -- records valid
  353. NameBuffer -- used as local storage
  354. fGenericNames -- accept local generic names (NULL, loopback, localhost)
  355. TRUE for DnsQuery() path
  356. FALSE for mcast queries
  357. Return Value:
  358. Ptr to record for query, if query name\type is IP.
  359. NULL if query not for IP.
  360. --*/
  361. {
  362. DNS_ADDR addr;
  363. IP4_ADDRESS ip4;
  364. IP6_ADDRESS ip6;
  365. PDNS_ADDR_ARRAY parray = NULL;
  366. DWORD addrFlag;
  367. DWORD family;
  368. PDNS_RECORD prr;
  369. BOOL fmatchedName = FALSE;
  370. PWSTR pnameRecord = NULL;
  371. DWORD iter;
  372. DWORD bufLength;
  373. PWSTR pnameDomain;
  374. DNS_RRSET rrset;
  375. WORD wtype = pBlob->wType;
  376. PWSTR pnameBuf = pBlob->NameBuffer;
  377. PWSTR pnameQuery = pBlob->pNameOrig;
  378. PDNS_NETINFO pnetInfo = pBlob->pNetInfo;
  379. PDNS_ADAPTER padapter;
  380. DNSDBG( TRACE, (
  381. "local_GetLocalAddressRecord( %S, %d )\n",
  382. pnameQuery,
  383. wtype ));
  384. // clear out param
  385. pBlob->fNoIpLocal = FALSE;
  386. // address types to include
  387. addrFlag = DNS_CONFIG_FLAG_ADDR_NON_CLUSTER;
  388. family = Family_GetFromDnsType( wtype );
  389. if ( !family )
  390. {
  391. DNS_ASSERT( FALSE );
  392. return NULL;
  393. }
  394. // init record builder
  395. DNS_RRSET_INIT( rrset );
  396. //
  397. // generic local names
  398. // - skip for doing MCAST matching
  399. // - NULL, empty, loopback, localhost accepted for regular query
  400. //
  401. if ( pBlob->Flags & DNSP_QUERY_NO_GENERIC_NAMES )
  402. {
  403. if ( !pnameQuery )
  404. {
  405. return NULL;
  406. }
  407. }
  408. else
  409. {
  410. //
  411. // NULL treated as local PDN
  412. //
  413. if ( !pnameQuery || !*pnameQuery )
  414. {
  415. DNSDBG( QUERY, ( "Local lookup -- no query name, treat as PDN.\n" ));
  416. goto MatchedPdn;
  417. }
  418. //
  419. // "*" treated as all machine records
  420. //
  421. if ( Dns_NameCompare_W(
  422. pnameQuery,
  423. L"..localmachine" ) )
  424. {
  425. DNSDBG( QUERY, ( "Local lookup -- * query name.\n" ));
  426. addrFlag |= DNS_CONFIG_FLAG_ADDR_CLUSTER;
  427. goto MatchedPdn;
  428. }
  429. //
  430. // loopback or localhost
  431. //
  432. if ( Dns_NameCompare_W(
  433. pnameQuery,
  434. L"loopback" )
  435. ||
  436. Dns_NameCompare_W(
  437. pnameQuery,
  438. L"localhost" ) )
  439. {
  440. pnameRecord = pnameQuery,
  441. IP6_SET_ADDR_LOOPBACK( &ip6 );
  442. ip4 = DNS_NET_ORDER_LOOPBACK;
  443. goto SingleIp;
  444. }
  445. }
  446. //
  447. // if no hostname -- done
  448. //
  449. if ( !pnetInfo->pszHostName )
  450. {
  451. DNSDBG( QUERY, ( "No hostname configured!\n" ));
  452. return NULL;
  453. }
  454. //
  455. // copy name
  456. //
  457. if ( ! Dns_NameCopyStandard_W(
  458. pnameBuf,
  459. pBlob->pNameOrig ) )
  460. {
  461. DNSDBG( ANY, (
  462. "Invalid name %S to local address query.\n",
  463. pnameQuery ));
  464. return NULL;
  465. }
  466. // split query name into hostname and domain name
  467. pnameDomain = Dns_SplitHostFromDomainNameW( pnameBuf );
  468. // must have hostname match
  469. if ( !Dns_NameCompare_W(
  470. pnameBuf,
  471. pnetInfo->pszHostName ) )
  472. {
  473. DNSDBG( ANY, (
  474. "Local lookup, failed hostname match!\n",
  475. pnameQuery ));
  476. return NULL;
  477. }
  478. //
  479. // hostname's match
  480. // - no domain name => PDN equivalent
  481. // - match PDN => all addresses
  482. // - match adapter name => adapter addresses
  483. // - no match
  484. //
  485. // check PDN match
  486. if ( !pnameDomain )
  487. {
  488. DNSDBG( QUERY, ( "Local lookup -- no domain, treat as PDN!\n" ));
  489. goto MatchedPdn;
  490. }
  491. if ( Dns_NameCompare_W(
  492. pnameDomain,
  493. pnetInfo->pszDomainName ) )
  494. {
  495. DNSDBG( QUERY, ( "Local lookup -- matched PDN!\n" ));
  496. goto MatchedPdn;
  497. }
  498. //
  499. // NO PDN match -- check adapter name match
  500. //
  501. for ( iter=0; iter<pnetInfo->AdapterCount; iter++ )
  502. {
  503. padapter = NetInfo_GetAdapterByIndex( pnetInfo, iter );
  504. if ( !(padapter->InfoFlags & AINFO_FLAG_REGISTER_DOMAIN_NAME) ||
  505. ! padapter->pLocalAddrs ||
  506. ! Dns_NameCompare_W(
  507. pnameDomain,
  508. padapter->pszAdapterDomain ) )
  509. {
  510. continue;
  511. }
  512. // build name if we haven't built it before
  513. // we stay in the loop in case more than one
  514. // adapter has the same domain name
  515. if ( !fmatchedName )
  516. {
  517. DNSDBG( QUERY, (
  518. "Local lookup -- matched adapter name %S\n",
  519. padapter->pszAdapterDomain ));
  520. if ( ! Dns_NameAppend_W(
  521. pnameBuf,
  522. DNS_MAX_NAME_BUFFER_LENGTH,
  523. pnetInfo->pszHostName,
  524. padapter->pszAdapterDomain ) )
  525. {
  526. DNS_ASSERT( FALSE );
  527. return NULL;
  528. }
  529. pnameRecord = pnameBuf;
  530. fmatchedName = TRUE;
  531. }
  532. //
  533. // build forward records for all IPs in adapter
  534. //
  535. // note: we do NOT include cluster addrs for adapter name match
  536. // as we only must be able to provide in the
  537. // gethostbyname(NULL) type cases, which use PDN
  538. //
  539. // DCR: mem alloc failures building local records
  540. // getting no records built mapped properly to NO_MEMORY error
  541. //
  542. parray = NetInfo_CreateLocalAddrArray(
  543. pnetInfo,
  544. NULL, // no adapter name
  545. padapter, // just this adapter
  546. family,
  547. addrFlag );
  548. if ( !parray )
  549. {
  550. continue;
  551. }
  552. localip_BuildRRListFromArray(
  553. &rrset,
  554. pnameRecord,
  555. wtype,
  556. parray
  557. );
  558. DnsAddrArray_Free( parray );
  559. parray = NULL;
  560. }
  561. //
  562. // done with adapter name match
  563. // either
  564. // - no match
  565. // - match but didn't get IPs
  566. // - match
  567. if ( !fmatchedName )
  568. {
  569. DNSDBG( QUERY, (
  570. "Leave local_GetLocalAddressRecord() => no domain name match.\n" ));
  571. return NULL;
  572. }
  573. prr = rrset.pFirstRR;
  574. if ( prr )
  575. {
  576. DNSDBG( QUERY, (
  577. "Leave local_GetLocalAddressRecord() => %p matched adapter name.\n",
  578. prr ));
  579. return prr;
  580. }
  581. goto NoIp;
  582. MatchedPdn:
  583. //
  584. // matched PDN
  585. //
  586. // for gethostbyname() app-compat, must build in specific order
  587. // - first IP in each adapter
  588. // - remainder of IPs on adapters
  589. //
  590. if ( pnetInfo->pszHostName )
  591. {
  592. if ( ! Dns_NameAppend_W(
  593. pnameBuf,
  594. DNS_MAX_NAME_BUFFER_LENGTH,
  595. pnetInfo->pszHostName,
  596. pnetInfo->pszDomainName ) )
  597. {
  598. DNS_ASSERT( FALSE );
  599. return NULL;
  600. }
  601. pnameRecord = pnameBuf;
  602. }
  603. else
  604. {
  605. pnameRecord = L"localhost";
  606. }
  607. //
  608. // read addrs
  609. //
  610. // note: we don't add cluster flag above, as cluster addrs
  611. // not used on adapter name matches, just PDN for gethostbyname()
  612. // compat
  613. //
  614. if ( g_IsServer &&
  615. (pBlob->Flags & DNSP_QUERY_INCLUDE_CLUSTER) )
  616. {
  617. addrFlag |= DNS_CONFIG_FLAG_ADDR_CLUSTER;
  618. }
  619. // DCR: mem alloc failures building local records
  620. // getting no records built mapped properly to NO_MEMORY error
  621. //
  622. parray = NetInfo_CreateLocalAddrArray(
  623. pnetInfo,
  624. NULL, // no adapter name
  625. NULL, // no specific adatper
  626. family,
  627. addrFlag );
  628. if ( !parray )
  629. {
  630. return NULL;
  631. }
  632. localip_BuildRRListFromArray(
  633. &rrset,
  634. pnameRecord,
  635. wtype,
  636. parray
  637. );
  638. DnsAddrArray_Free( parray );
  639. // if successfully built -- done
  640. prr = rrset.pFirstRR;
  641. if ( prr )
  642. {
  643. DNSDBG( QUERY, (
  644. "Leave local_GetLocalAddressRecord() => %p matched PDN name.\n",
  645. prr ));
  646. return prr;
  647. }
  648. // matched name but found no records
  649. // fall through to NoIp section
  650. //
  651. //goto NoIp;
  652. NoIp:
  653. //
  654. // matched name -- but no IP
  655. // use loopback address; assume this is a lookup prior to
  656. // connect which happens to be the local name, rather than an
  657. // explict local lookup to get binding IPs
  658. //
  659. DNSDBG( ANY, (
  660. "WARNING: local name match but no IP -- using loopback\n" ));
  661. IP6_SET_ADDR_LOOPBACK( &ip6 );
  662. ip4 = DNS_NET_ORDER_LOOPBACK;
  663. pBlob->fNoIpLocal = TRUE;
  664. // fall through to single IP
  665. SingleIp:
  666. // single IP
  667. // - loopback address and be unicode queried name
  668. if ( wtype == DNS_TYPE_A )
  669. {
  670. DnsAddr_BuildFromIp4(
  671. &addr,
  672. ip4,
  673. 0 // no port
  674. );
  675. }
  676. else
  677. {
  678. DnsAddr_BuildFromIp6(
  679. &addr,
  680. & ip6,
  681. 0, // no scope
  682. 0 // no port
  683. );
  684. }
  685. prr = Dns_CreateForwardRecord(
  686. (PDNS_NAME) pnameRecord,
  687. wtype,
  688. & addr,
  689. LOCAL_IP_TTL,
  690. DnsCharSetUnicode,
  691. DnsCharSetUnicode );
  692. return prr;
  693. }
  694. DNS_STATUS
  695. Local_GetRecordsForLocalName(
  696. IN OUT PQUERY_BLOB pBlob
  697. )
  698. /*++
  699. Routine Description:
  700. Get local address info array.
  701. EXPORTED: called by resolver for MCAST
  702. Arguments:
  703. pBlob -- query blob
  704. Uses:
  705. pNameOrig
  706. wType
  707. pNetInfo
  708. Sets:
  709. pLocalRecords
  710. fNoIpLocal if local name without records
  711. Return Value:
  712. ERROR_SUCCESS if successful.
  713. DNS_ERROR_RCODE_NAME_ERROR on failure.
  714. --*/
  715. {
  716. WORD wtype = pBlob->wType;
  717. PDNS_RECORD prr = NULL;
  718. if ( wtype == DNS_TYPE_A ||
  719. wtype == DNS_TYPE_AAAA )
  720. {
  721. prr = local_GetLocalAddressRecord( pBlob );
  722. }
  723. else if ( wtype == DNS_TYPE_PTR )
  724. {
  725. prr = local_GetLocalPtrRecord( pBlob );
  726. }
  727. // set local records
  728. // - if not NO IP situation then this
  729. // is final query result also
  730. if ( prr )
  731. {
  732. pBlob->pLocalRecords = prr;
  733. if ( !pBlob->fNoIpLocal )
  734. {
  735. pBlob->pRecords = prr;
  736. }
  737. return ERROR_SUCCESS;
  738. }
  739. return DNS_ERROR_RCODE_NAME_ERROR;
  740. }
  741. //
  742. // End localip.c
  743. //