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.

1433 lines
37 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. mcast.c
  5. Abstract:
  6. DNS Resolver Service
  7. Multicast routines.
  8. Author:
  9. Glenn Curtis (glennc) December 1999
  10. Revision History:
  11. James Gilroy (jamesg) February 2000 cleanup
  12. --*/
  13. #include "local.h"
  14. //
  15. // Globals
  16. //
  17. HANDLE g_hMulticastThread = NULL;
  18. BOOL g_MulticastStop = FALSE;
  19. SOCKET g_MulticastUnicastSocket = 0;
  20. PSOCKET_CONTEXT g_MulticastIoContextList = NULL;
  21. HANDLE g_MulticastCompletionPort = NULL;
  22. //
  23. // Should be read from netinfo blob
  24. //
  25. PSTR g_HostName = NULL;
  26. //
  27. // Multicast config globals
  28. //
  29. // DCR: regkeys for multicast values
  30. //
  31. #define DNS_DEFAULT_ALLOW_MULTICAST_RESOLVER_OPERATION 0 // Off
  32. #define DNS_DEFAULT_ALLOW_MULTICAST_RESOLVER_AS_PROXY 0 // Off
  33. #define DNS_DEFAULT_ALLOW_MULTICAST_DNS_SRV_RECORD 0 // Off
  34. #define DNS_DEFAULT_MULTICAST_RESOLVER_RECORD_TTL 10*60 // 10 minutes
  35. DWORD g_MulticastRecordTTL = DNS_DEFAULT_MULTICAST_RESOLVER_RECORD_TTL;
  36. BOOL g_AllowMulticastAsProxy = FALSE;
  37. BOOL g_AllowMulticastDnsSrvRecord = FALSE;
  38. //
  39. // Private prototypes
  40. //
  41. BOOL
  42. IsLocalMachineQuery(
  43. IN LPSTR pName,
  44. IN WORD Type,
  45. OUT PDNS_RECORD * ppRecord
  46. );
  47. VOID
  48. FixupNameOwnerPointers(
  49. IN OUT PDNS_RECORD pRecord
  50. );
  51. PDNS_RECORD
  52. BuildPTR(
  53. IN LPSTR pName,
  54. IN LPSTR pHostname,
  55. IN LPSTR pDomain,
  56. IN LPSTR pPrimaryDomain
  57. );
  58. PDNS_RECORD
  59. BuildARecord(
  60. IN LPSTR Name,
  61. IN IP_ADDRESS Address );
  62. PDNS_RECORD
  63. BuildDNSServerRecord(
  64. IN IP_ADDRESS Address );
  65. PDNS_RECORD
  66. BuildLocalAddressRecords(
  67. IN LPSTR Name );
  68. BOOL
  69. IsLocalAddress(
  70. IN IP_ADDRESS Ip );
  71. PSOCKET_CONTEXT
  72. AllocateIoContext(
  73. IN IP_ADDRESS ipAddr );
  74. VOID
  75. FreeIoContextList(
  76. IN PSOCKET_CONTEXT pContext,
  77. IN BOOL fIssueSocketShutdown );
  78. VOID
  79. DropReceive(
  80. IN PSOCKET_CONTEXT pContext );
  81. VOID
  82. MulticastThread(
  83. VOID
  84. )
  85. /*++
  86. Routine Description:
  87. Multicast response thread.
  88. Runs while cache is running, responding to multicast queries.
  89. Arguments:
  90. None.
  91. Return Value:
  92. None.
  93. --*/
  94. {
  95. DNS_STATUS status = NO_ERROR;
  96. PDNS_NETINFO ptempNetInfo = NULL;
  97. PSOCKET_CONTEXT pcontext;
  98. DWORD iter;
  99. DWORD bytesRecvd;
  100. LPOVERLAPPED poverlapped;
  101. //
  102. // init globals for safe cleanup on failure
  103. //
  104. g_MulticastStop = FALSE;
  105. g_MulticastCompletionPort = NULL;
  106. g_MulticastUnicastSocket = 0;
  107. g_MulticastIoContextList = NULL;
  108. //
  109. // We are going to create a completion port with
  110. // socket contexts for each of the primary IP addresses of each
  111. // adapter on the system.
  112. //
  113. //
  114. // Get a copy of the network adapter information
  115. //
  116. ptempNetInfo = GrabNetworkInfo();
  117. if ( ! ptempNetInfo )
  118. {
  119. goto Cleanup;
  120. }
  121. //
  122. // create multicast completion port
  123. //
  124. g_MulticastCompletionPort = CreateIoCompletionPort(
  125. INVALID_HANDLE_VALUE,
  126. NULL,
  127. 0,
  128. 0 );
  129. if ( ! g_MulticastCompletionPort )
  130. {
  131. DNSLOG_F1( "Error: Failed to create io completion port." );
  132. goto Cleanup;
  133. }
  134. // We create two sockets here, one for multicast receives and
  135. // one for the unicast response. This shouldn't be necessary;
  136. // there should be nothing preventing us from responding via
  137. // unicast even with a socket that's joined to a multicast address.
  138. // In most cases, it does in fact work; but it seems that
  139. // packets sent to the local address do not arrive if they are
  140. // sent from a socket that is configured for multicast receive.
  141. // Apparently, such a socket sends all packets onto the wire
  142. // without checking the destination address. I imagine this is
  143. // a bug in the TCP stack, perhaps, but for now, creating two
  144. // separate sockets is a simple workaround. - tbrown 10/19/99
  145. g_MulticastUnicastSocket = Dns_CreateSocket(
  146. SOCK_DGRAM,
  147. INADDR_ANY,
  148. DNS_PORT_NET_ORDER );
  149. if ( g_MulticastUnicastSocket == 0 ||
  150. g_MulticastUnicastSocket == INVALID_SOCKET )
  151. {
  152. DNSLOG_F1( "Error: Failed to create unicast socket." );
  153. goto Cleanup;
  154. }
  155. //
  156. // build context list
  157. // - create socket\context for each adapters first IP
  158. // - associate socket with completion port
  159. //
  160. g_MulticastIoContextList = NULL;
  161. pcontext = NULL;
  162. for ( iter = 0; iter < ptempNetInfo->cAdapterCount; iter++ )
  163. {
  164. PIP_ARRAY pipArray;
  165. pipArray = ptempNetInfo->AdapterArray[iter]->pAdapterIPAddresses;
  166. if ( pipArray &&
  167. pipArray->AddrCount )
  168. {
  169. PSOCKET_CONTEXT pnewContext;
  170. pnewContext = AllocateIoContext( pipArray->AddrArray[0] );
  171. if ( pnewContext )
  172. {
  173. HANDLE hport = NULL;
  174. if ( pcontext )
  175. {
  176. pcontext->pNext = pnewContext;
  177. pcontext = pnewContext;
  178. }
  179. else
  180. {
  181. g_MulticastIoContextList = pnewContext;
  182. pcontext = pnewContext;
  183. }
  184. hport = CreateIoCompletionPort(
  185. (HANDLE) pnewContext->Socket,
  186. g_MulticastCompletionPort,
  187. (UINT_PTR) pnewContext,
  188. 0 );
  189. if ( !hport )
  190. {
  191. DNSLOG_F1( "Error: Failed to add socket to io completion port." );
  192. goto Cleanup;
  193. }
  194. }
  195. }
  196. }
  197. //
  198. // if no sockets -- done
  199. //
  200. if ( ! g_MulticastIoContextList )
  201. {
  202. goto Cleanup;
  203. }
  204. //
  205. // drop listen on sockets
  206. //
  207. pcontext = g_MulticastIoContextList;
  208. while ( pcontext )
  209. {
  210. DropReceive( pcontext );
  211. pcontext = pcontext->pNext;
  212. }
  213. //
  214. // main listen loop
  215. //
  216. do
  217. {
  218. if ( g_LogTraceInfo )
  219. {
  220. DNSLOG_F1( " Multicast Resolver: Going to listen for message." );
  221. DNSLOG_F1( "" );
  222. }
  223. if ( GetQueuedCompletionStatus(
  224. g_MulticastCompletionPort,
  225. & bytesRecvd,
  226. & (ULONG_PTR) pcontext,
  227. & poverlapped,
  228. INFINITE ) )
  229. {
  230. //
  231. // We received notice that something happened on a given
  232. // completion port, get the socket from the context and
  233. // do a receive to see what we got.
  234. //
  235. if ( pcontext && bytesRecvd )
  236. {
  237. WORD Xid;
  238. IP4_ADDRESS Ip;
  239. BYTE Opcode;
  240. WORD QuestionCount;
  241. WORD AnswerCount;
  242. WORD NameServerCount;
  243. WORD AdditionalCount;
  244. Ip = MSG_REMOTE_IP4( pcontext->pMsg );
  245. Xid = pcontext->pMsg->MessageHead.Xid;
  246. Opcode = pcontext->pMsg->MessageHead.Opcode;
  247. QuestionCount = pcontext->pMsg->MessageHead.QuestionCount;
  248. AnswerCount = pcontext->pMsg->MessageHead.AnswerCount;
  249. NameServerCount = pcontext->pMsg->MessageHead.NameServerCount;
  250. AdditionalCount = pcontext->pMsg->MessageHead.AdditionalCount;
  251. if ( g_LogTraceInfo )
  252. {
  253. DNSLOG_F1( " Multicast Resolver: Received DNS message." );
  254. DNSLOG_F1( " Message contained . . ." );
  255. DNSLOG_F2( " Xid : 0x%x", Xid );
  256. DNSLOG_F2( " IP Address : %s", IP_STRING( Ip ) );
  257. DNSLOG_F2( " Opcode : 0x%x", Opcode );
  258. DNSLOG_F1( "" );
  259. }
  260. if ( g_MulticastStop )
  261. {
  262. DNSLOG_F1( " Multicast Resolver detected stop signal." );
  263. DNSLOG_F1( " Will not process last received message." );
  264. DNSLOG_F1( "" );
  265. continue;
  266. }
  267. if ( IsLocalAddress( Ip ) )
  268. {
  269. if ( g_LogTraceInfo )
  270. {
  271. DNSLOG_F1( " Multicast Resolver: Skip query from local machine." );
  272. DNSLOG_F1( "" );
  273. }
  274. continue;
  275. }
  276. if ( Opcode == DNS_OPCODE_QUERY &&
  277. QuestionCount == 1 &&
  278. AnswerCount == 0 &&
  279. NameServerCount == 0 &&
  280. AdditionalCount == 0 )
  281. {
  282. char QuestionName[ DNS_MAX_NAME_BUFFER_LENGTH ];
  283. WORD QuestionNameLength = DNS_MAX_NAME_BUFFER_LENGTH;
  284. PCHAR pch;
  285. WORD QuestionType = 0;
  286. WORD QuestionClass = 0;
  287. PDNS_RECORD pRecord = NULL;
  288. pch = (PCHAR) &pcontext->pMsg->MessageBody;
  289. //
  290. // Get DNS Question name from packet
  291. //
  292. pch = Dns_ReadPacketName(
  293. QuestionName,
  294. &QuestionNameLength,
  295. 0,
  296. 0,
  297. pch,
  298. (PCHAR) &pcontext->pMsg->MessageHead,
  299. pcontext->pMsg->pBufferEnd );
  300. if ( !pch )
  301. {
  302. DNSLOG_F1( " Multicast Resolver: Dns_ReadPacketName failed" );
  303. DNSLOG_F2( " with error: 0x%x" , DNS_RCODE_FORMAT_ERROR );
  304. DNSLOG_F1( "" );
  305. continue;
  306. }
  307. //
  308. // Get DNS Question type from packet
  309. //
  310. QuestionType = ntohs( *(UNALIGNED WORD *) pch );
  311. pch += sizeof( WORD );
  312. //
  313. // Get DNS Question class from packet
  314. //
  315. QuestionClass = ntohs( *(UNALIGNED WORD *) pch );
  316. pch += sizeof( WORD );
  317. DNSLOG_F1( " Multicast Resolver - Valid query for . . ." );
  318. DNSLOG_F2( " Name : %s", QuestionName );
  319. DNSLOG_F2( " Type : %d", QuestionType );
  320. DNSLOG_F2( " Class : %d", QuestionClass );
  321. DNSLOG_F1( "" );
  322. //
  323. // Set pCurrent so that question section is included
  324. // in response packet.
  325. //
  326. pcontext->pMsg->pCurrent = pch;
  327. pcontext->pMsg->MessageHead.IsResponse = TRUE;
  328. pcontext->pMsg->MessageHead.ResponseCode = 0;
  329. pcontext->pMsg->MessageHead.RecursionAvailable = 0;
  330. pcontext->pMsg->MessageHead.Authoritative = 0;
  331. if ( IsLocalMachineQuery( QuestionName,
  332. QuestionType,
  333. &pRecord ) )
  334. {
  335. DNSLOG_F1( " Multicast Resolver: Got valid local machine query" );
  336. pcontext->pMsg->MessageHead.Authoritative = TRUE;
  337. status = Dns_AddRecordsToMessage( pcontext->pMsg,
  338. pRecord,
  339. FALSE );
  340. Dns_RecordListFree( pRecord );
  341. // Switch to the unicast socket
  342. pcontext->pMsg->Socket = g_MulticastUnicastSocket;
  343. Dns_Send( pcontext->pMsg );
  344. }
  345. else if ( g_AllowMulticastAsProxy )
  346. {
  347. LPSTR lpTempName = NULL;
  348. WORD wNameLen;
  349. DNSLOG_F1( " Multicast Resolver: Going to proxy query for client" );
  350. wNameLen = (WORD) strlen( QuestionName );
  351. lpTempName = MCAST_HEAP_ALLOC_ZERO(
  352. (wNameLen + 1) * sizeof(WCHAR) );
  353. if ( lpTempName == NULL )
  354. {
  355. DNSLOG_F1( " Multicast Resolver: HeapAlloc failed" );
  356. continue;
  357. }
  358. Dns_NameCopy( lpTempName,
  359. NULL,
  360. QuestionName,
  361. wNameLen,
  362. DnsCharSetUtf8,
  363. DnsCharSetUnicode );
  364. status = R_ResolverQuery(
  365. NULL,
  366. (LPWSTR) lpTempName,
  367. QuestionType,
  368. 0,
  369. &pRecord );
  370. MCAST_HEAP_FREE( lpTempName );
  371. if ( status == DNS_ERROR_RCODE_NAME_ERROR )
  372. {
  373. DNSLOG_F1( " Multicast Resolver: returning DNS_RCODE_NAME_ERROR" );
  374. pcontext->pMsg->MessageHead.ResponseCode = DNS_RCODE_NAME_ERROR;
  375. // Switch to the unicast socket
  376. pcontext->pMsg->Socket = g_MulticastUnicastSocket;
  377. Dns_Send( pcontext->pMsg );
  378. }
  379. else if ( status == DNS_ERROR_NAME_DOES_NOT_EXIST )
  380. {
  381. DNSLOG_F1( " Multicast Resolver: returning DNS_RCODE_NXDOMAIN" );
  382. pcontext->pMsg->MessageHead.ResponseCode = DNS_RCODE_NXDOMAIN;
  383. // Switch to the unicast socket
  384. pcontext->pMsg->Socket = g_MulticastUnicastSocket;
  385. Dns_Send( pcontext->pMsg );
  386. }
  387. else if ( status == DNS_ERROR_RCODE_NXRRSET )
  388. {
  389. DNSLOG_F1( " Multicast Resolver: returning DNS_RCODE_NXRRSET" );
  390. pcontext->pMsg->MessageHead.ResponseCode = DNS_RCODE_NXRRSET;
  391. // Switch to the unicast socket
  392. pcontext->pMsg->Socket = g_MulticastUnicastSocket;
  393. Dns_Send( pcontext->pMsg );
  394. }
  395. else if ( status == NO_ERROR )
  396. {
  397. if ( pRecord )
  398. {
  399. FixupNameOwnerPointers( pRecord );
  400. status = Dns_AddRecordsToMessage(
  401. pcontext->pMsg,
  402. pRecord,
  403. FALSE );
  404. Dns_RecordListFree( pRecord );
  405. if ( status != ERROR_SUCCESS )
  406. {
  407. DNSLOG_F1( " Multicast Resolver: Dns_AddRecordsToMessage failed" );
  408. DNSLOG_F2( " with error: 0x%x" , status );
  409. continue;
  410. }
  411. // Switch to the unicast socket
  412. pcontext->pMsg->Socket = g_MulticastUnicastSocket;
  413. Dns_Send( pcontext->pMsg );
  414. }
  415. }
  416. else if ( pRecord )
  417. {
  418. DNSLOG_F1( " Multicast Resolver: Nothing to return" );
  419. Dns_RecordListFree( pRecord );
  420. }
  421. }
  422. else
  423. {
  424. DNSLOG_F1( " Multicast Resolver: Nothing can be done for this client query" );
  425. }
  426. DNSLOG_F1( "" );
  427. }
  428. //
  429. // Now send down another receive request to wait on.
  430. //
  431. DropReceive( pcontext );
  432. }
  433. else
  434. {
  435. DNSLOG_F1( " Multicast Resolver: GQCP returned no context!" );
  436. DNSLOG_F1( " Could be terminating resolver service?" );
  437. DNSLOG_F1( "" );
  438. }
  439. }
  440. else
  441. {
  442. //
  443. // GQCP failed, see what the failure was and handle accordingly
  444. //
  445. status = GetLastError();
  446. if ( !pcontext )
  447. {
  448. continue;
  449. }
  450. //
  451. // Now send down another receive request to wait on.
  452. //
  453. DropReceive( pcontext );
  454. }
  455. }
  456. while( !g_MulticastStop );
  457. Cleanup :
  458. //
  459. // cleanup multicast stuff
  460. // - sockets, contexts, i/o completion port
  461. //
  462. NetInfo_Free( ptempNetInfo );
  463. if ( g_MulticastUnicastSocket )
  464. {
  465. Dns_CloseSocket( g_MulticastUnicastSocket );
  466. g_MulticastUnicastSocket = 0;
  467. }
  468. FreeIoContextList( g_MulticastIoContextList, FALSE );
  469. g_MulticastIoContextList = NULL;
  470. if ( g_MulticastCompletionPort )
  471. {
  472. CloseHandle( g_MulticastCompletionPort );
  473. g_MulticastCompletionPort = 0;
  474. }
  475. DNSLOG_F1( "MulticastThread exiting." );
  476. }
  477. VOID
  478. MulticastThreadSignalStop(
  479. VOID
  480. )
  481. /*++
  482. Routine Description:
  483. Stop the multicast thread.
  484. Note, not synchronous, simply signals shutdown.
  485. Arguments:
  486. None.
  487. Return Value:
  488. None
  489. --*/
  490. {
  491. g_MulticastStop = TRUE;
  492. PostQueuedCompletionStatus(
  493. g_MulticastCompletionPort,
  494. 0,
  495. 0,
  496. NULL );
  497. }
  498. BOOL
  499. IsLocalMachineQuery(
  500. IN LPSTR pName,
  501. IN WORD Type,
  502. OUT PDNS_RECORD * ppRecord
  503. )
  504. {
  505. PDNS_NETINFO ptempNetworkInfo = NULL;
  506. LPSTR pszPrimaryDomain = NULL;
  507. DWORD iter;
  508. DWORD iter2;
  509. PDNS_RECORD presultRecords = NULL;
  510. //
  511. // if no hostname -- bail
  512. //
  513. // note: MUST INSURE hostname is never NULL afterwards or
  514. // (preferred) take local copy under lock
  515. //
  516. if ( !g_HostName )
  517. {
  518. return FALSE;
  519. }
  520. //
  521. // get local copy of network info
  522. //
  523. // DCR_FIX: cleanup net-info creation
  524. //
  525. ptempNetworkInfo = GrabNetworkInfo();
  526. if ( ! ptempNetworkInfo )
  527. {
  528. return FALSE;
  529. }
  530. // get primary domain name -- if any
  531. if ( ptempNetworkInfo->pSearchList )
  532. {
  533. pszPrimaryDomain = ptempNetworkInfo->pSearchList->pszDomainOrZoneName;
  534. }
  535. //
  536. // A record query
  537. //
  538. if ( Type == DNS_TYPE_A )
  539. {
  540. char testName[DNS_MAX_NAME_LENGTH * 2];
  541. //
  542. // host name with PDN if available
  543. //
  544. strcpy( testName, g_HostName );
  545. if ( pszPrimaryDomain )
  546. {
  547. strcat( testName, "." );
  548. strcat( testName, pszPrimaryDomain );
  549. }
  550. // name matches hostname -- return name (with PDN if available)
  551. if ( Dns_NameCompare_UTF8( pName, g_HostName ) )
  552. {
  553. presultRecords = BuildLocalAddressRecords( testName );
  554. goto Done;
  555. }
  556. // name matches full PDN -- return full PDN
  557. if ( pszPrimaryDomain &&
  558. Dns_NameCompare_UTF8( pName, testName ) )
  559. {
  560. presultRecords = BuildLocalAddressRecords( testName );
  561. goto Done;
  562. }
  563. //
  564. // is name ".local" query
  565. //
  566. strcpy( testName, g_HostName );
  567. strcat( testName, "." );
  568. strcat( testName, MULTICAST_DNS_LOCAL_DOMAIN );
  569. if ( Dns_NameCompare_UTF8( pName, testName ) )
  570. {
  571. presultRecords = BuildLocalAddressRecords( testName );
  572. goto Done;
  573. }
  574. //
  575. // see if name matches any adapter name
  576. //
  577. for ( iter = 0; iter < ptempNetworkInfo->cAdapterCount; iter++ )
  578. {
  579. PIP_ARRAY pipArray = ptempNetworkInfo->AdapterArray[iter]->
  580. pAdapterIPAddresses;
  581. LPSTR pszDomain = ptempNetworkInfo->AdapterArray[iter]->
  582. pszAdapterDomain;
  583. if ( pszDomain )
  584. {
  585. strcpy( testName, g_HostName );
  586. strcat( testName, "." );
  587. strcat( testName, pszDomain );
  588. if ( pipArray &&
  589. Dns_NameCompare_UTF8( pName, testName ) )
  590. {
  591. PDNS_RECORD pPrev = NULL;
  592. for ( iter2 = 0; iter2 < pipArray->AddrCount; iter2++ )
  593. {
  594. PDNS_RECORD pNew = BuildARecord(
  595. testName,
  596. pipArray->AddrArray[iter2] );
  597. if ( pNew )
  598. {
  599. if ( pPrev )
  600. pPrev->pNext = pNew;
  601. else
  602. presultRecords = pNew;
  603. pPrev = pNew;
  604. }
  605. }
  606. }
  607. }
  608. }
  609. goto Done;
  610. }
  611. //
  612. // PTR query
  613. //
  614. else if ( Type == DNS_TYPE_PTR )
  615. {
  616. //
  617. // check for loopback
  618. // Dnslib uses this address to 'ping' adapters, must always respond
  619. //
  620. if ( Dns_NameCompare_UTF8( pName, "1.0.0.127.in-addr.arpa." ) )
  621. {
  622. presultRecords = BuildPTR(
  623. pName,
  624. g_HostName,
  625. NULL,
  626. pszPrimaryDomain );
  627. goto Done;
  628. }
  629. //
  630. // check all IPs on box (one adapter at a time)
  631. //
  632. for ( iter = 0; iter < ptempNetworkInfo->cAdapterCount; iter++ )
  633. {
  634. PIP_ARRAY pipArray = ptempNetworkInfo ->
  635. AdapterArray[iter] ->
  636. pAdapterIPAddresses;
  637. LPSTR pszDomain = ptempNetworkInfo ->
  638. AdapterArray[iter] ->
  639. pszAdapterDomain;
  640. if ( pipArray )
  641. {
  642. // check if query matches IP for this adapter
  643. //
  644. // ENHANCE: this is backwards; ought to covert query to IP
  645. // and then check IPs, rather than turning every IP into
  646. // reverse name; then could even use standard routines
  647. // to build PTR
  648. for ( iter2 = 0; iter2 < pipArray->AddrCount; iter2++ )
  649. {
  650. CHAR reverseName[DNS_MAX_REVERSE_NAME_BUFFER_LENGTH];
  651. IP4_ADDRESS ip = pipArray->AddrArray[iter2];
  652. Dns_Ip4AddressToReverseName_A(
  653. reverseName,
  654. ip );
  655. if ( Dns_NameCompare_UTF8( pName, reverseName ) )
  656. {
  657. presultRecords = BuildPTR(
  658. pName,
  659. g_HostName,
  660. pszDomain,
  661. pszPrimaryDomain );
  662. goto Done;
  663. }
  664. }
  665. }
  666. }
  667. }
  668. //
  669. // SRV query
  670. //
  671. else if ( Type == DNS_TYPE_SRV )
  672. {
  673. //
  674. // check if ".local" query
  675. //
  676. if ( Dns_NameCompare_UTF8( pName, MULTICAST_DNS_SRV_RECORD_NAME ) )
  677. {
  678. if ( g_AllowMulticastDnsSrvRecord &&
  679. ptempNetworkInfo->cAdapterCount &&
  680. ptempNetworkInfo->AdapterArray[0]->cServerCount )
  681. {
  682. presultRecords = BuildDNSServerRecord(
  683. ptempNetworkInfo->
  684. AdapterArray[0]->
  685. ServerArray[0].IpAddress );
  686. goto Done;
  687. }
  688. }
  689. }
  690. Done:
  691. // cleanup
  692. // return records
  693. // if found records TRUE; otherwise FALSE
  694. NetInfo_Free( ptempNetworkInfo );
  695. *ppRecord = presultRecords;
  696. return( presultRecords != NULL );
  697. }
  698. VOID
  699. FixupNameOwnerPointers(
  700. IN OUT PDNS_RECORD pRpcRecord
  701. )
  702. {
  703. PDNS_RECORD pTempRecord = pRpcRecord;
  704. LPWSTR lpNameOwner = pRpcRecord->pName;
  705. DNSDBG( TRACE, ( "FixupNameOwnerPointers()\n" ));
  706. while ( pTempRecord )
  707. {
  708. if ( pTempRecord->pName == NULL )
  709. pTempRecord->pName = lpNameOwner;
  710. else
  711. lpNameOwner = pTempRecord->pName;
  712. pTempRecord = pTempRecord->pNext;
  713. }
  714. }
  715. PDNS_RECORD
  716. BuildPTR(
  717. IN LPSTR pName,
  718. IN LPSTR pHostname,
  719. IN LPSTR pDomain,
  720. IN LPSTR pPrimaryDomain
  721. )
  722. {
  723. PDNS_RECORD prr1 = NULL;
  724. PDNS_RECORD prr2 = NULL;
  725. LPSTR pdata1 = NULL;
  726. LPSTR pdata2 = NULL;
  727. LPSTR pnameOwner = NULL;
  728. DWORD length;
  729. //
  730. // DCR_FIX: duplicates a lot of Dns_CreatePtrRecord
  731. //
  732. // DCR_FIX: build generic name-appending counter and
  733. // builder
  734. //
  735. // DCR_FIX0: records are not unicode is this ok?
  736. //
  737. prr1 = Dns_AllocateRecord( sizeof( DNS_PTR_DATA ) );
  738. if ( !prr1 )
  739. {
  740. return( NULL );
  741. }
  742. //
  743. // create owner name
  744. // create data name
  745. //
  746. pnameOwner = RECORD_HEAP_ALLOC( strlen(pName) + 1 );
  747. if ( !pnameOwner )
  748. {
  749. goto Failed;
  750. }
  751. strcpy( pnameOwner, pName );
  752. //
  753. // create PTR data
  754. //
  755. length = strlen( pHostname ) + 2;
  756. if ( pDomain )
  757. {
  758. length += strlen( pDomain ) + 2;
  759. }
  760. strcpy( pdata1, pHostname );
  761. strcat( pdata1, "." );
  762. if ( pDomain )
  763. {
  764. strcat( pdata1, pDomain );
  765. }
  766. //
  767. // create, fill-in record
  768. //
  769. pdata1 = RECORD_HEAP_ALLOC( length );
  770. if ( !pdata1 )
  771. {
  772. goto Failed;
  773. }
  774. prr1->pNext = NULL;
  775. prr1->pName = (PDNS_NAME) pnameOwner;
  776. prr1->wType = DNS_TYPE_PTR;
  777. prr1->Flags.S.Section = DNSREC_ANSWER;
  778. SET_FREE_DATA( prr1 );
  779. SET_FREE_OWNER( prr1 );
  780. prr1->dwTtl = g_MulticastRecordTTL;
  781. prr1->Data.Ptr.pNameHost = (PDNS_NAME) pdata1;
  782. //
  783. // build record for primary domain name
  784. // - if exists and different from domain name
  785. //
  786. if ( pPrimaryDomain &&
  787. ! Dns_NameCompare_UTF8( pDomain, pPrimaryDomain ) )
  788. {
  789. pdata2 = RECORD_HEAP_ALLOC(
  790. strlen( pHostname ) + strlen( pPrimaryDomain ) + 2 );
  791. if ( !pdata2 )
  792. {
  793. goto Failed;
  794. }
  795. strcpy( pdata2, pHostname );
  796. strcat( pdata2, "." );
  797. strcat( pdata2, pPrimaryDomain );
  798. prr2 = Dns_AllocateRecord( sizeof( DNS_PTR_DATA ) );
  799. if ( !prr2 )
  800. {
  801. goto Failed;
  802. }
  803. prr2->pNext = NULL;
  804. prr2->pName = (PDNS_NAME) pnameOwner;
  805. prr2->wType = DNS_TYPE_PTR;
  806. prr2->Flags.S.Section = DNSREC_ANSWER;
  807. SET_FREE_DATA( prr2 );
  808. prr2->dwTtl = g_MulticastRecordTTL;
  809. prr2->Data.Ptr.pNameHost = (PDNS_NAME) pdata2;
  810. }
  811. //
  812. // set next field
  813. // - appends record for primary name (if any)
  814. // - or sets pNext=NULL
  815. //
  816. prr1->pNext = prr2;
  817. return prr1;
  818. Failed:
  819. RECORD_HEAP_FREE( prr1 );
  820. RECORD_HEAP_FREE( pnameOwner );
  821. RECORD_HEAP_FREE( pdata1 );
  822. RECORD_HEAP_FREE( prr2 );
  823. RECORD_HEAP_FREE( pdata2 );
  824. return NULL;
  825. }
  826. PDNS_RECORD
  827. BuildARecord(
  828. IN LPSTR pName,
  829. IN IP_ADDRESS IpAddress
  830. )
  831. {
  832. PDNS_RECORD prr;
  833. LPSTR pnameOwner;
  834. prr = Dns_AllocateRecord( sizeof(DNS_A_DATA) );
  835. if ( !prr )
  836. {
  837. return NULL;
  838. }
  839. pnameOwner = RECORD_HEAP_ALLOC( strlen(pName) + 1 );
  840. if ( ! pnameOwner )
  841. {
  842. goto Failed;
  843. }
  844. strcpy( pnameOwner, pName );
  845. prr->pNext = NULL;
  846. prr->pName = (PDNS_NAME) pnameOwner;
  847. prr->wType = DNS_TYPE_A;
  848. prr->dwTtl = g_MulticastRecordTTL;
  849. prr->Flags.S.Section = DNSREC_ANSWER;
  850. SET_FREE_OWNER( prr );
  851. SET_FREE_DATA( prr );
  852. prr->Data.A.IpAddress = IpAddress;
  853. return prr;
  854. Failed:
  855. RECORD_HEAP_FREE( prr );
  856. return NULL;
  857. }
  858. PDNS_RECORD
  859. BuildDNSServerRecord(
  860. IN IP_ADDRESS IpAddress
  861. )
  862. {
  863. PDNS_RECORD prr = NULL;
  864. PDNS_RECORD prrAdditional = NULL;
  865. LPSTR pnameOwner = NULL;
  866. LPSTR pnameTarget = NULL;
  867. //
  868. // DCR_FIX: where to start? geez
  869. //
  870. // DCR_FIX: character set issue -- what's the paradigm here?
  871. //
  872. //
  873. // build additional record
  874. //
  875. prrAdditional = BuildARecord( MULTICAST_DNS_A_RECORD_NAME, IpAddress );
  876. if ( ! prrAdditional )
  877. {
  878. goto Failed;
  879. }
  880. prrAdditional->Flags.S.Section = DNSREC_ADDITIONAL;
  881. //
  882. // build SRV record
  883. //
  884. prr = Dns_AllocateRecord( sizeof( DNS_SRV_DATA ) );
  885. if ( !prr )
  886. {
  887. return( NULL );
  888. }
  889. pnameOwner = RECORD_HEAP_ALLOC( strlen(MULTICAST_DNS_SRV_RECORD_NAME) + 1 );
  890. if ( !pnameOwner )
  891. {
  892. goto Failed;
  893. }
  894. strcpy( pnameOwner, MULTICAST_DNS_SRV_RECORD_NAME );
  895. prr->pNext = prrAdditional;
  896. prr->pName = (PDNS_NAME) pnameOwner;
  897. prr->Flags.S.Section = DNSREC_ANSWER;
  898. SET_FREE_OWNER( prr );
  899. prr->wType = DNS_TYPE_SRV;
  900. prr->dwTtl = g_MulticastRecordTTL;
  901. prr->Data.SRV.pNameTarget = RECORD_HEAP_ALLOC(
  902. strlen( MULTICAST_DNS_A_RECORD_NAME ) + 1 );
  903. if ( ! pnameTarget )
  904. {
  905. goto Failed;
  906. }
  907. strcpy(
  908. pnameTarget,
  909. MULTICAST_DNS_A_RECORD_NAME );
  910. prr->Data.SRV.wPriority = 0;
  911. prr->Data.SRV.wWeight = 0;
  912. prr->Data.SRV.wPort = DNS_PORT_HOST_ORDER;
  913. prr->Data.SRV.pNameTarget = (PDNS_NAME) pnameTarget;
  914. SET_FREE_DATA( prr );
  915. return prr;
  916. Failed:
  917. // cleanup
  918. // - additional rr done wholesale
  919. // - SRV record done in pieces
  920. Dns_RecordFree( prrAdditional );
  921. RECORD_HEAP_FREE( pnameOwner );
  922. RECORD_HEAP_FREE( pnameTarget );
  923. RECORD_HEAP_FREE( prr );
  924. return NULL;
  925. }
  926. PDNS_RECORD
  927. BuildLocalAddressRecords(
  928. IN LPSTR Name )
  929. {
  930. return NULL;
  931. #if 0
  932. PDNS_RECORD pList = NULL;
  933. PDNS_RECORD pPrev = NULL;
  934. DWORD iter;
  935. EnterCriticalSection( &NetworkListCritSec );
  936. if ( g_IpAddressList &&
  937. g_IpAddressListCount )
  938. {
  939. for ( iter = 0; iter < g_IpAddressListCount; iter++ )
  940. {
  941. PDNS_RECORD pNew = BuildARecord( Name,
  942. g_IpAddressList[iter].ipAddress );
  943. if ( pNew )
  944. {
  945. if ( pPrev )
  946. pPrev->pNext = pNew;
  947. else
  948. pList = pNew;
  949. pPrev = pNew;
  950. }
  951. }
  952. }
  953. LeaveCriticalSection( &NetworkListCritSec );
  954. return pList;
  955. #endif
  956. }
  957. BOOL
  958. IsLocalAddress(
  959. IN IP_ADDRESS IpAddress
  960. )
  961. {
  962. return( FALSE );
  963. #if 0
  964. DWORD iter;
  965. BOOL bisLocal = FALSE;
  966. EnterCriticalSection( &NetworkListCritSec );
  967. if ( g_IpAddressList )
  968. {
  969. for ( iter = 0; iter < g_IpAddressListCount; iter++ )
  970. {
  971. if ( IpAddress == g_IpAddressList[iter].ipAddress )
  972. {
  973. bisLocal = TRUE;
  974. break;
  975. }
  976. }
  977. }
  978. LeaveCriticalSection( &NetworkListCritSec );
  979. return bisLocal;
  980. #endif
  981. }
  982. PSOCKET_CONTEXT
  983. AllocateIoContext(
  984. IN IP_ADDRESS IpAddr
  985. )
  986. {
  987. PSOCKET_CONTEXT pcontext;
  988. SOCKET socket = 0;
  989. // allocate and clear context
  990. pcontext = MCAST_HEAP_ALLOC_ZERO( sizeof(SOCKET_CONTEXT) );
  991. if ( !pcontext )
  992. {
  993. DNSLOG_F1( "Error: Failed to allocate multicast socket context." );
  994. return NULL;
  995. }
  996. // create multicast socket
  997. // - bound to this address and DNS port
  998. socket = Dns_CreateMulticastSocket(
  999. SOCK_DGRAM,
  1000. IpAddr,
  1001. DNS_PORT_NET_ORDER,
  1002. FALSE,
  1003. TRUE );
  1004. if ( socket == 0 || socket == INVALID_SOCKET )
  1005. {
  1006. DNSLOG_F1( "Error: Failed to create multicast socket." );
  1007. goto Failed;
  1008. }
  1009. // create message buffer for socket
  1010. pcontext->pMsg = Dns_AllocateMsgBuf( 0 );
  1011. if ( !pcontext->pMsg )
  1012. {
  1013. DNSLOG_F1( "Error: Failed to allocate message buffer." );
  1014. goto Failed;
  1015. }
  1016. pcontext->Socket = socket;
  1017. pcontext->IpAddress = IpAddr;
  1018. pcontext->pMsg->fTcp = FALSE;
  1019. return pcontext;
  1020. Failed:
  1021. if ( socket )
  1022. {
  1023. Dns_CloseSocket( socket );
  1024. }
  1025. MCAST_HEAP_FREE( pcontext );
  1026. return NULL;
  1027. }
  1028. VOID
  1029. FreeIoContextList(
  1030. IN OUT PSOCKET_CONTEXT pContext,
  1031. IN BOOL fIssueSocketShutdown
  1032. )
  1033. {
  1034. PSOCKET_CONTEXT ptempContext;
  1035. //
  1036. // cleanup context list
  1037. // - shutdown socket
  1038. // - close socket
  1039. // - free message buffer
  1040. // - free context
  1041. //
  1042. while ( pContext )
  1043. {
  1044. ptempContext = pContext;
  1045. pContext = pContext->pNext;
  1046. if ( fIssueSocketShutdown )
  1047. {
  1048. shutdown( ptempContext->Socket, SD_BOTH );
  1049. }
  1050. Dns_CloseSocket( ptempContext->Socket );
  1051. if ( ptempContext->pMsg )
  1052. {
  1053. Dns_Free( ptempContext->pMsg );
  1054. }
  1055. // QUESTION: should we tag memory free?
  1056. MCAST_HEAP_FREE( ptempContext );
  1057. }
  1058. }
  1059. VOID
  1060. DropReceive(
  1061. IN OUT PSOCKET_CONTEXT pContext
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. Drop down UDP receive request.
  1066. Arguments:
  1067. pContext -- context for socket being recieved
  1068. Return Value:
  1069. None
  1070. --*/
  1071. {
  1072. DNS_STATUS status;
  1073. WSABUF WsaBuf;
  1074. DWORD bytesRecvd;
  1075. DWORD dwFlags = 0;
  1076. if ( !pContext->pMsg )
  1077. {
  1078. return;
  1079. }
  1080. WsaBuf.len = DNS_MAX_UDP_PACKET_BUFFER_LENGTH;
  1081. WsaBuf.buf = (PCHAR) (&pContext->pMsg->MessageHead);
  1082. pContext->pMsg->Socket = pContext->Socket;
  1083. //
  1084. // loop until successful WSARecvFrom() is down
  1085. //
  1086. // this loop is only active while we continue to recv
  1087. // WSAECONNRESET or WSAEMSGSIZE errors, both of which
  1088. // cause us to dump data and retry;
  1089. //
  1090. // note loop rather than recursion (to this function) is
  1091. // required to aVOID possible stack overflow from malicious
  1092. // send
  1093. //
  1094. // normal returns from WSARecvFrom() are
  1095. // SUCCESS -- packet was waiting, GQCS will fire immediately
  1096. // WSA_IO_PENDING -- no data yet, GQCS will fire when ready
  1097. //
  1098. while ( 1 )
  1099. {
  1100. status = WSARecvFrom(
  1101. pContext->Socket,
  1102. & WsaBuf,
  1103. 1,
  1104. & bytesRecvd,
  1105. & dwFlags,
  1106. (PSOCKADDR) & pContext->pMsg->RemoteAddress,
  1107. & pContext->pMsg->RemoteAddressLength,
  1108. & pContext->Overlapped,
  1109. NULL );
  1110. if ( status == ERROR_SUCCESS )
  1111. {
  1112. return;
  1113. }
  1114. status = GetLastError();
  1115. if ( status == WSA_IO_PENDING )
  1116. {
  1117. return;
  1118. }
  1119. //
  1120. // when last send ICMP'd
  1121. // - set flag to indicate retry and repost send
  1122. // - if over some reasonable number of retries, assume error
  1123. // and fall through recv failure code
  1124. //
  1125. if ( status == WSAECONNRESET )
  1126. {
  1127. continue;
  1128. }
  1129. if ( status == WSAEMSGSIZE )
  1130. {
  1131. continue;
  1132. }
  1133. return;
  1134. }
  1135. }
  1136. //
  1137. // End mcast.c
  1138. //