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.

4266 lines
100 KiB

  1. /*++
  2. Copyright (c) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. send.c
  5. Abstract:
  6. Domain Name System (DNS) API
  7. Send response routines.
  8. Author:
  9. Jim Gilroy (jamesg) October, 1996
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. //
  14. // Disjoint name space
  15. //
  16. // If DNS name space is disjoint then NAME_ERROR response from one
  17. // adapter does NOT necessarily mean that name does not exist. Rather
  18. // must continue on other adapters.
  19. //
  20. // This flag should be set if name space is disjoint, off otherwise.
  21. //
  22. // DCR_PERF: auto-detect disjoint name space (really cool)
  23. // DCR_ENHANCE: auto-detect disjoint name space (really cool)
  24. // initially continue trying on other adapters and if they always
  25. // coincide, then conclude non-disjoint (and turn off)
  26. //
  27. // DCR_ENHANCE: registry turn off of disjoint name space
  28. //
  29. // Note: should consider that name spaces often disjoint in that
  30. // Intranet is hidden from Internet
  31. //
  32. BOOL fDisjointNameSpace = TRUE;
  33. //
  34. // Query \ response IP matching.
  35. //
  36. // Some resolvers (Win95) have required matching between DNS server IP
  37. // queried and response. This flag allows this matching to be turned on.
  38. // Better now than requiring SP later.
  39. //
  40. // DCR_ENHANCE: registry enable query\response IP matching.
  41. //
  42. BOOL fQueryIpMatching = FALSE;
  43. //
  44. // Timeouts
  45. //
  46. #define HARD_TIMEOUT_LIMIT 16 // 16 seconds, total of 31 seconds
  47. #define INITIAL_UPDATE_TIMEOUT 2 // 3 seconds
  48. #define MAX_UPDATE_TIMEOUT 24 // 24 seconds
  49. #define DNS_MAX_QUERY_TIMEOUTS 10 // 10
  50. #define ONE_HOUR_TIMEOUT 60*60 // One hour
  51. // TCP timeout 10 seconds to come back
  52. #define DEFAULT_TCP_TIMEOUT 10
  53. // Retry limits
  54. #define MAX_SINGLE_SERVER_RETRY (3)
  55. #define NT_TCPIP_REG_LOCATION "System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
  56. #define WIN95_TCPIP_REG_LOCATION "System\\CurrentControlSet\\Services\\VxD\\MSTCP"
  57. #define DNS_QUERY_TIMEOUTS "DnsQueryTimeouts"
  58. #define DNS_QUICK_QUERY_TIMEOUTS "DnsQuickQueryTimeouts"
  59. #define DNS_MULTICAST_QUERY_TIMEOUTS "DnsMulticastQueryTimeouts"
  60. //
  61. // Timeouts
  62. // MUST have terminating 0, this signals end of timeouts.
  63. // This is better than a timeout limit as different query types can
  64. // have different total retries.
  65. //
  66. DWORD QueryTimeouts[] =
  67. {
  68. 1, // NT5 1,
  69. 1, // 2,
  70. 2, // 2,
  71. 4, // 4,
  72. 7, // 8,
  73. 0
  74. };
  75. DWORD RegistryQueryTimeouts[DNS_MAX_QUERY_TIMEOUTS + 1];
  76. LPDWORD g_QueryTimeouts = QueryTimeouts;
  77. DWORD QuickQueryTimeouts[] =
  78. {
  79. 1,
  80. 2,
  81. 2,
  82. 0
  83. };
  84. DWORD RegistryQuickQueryTimeouts[DNS_MAX_QUERY_TIMEOUTS + 1];
  85. LPDWORD g_QuickQueryTimeouts = QuickQueryTimeouts;
  86. //
  87. // Update timeouts.
  88. // Must be long enough to handle zone lock on primary for XFR
  89. // or time required for DS write.
  90. //
  91. DWORD UpdateTimeouts[] =
  92. {
  93. 5,
  94. 10,
  95. 20,
  96. 0
  97. };
  98. //
  99. // Multicast Query timeouts.
  100. // Local only. 1sec timeout, three retries.
  101. //
  102. DWORD MulticastQueryTimeouts[] =
  103. {
  104. 1,
  105. 1,
  106. 1,
  107. 0
  108. };
  109. DWORD RegistryMulticastQueryTimeouts[DNS_MAX_QUERY_TIMEOUTS + 1];
  110. LPDWORD g_MulticastQueryTimeouts = MulticastQueryTimeouts;
  111. //
  112. // Failure priority boosts
  113. //
  114. #define TIMEOUT_PRIORITY_DROP (10)
  115. #define SERVER_FAILURE_PRIORITY_DROP (1)
  116. #define NO_DNS_PRIORITY_DROP (200)
  117. //
  118. // Query flag
  119. //
  120. // Flags that terminate query on adapter
  121. #define RUN_FLAG_COMBINED_IGNORE_ADAPTER \
  122. (RUN_FLAG_IGNORE_ADAPTER | RUN_FLAG_STOP_QUERY_ON_ADAPTER)
  123. //
  124. // Return flags
  125. //
  126. // Flags that are not cleaned up
  127. #define DNS_FLAGS_NOT_RESET (DNS_FLAG_IGNORE_ADAPTER)
  128. //
  129. // Authoritative empty response
  130. // - map to NXRRSET for tracking in send code
  131. //
  132. #define DNS_RCODE_AUTH_EMPTY_RESPONSE (DNS_RCODE_NXRRSET)
  133. //
  134. // Dummy no-send-to-this-server error code
  135. //
  136. #define DNS_ERROR_NO_SEND ((DWORD)(-100))
  137. //
  138. // ServerInfo address type check
  139. // Current server info address setup (a mistake) is
  140. // IP4_ADDRESS IpAddress
  141. // DWORD Reserved[3]
  142. // Check that reserved DWORDs are zero is check that have
  143. // IP4 address
  144. //
  145. #if 0
  146. //
  147. // This test is not working on IA64 -- not sure why
  148. //
  149. // For quickie BVT fix we'll just rule out IA64 sends
  150. //
  151. IP6_ADDRESS g_Ip6EmptyAddress = { 0, 0, 0, 0 };
  152. DWORD g_Empty[4] = { 0, 0, 0, 0 };
  153. #define IS_SERVER_INFO_ADDRESS_IP4( pIp ) \
  154. RtlEqualMemory( \
  155. (PDWORD)(pIp)+1, \
  156. g_Empty, \
  157. sizeof(DWORD) * 3 )
  158. #endif
  159. #define IS_SERVER_INFO_ADDRESS_IP4( pIp ) TRUE
  160. //
  161. // OPT failure tracking
  162. //
  163. BOOL
  164. Dns_IsServerOptExclude(
  165. IN IP4_ADDRESS IpAddress
  166. );
  167. VOID
  168. Dns_SetServerOptExclude(
  169. IN IP4_ADDRESS IpAddress
  170. );
  171. //
  172. // Private protos
  173. //
  174. DNS_STATUS
  175. SendMessagePrivate(
  176. IN OUT PDNS_MSG_BUF pMsg,
  177. IN PCHAR pSendIp,
  178. IN BOOL fIp4,
  179. IN BOOL fNoOpt
  180. );
  181. VOID
  182. TimeoutDnsServers(
  183. IN PDNS_NETINFO pNetInfo,
  184. IN DWORD dwTimeout
  185. )
  186. /*++
  187. Routine Description:
  188. Mark a DNS server that timed out.
  189. Arguments:
  190. pNetInfo -- struct with list of DNS servers
  191. dwTimeout -- timeout in seconds
  192. Return Value:
  193. None.
  194. --*/
  195. {
  196. PDNS_ADAPTER padapter;
  197. PDNS_SERVER_INFO pserver;
  198. DWORD lastSendIndex;
  199. DWORD i;
  200. DNSDBG( SEND, (
  201. "Enter TimeoutDnsServers( %p, timeout=%d )\n",
  202. pNetInfo,
  203. dwTimeout ));
  204. DNS_ASSERT( pNetInfo );
  205. //
  206. // find DNS server in list,
  207. // -- drop its priority based on timeout
  208. // -- if already has RCODE, then did not time out
  209. //
  210. // if change a priority, then set flag at top of adapter list, so
  211. // that global copy may be updated
  212. //
  213. for( i=0; i<pNetInfo->AdapterCount; i++ )
  214. {
  215. padapter = pNetInfo->AdapterArray[i];
  216. DNS_ASSERT( padapter );
  217. lastSendIndex = padapter->ServerIndex;
  218. if ( lastSendIndex == EMPTY_SERVER_INDEX ||
  219. lastSendIndex >= padapter->ServerCount )
  220. {
  221. continue;
  222. }
  223. //
  224. // found last send DNS server
  225. // - if it responded with status, then it didn't timeout
  226. // (if responded with success, then query completed and
  227. // we wouldn't be in this function)
  228. //
  229. // - go "easy" on OPT sends;
  230. // don't drop priority, just note timeout
  231. //
  232. pserver = &padapter->ServerArray[lastSendIndex];
  233. if ( TEST_DNSSS_STATUS(pserver->Status, DNSSS_SENT) )
  234. {
  235. DNSDBG( SEND, (
  236. "Timeout on server index=%d (padapter=%p)\n",
  237. lastSendIndex,
  238. padapter ));
  239. if ( TEST_DNSSS_STATUS(pserver->Status, DNSSS_SENT_NON_OPT) )
  240. {
  241. SET_SERVER_STATUS( pserver, DNSSS_TIMEOUT_NON_OPT );
  242. pserver->Priority += dwTimeout + TIMEOUT_PRIORITY_DROP;
  243. padapter->RunFlags |= RUN_FLAG_RESET_SERVER_PRIORITY;
  244. pNetInfo->ReturnFlags |= RUN_FLAG_RESET_SERVER_PRIORITY;
  245. }
  246. else
  247. {
  248. DNSDBG( SEND, (
  249. "Timeout on server index=%d OPT only\n",
  250. lastSendIndex ));
  251. SET_SERVER_STATUS( pserver, DNSSS_TIMEOUT_OPT );
  252. }
  253. }
  254. }
  255. }
  256. VOID
  257. resetOnFinalTimeout(
  258. IN PDNS_NETINFO pNetInfo
  259. )
  260. /*++
  261. Routine Description:
  262. Markup network info on final timeout.
  263. Arguments:
  264. pNetInfo -- struct with list of DNS servers
  265. dwTimeout -- timeout in seconds
  266. Return Value:
  267. None.
  268. --*/
  269. {
  270. DWORD i;
  271. PDNS_ADAPTER padapter;
  272. //
  273. // We've timed out against all DNS server for a least
  274. // one of the adapters. Update adapter status to show
  275. // time out error.
  276. //
  277. // DCR: is final timeout correct
  278. // - worried about timeout on some but not all servers
  279. // case; adapter shouldn't show timeout should it?
  280. //
  281. for ( i = 0; i < pNetInfo->AdapterCount; i++ )
  282. {
  283. padapter = pNetInfo->AdapterArray[i];
  284. if ( padapter->Status == NO_ERROR &&
  285. padapter->ServerIndex &&
  286. padapter->RunFlags & RUN_FLAG_RESET_SERVER_PRIORITY )
  287. {
  288. padapter->Status = ERROR_TIMEOUT;
  289. }
  290. }
  291. }
  292. DNS_STATUS
  293. ResetDnsServerPriority(
  294. IN PDNS_NETINFO pNetInfo,
  295. IN IP4_ADDRESS IpDns,
  296. //IN IP6_ADDRESS IpDns,
  297. //IN PIP6_ADDRESS pIpDns,
  298. IN DNS_STATUS Status
  299. )
  300. /*++
  301. Routine Description:
  302. Reset priority on DNS server that sent response.
  303. // DCR: needs IP6 entry
  304. Arguments:
  305. pNetInfo -- struct with list of DNS servers
  306. IpDns -- IP address of DNS that responded
  307. Status -- RCODE of response
  308. Return Value:
  309. ERROR_SUCCESS if continue query.
  310. DNS_ERROR_RCODE_NAME_ERROR if all (valid) adapters have name-error or auth-empty response.
  311. --*/
  312. {
  313. PDNS_ADAPTER padapter;
  314. PDNS_SERVER_INFO pserver;
  315. DWORD i;
  316. DWORD j;
  317. DNS_STATUS result = DNS_ERROR_RCODE_NAME_ERROR;
  318. #if DBG
  319. BOOL freset = FALSE;
  320. #endif
  321. DNSDBG( SEND, (
  322. "Enter ResetDnsServerPriority( %p, %s rcode=%d)\n",
  323. pNetInfo,
  324. IP_STRING(IpDns),
  325. Status ));
  326. DNS_ASSERT( pNetInfo );
  327. //
  328. // find DNS server in list, clear its priority field
  329. //
  330. // note: going through full list here after found DNS
  331. // this is to avoid starving DNS by failing to clear priority field;
  332. // if have guaranteed non-overlapping lists, then can terminate
  333. // loop on find
  334. //
  335. for( i=0; i<pNetInfo->AdapterCount; i++ )
  336. {
  337. padapter = pNetInfo->AdapterArray[i];
  338. for ( j=0; j<padapter->ServerCount; j++ )
  339. {
  340. pserver = & padapter->ServerArray[j];
  341. if ( IpDns != pserver->IpAddress )
  342. //if ( IpDns != *(PIP6_ADDRESS)&pserver->IpAddress )
  343. {
  344. continue;
  345. }
  346. pserver->Status = Status;
  347. #if DBG
  348. freset = TRUE;
  349. #endif
  350. //
  351. // no DNS running
  352. //
  353. // WSAECONNRESET reported for reception of ICMP unreachable, so
  354. // no DNS is currently running on the IP; that's a severe
  355. // priority drop, worse than just TIMEOUT
  356. //
  357. if ( Status == WSAECONNRESET )
  358. {
  359. pserver->Priority += NO_DNS_PRIORITY_DROP;
  360. padapter->RunFlags |= RUN_FLAG_RESET_SERVER_PRIORITY;
  361. pNetInfo->ReturnFlags |= RUN_FLAG_RESET_SERVER_PRIORITY;
  362. break;
  363. }
  364. // if SERVER_FAILURE rcode, may or may not indicate problem,
  365. // (may be simply unable to contact remote DNS)
  366. // but it certainly suggests trying other DNS servers in
  367. // the list first
  368. //
  369. // DCR_FIX: SEVRFAIL response priority reset
  370. // the explicitly correct approach would be to flag the
  371. // SERVER_FAILURE error, but NOT reset the priority unless
  372. // at the end of the query, we find another server in the list
  373. // got a useful response
  374. if ( Status == DNS_ERROR_RCODE_SERVER_FAILURE )
  375. {
  376. pserver->Priority += SERVER_FAILURE_PRIORITY_DROP;
  377. padapter->RunFlags |= RUN_FLAG_RESET_SERVER_PRIORITY;
  378. pNetInfo->ReturnFlags |= RUN_FLAG_RESET_SERVER_PRIORITY;
  379. break;
  380. }
  381. //
  382. // other status code indicates functioning DNS server,
  383. // - reset the server's priority
  384. if ( pserver->Priority )
  385. {
  386. pserver->Priority = 0;
  387. padapter->RunFlags |= RUN_FLAG_RESET_SERVER_PRIORITY;
  388. pNetInfo->ReturnFlags |= RUN_FLAG_RESET_SERVER_PRIORITY;
  389. }
  390. //
  391. // NAME_ERROR or AUTH-EMPTY response
  392. // - save to server list for adapter to eliminate all
  393. // further retries on this adapter's list
  394. // - if not waiting for all adapters, then
  395. // NAME_ERROR or no-records is terminal
  396. if ( Status == DNS_ERROR_RCODE_NAME_ERROR ||
  397. Status == DNS_INFO_NO_RECORDS )
  398. {
  399. padapter->Status = Status;
  400. padapter->RunFlags |= RUN_FLAG_STOP_QUERY_ON_ADAPTER;
  401. if ( !g_WaitForNameErrorOnAll )
  402. {
  403. result = DNS_ERROR_RCODE_NAME_ERROR;
  404. goto Done;
  405. }
  406. }
  407. break;
  408. }
  409. //
  410. // do running check that still adapter worth querying
  411. // - not ignoring in first place
  412. // - hasn't received NAME_ERROR or AUTH_EMPTY response
  413. //
  414. // this is "at recv" check -- only trying to determine if we
  415. // should stop query RIGHT NOW as a result of this receive;
  416. // this does NOT check on whether there are any other servers
  417. // worth querying as that is done when go back for next send
  418. //
  419. // note how this works -- result starts as NAME_ERROR, when find
  420. // ANY adapter that hasn't gotten terminal response, then
  421. // result shifts (and stays) at ERROR_SUCCESS
  422. //
  423. // note, if we fix the twice through list issue above, then have to
  424. // change this so don't skip adapter lists after IP is found
  425. //
  426. if ( !(padapter->RunFlags & RUN_FLAG_COMBINED_IGNORE_ADAPTER) )
  427. {
  428. result = ERROR_SUCCESS;
  429. }
  430. }
  431. Done:
  432. #if DBG
  433. if ( !freset )
  434. {
  435. DNSDBG( ANY, (
  436. "ERROR: DNS server %s not in list.\n", IP_STRING(IpDns) ));
  437. DNS_ASSERT( FALSE );
  438. }
  439. #endif
  440. return( result );
  441. }
  442. PDNS_SERVER_INFO
  443. bestDnsServerForNextSend(
  444. IN PDNS_ADAPTER pAdapter
  445. )
  446. /*++
  447. Routine Description:
  448. Get best DNS server IP address from list.
  449. Arguments:
  450. pAdapter -- struct with list of DNS servers
  451. Return Value:
  452. Ptr to server info of best send.
  453. NULL if no server on adapter is worth sending to; this is
  454. the case if all servers have received a response.
  455. --*/
  456. {
  457. PDNS_SERVER_INFO pserver;
  458. DWORD i;
  459. DWORD status;
  460. DWORD priority;
  461. DWORD priorityBest = MAXDWORD;
  462. PDNS_SERVER_INFO pbestServer = NULL;
  463. DWORD bestIndex = EMPTY_SERVER_INDEX;
  464. DNSDBG( SEND, (
  465. "Enter bestDnsServerForNextSend( %p )\n",
  466. pAdapter ));
  467. if ( !pAdapter || !pAdapter->ServerCount )
  468. {
  469. DNSDBG( SEND, (
  470. "WARNING: Leaving bestDnsServerForNextSend, no server list\n" ));
  471. return( NULL );
  472. }
  473. //
  474. // if already received name error on server in this list, done
  475. //
  476. if ( pAdapter->Status == DNS_ERROR_RCODE_NAME_ERROR ||
  477. pAdapter->Status == DNS_INFO_NO_RECORDS )
  478. {
  479. DNSDBG( SEND, (
  480. "Leaving bestDnsServerForNextSend, NAME_ERROR already received\n"
  481. "\ton server in server list %p\n",
  482. pAdapter ));
  483. return( NULL );
  484. }
  485. //
  486. // check each server in list
  487. //
  488. for ( i=0; i<pAdapter->ServerCount; i++ )
  489. {
  490. pserver = & pAdapter->ServerArray[i];
  491. // if server has already recieved a response, then skip it
  492. status = pserver->Status;
  493. if ( TEST_DNSSS_VALID_RECV(status) )
  494. {
  495. // NAME_ERROR or EMPTY_AUTH then adapter should have been
  496. // marked as "done" and we shouldn't be here
  497. // NO_ERROR should have exited immediately
  498. DNS_ASSERT( status != NO_ERROR &&
  499. status != DNS_ERROR_RCODE_NAME_ERROR &&
  500. status != DNS_INFO_NO_RECORDS );
  501. continue;
  502. }
  503. // return first "clean" server
  504. // or return one with lowest dings
  505. //
  506. // DCR: skip NO_DNS server for a while
  507. // skip timeout server for a little while
  508. // perhaps this should be done be ignoring these
  509. // when list is sent down?
  510. priority = pserver->Priority;
  511. if ( priority < priorityBest )
  512. {
  513. bestIndex = i;
  514. pbestServer = pserver;
  515. if ( priority == 0 )
  516. {
  517. break;
  518. }
  519. }
  520. }
  521. // save off IP of server we are using
  522. if ( pbestServer )
  523. {
  524. pAdapter->ServerIndex = bestIndex;
  525. }
  526. return( pbestServer );
  527. }
  528. DNS_STATUS
  529. SendUsingServerInfo(
  530. IN OUT PDNS_MSG_BUF pMsg,
  531. IN OUT PDNS_SERVER_INFO pServInfo
  532. )
  533. /*++
  534. Routine Description:
  535. Send DNS message using server info.
  536. This function encapsulates the process of checking
  537. server info for validity, sending (as appropriate)
  538. and marking servinfo result.
  539. Note: right now this is UDP only; may need to expand
  540. Arguments:
  541. pMsg - message info for message to send
  542. pServInfo - info of server to send to
  543. Return Value:
  544. ERROR_SUCCESS if successful.
  545. ErrorCode on send failure.
  546. --*/
  547. {
  548. DNS_STATUS status;
  549. BOOL fnoOpt;
  550. BOOL fip4;
  551. IP4_ADDRESS ip4;
  552. DNSDBG( SEND, (
  553. "SendUsingServerInfo( msg=%p, servinfo=%p )\n",
  554. pMsg ));
  555. //
  556. // check that haven't already completed send\recv
  557. //
  558. if ( TEST_DNSSS_VALID_RECV( pServInfo->Status ) )
  559. {
  560. return DNS_ERROR_NO_SEND;
  561. }
  562. //
  563. // check OPT status
  564. // - previous OPT send that timed OUT, then send non-OPT
  565. //
  566. // DCR: known OPT-ok list could screen wasted send
  567. fnoOpt = TEST_DNSSS_STATUS( pServInfo->Status, DNSSS_SENT_OPT );
  568. //
  569. // send
  570. //
  571. status = SendMessagePrivate(
  572. pMsg,
  573. (PCHAR) &pServInfo->IpAddress,
  574. IS_SERVER_INFO_ADDRESS_IP4( &pServInfo->IpAddress ),
  575. fnoOpt );
  576. if ( status == ERROR_SUCCESS )
  577. {
  578. DNS_ASSERT( !fnoOpt || !pMsg->fLastSendOpt );
  579. SET_SERVER_STATUS(
  580. pServInfo,
  581. pMsg->fLastSendOpt
  582. ? DNSSS_SENT_OPT
  583. : DNSSS_SENT_NON_OPT);
  584. }
  585. return status;
  586. }
  587. DNS_STATUS
  588. SendUdpToNextDnsServers(
  589. IN OUT PDNS_MSG_BUF pMsgSend,
  590. IN OUT PDNS_NETINFO pNetInfo,
  591. IN DWORD cRetryCount,
  592. IN DWORD dwTimeout,
  593. OUT PDWORD pSendCount
  594. )
  595. /*++
  596. Routine Description:
  597. Sends to next DNS servers in list.
  598. Arguments:
  599. pMsgSend -- message to send
  600. pNetInfo -- per adapter DNS info
  601. cRetryCount -- retry for this send
  602. dwTimeout -- timeout on last send, if timed out
  603. pSendCount -- addr to receive send count
  604. Return Value:
  605. ERROR_SUCCESS if successful send.
  606. ERROR_TIMEOUT if no DNS servers left to send to.
  607. Winsock error code on send failure.
  608. --*/
  609. {
  610. DWORD i;
  611. DWORD j;
  612. DWORD sendCount = 0;
  613. PDNS_ADAPTER padapter;
  614. PDNS_SERVER_INFO pserver;
  615. DNS_STATUS status = ERROR_TIMEOUT;
  616. DNSDBG( SEND, (
  617. "Enter SendUdpToNextDnsServers()\n"
  618. "\tretry = %d\n",
  619. cRetryCount ));
  620. //
  621. // if netinfo not initialized for send, init
  622. //
  623. if ( !(pNetInfo->ReturnFlags & RUN_FLAG_NETINFO_PREPARED) )
  624. {
  625. DNSDBG( SEND, ( "Netinfo not prepared for send -- preparing now.\n" ));
  626. NetInfo_Clean(
  627. pNetInfo,
  628. CLEAR_LEVEL_QUERY );
  629. }
  630. #if DBG
  631. //
  632. // verify i'm getting a clean list on start
  633. //
  634. if ( cRetryCount == 0 )
  635. {
  636. for( i=0; i<pNetInfo->AdapterCount; i++ )
  637. {
  638. padapter = pNetInfo->AdapterArray[i];
  639. // ignore this adapter because there are no DNS
  640. // servers configured?
  641. if ( padapter->InfoFlags & DNS_FLAG_IGNORE_ADAPTER )
  642. {
  643. continue;
  644. }
  645. DNS_ASSERT( padapter->ServerIndex == EMPTY_SERVER_INDEX );
  646. DNS_ASSERT( padapter->Status == 0 );
  647. for ( j=0; j<padapter->ServerCount; j++ )
  648. {
  649. DNS_ASSERT( padapter->ServerArray[j].Status == DNSSS_NEW );
  650. }
  651. }
  652. }
  653. #endif
  654. //
  655. // if previous send timed out, update adapter list
  656. // - but ONLY do this when sending to individual servers in list
  657. // - timeout on all servers just produces an unnecessary copy and
  658. // can only change ordering relative to servers which have already
  659. // responded with RCODE; since its a timeout, this isn't going to
  660. // lower these server's priority so no point
  661. //
  662. if ( dwTimeout && cRetryCount && cRetryCount < MAX_SINGLE_SERVER_RETRY )
  663. {
  664. TimeoutDnsServers( pNetInfo, dwTimeout );
  665. }
  666. //
  667. // send on DNS server(s) for adapter(s)
  668. //
  669. for( i=0; i<pNetInfo->AdapterCount; i++ )
  670. {
  671. padapter = pNetInfo->AdapterArray[i];
  672. // ignore this adapter
  673. // - no DNS servers
  674. // - not querying this adapter name
  675. // - already responded to this name
  676. if ( ( padapter->InfoFlags & DNS_FLAG_IGNORE_ADAPTER ) ||
  677. ( padapter->RunFlags & RUN_FLAG_STOP_QUERY_ON_ADAPTER ) )
  678. {
  679. continue;
  680. }
  681. //
  682. // first three attempts, we only go to one DNS on a given adapter
  683. //
  684. // - first time through ONLY to first server in first adapter list
  685. // - on subsequent tries go to best server in all lists
  686. //
  687. if ( cRetryCount < MAX_SINGLE_SERVER_RETRY )
  688. {
  689. pserver = bestDnsServerForNextSend( padapter );
  690. if ( !pserver )
  691. {
  692. continue;
  693. }
  694. status = SendUsingServerInfo(
  695. pMsgSend,
  696. pserver );
  697. if ( status == ERROR_SUCCESS )
  698. {
  699. sendCount++;
  700. if ( cRetryCount == 0 )
  701. {
  702. break;
  703. }
  704. continue;
  705. }
  706. if ( status == DNS_ERROR_NO_SEND )
  707. {
  708. continue;
  709. }
  710. // quit on send error
  711. break;
  712. }
  713. //
  714. // after first three tries, send to all servers that
  715. // have not already responded (have RCODE, as if NO_ERROR) we
  716. // already finished
  717. //
  718. else
  719. {
  720. for ( j=0; j<padapter->ServerCount; j++ )
  721. {
  722. status = SendUsingServerInfo(
  723. pMsgSend,
  724. &padapter->ServerArray[j] );
  725. if ( status == ERROR_SUCCESS )
  726. {
  727. sendCount++;
  728. continue;
  729. }
  730. if ( status == DNS_ERROR_NO_SEND )
  731. {
  732. continue;
  733. }
  734. break;
  735. }
  736. }
  737. }
  738. //
  739. // if sent packet, success
  740. //
  741. *pSendCount = sendCount;
  742. DNSDBG( SEND, (
  743. "Leave SendUdpToNextDnsServers()\n"
  744. "\tsends = %d\n",
  745. sendCount ));
  746. if ( sendCount )
  747. {
  748. return( ERROR_SUCCESS );
  749. }
  750. // if no packets sent, alert caller we're done
  751. // - this is possible if servers have responded uselessly
  752. // (NAME_ERROR, SERVER_FAILURE)
  753. if ( status == ERROR_SUCCESS )
  754. {
  755. status = ERROR_TIMEOUT;
  756. }
  757. return( status );
  758. }
  759. //
  760. // Send routines
  761. //
  762. VOID
  763. SetMsgRemoteSockaddr(
  764. IN OUT PDNS_MSG_BUF pMsg,
  765. IN PIP6_ADDRESS pIpAddr,
  766. IN BOOL fIp4
  767. )
  768. /*++
  769. Routine Description:
  770. Initialize remote sockaddr.
  771. Note: this handles IP4 or IP6
  772. This could be changed to simply test for IP4_MAPPED
  773. and simply pass address pointer.
  774. Arguments:
  775. pMsg - message to send
  776. fIp4 - TRUE if IP4
  777. pIp6Addr - IP address to send
  778. Return Value:
  779. None.
  780. --*/
  781. {
  782. // zero
  783. RtlZeroMemory(
  784. & pMsg->RemoteAddress,
  785. sizeof( pMsg->RemoteAddress ) );
  786. //
  787. // fill in for IP4 or IP6
  788. //
  789. // DCR: just pass in IP6_ADDRESS
  790. // then test for V4 mapped
  791. // if ( IN6_IS_ADDR_V4MAPPED(IpAddress) )
  792. //
  793. if ( fIp4 )
  794. {
  795. pMsg->RemoteAddress.In4.sin_family = AF_INET;
  796. pMsg->RemoteAddress.In4.sin_port = DNS_PORT_NET_ORDER;
  797. pMsg->RemoteAddress.In4.sin_addr.s_addr = *(PIP4_ADDRESS) pIpAddr;
  798. pMsg->RemoteAddressLength = sizeof(SOCKADDR_IN);
  799. }
  800. else
  801. {
  802. pMsg->RemoteAddress.In6.sin6_family = AF_INET6;
  803. pMsg->RemoteAddress.In6.sin6_port = DNS_PORT_NET_ORDER;
  804. RtlCopyMemory(
  805. (PIP6_ADDRESS) &pMsg->RemoteAddress.In6.sin6_addr,
  806. pIpAddr,
  807. sizeof(IP6_ADDRESS) );
  808. pMsg->RemoteAddressLength = sizeof(SOCKADDR_IN6);
  809. }
  810. }
  811. VOID
  812. Dns_InitializeMsgRemoteSockaddr(
  813. IN OUT PDNS_MSG_BUF pMsg,
  814. IN IP4_ADDRESS IpAddr
  815. )
  816. /*++
  817. Routine Description:
  818. Initialize remote sockaddr.
  819. Note: EXPORTED function
  820. // DCR: EXPORTED may remove when clean
  821. Arguments:
  822. pMsg - message to send
  823. IpAddr - IP4 address to send to
  824. Return Value:
  825. None.
  826. --*/
  827. {
  828. IP4_ADDRESS ip4 = IpAddr;
  829. SetMsgRemoteSockaddr(
  830. pMsg,
  831. (PIP6_ADDRESS) &ip4,
  832. TRUE // IP4
  833. );
  834. }
  835. DNS_STATUS
  836. SendMessagePrivate(
  837. IN OUT PDNS_MSG_BUF pMsg,
  838. IN PCHAR pSendIp,
  839. IN BOOL fIp4,
  840. IN BOOL fNoOpt
  841. )
  842. /*++
  843. Routine Description:
  844. Send a DNS packet.
  845. This is the generic send routine used for ANY send of a DNS message.
  846. It assumes nothing about the message type, but does assume:
  847. - pCurrent points at byte following end of desired data
  848. - RR count bytes are in HOST byte order
  849. Arguments:
  850. pMsg - message info for message to send
  851. pSendIp - ptr to IP address to send to
  852. OPTIONAL, required only if UDP and message sockaddr not set
  853. fIp4 -- TRUE if IP4, FALSE for IP6
  854. fNoOpt - TRUE if OPT send is forbidden
  855. Return Value:
  856. TRUE if successful.
  857. FALSE on send error.
  858. --*/
  859. {
  860. PDNS_HEADER pmsgHead;
  861. INT err;
  862. WORD sendLength;
  863. BOOL fexcludedOpt = FALSE;
  864. DNSDBG( SEND, (
  865. "SendMessagePrivate()\n"
  866. "\tpMsg = %p\n"
  867. "\tpSendIp = %p\n"
  868. "\tIs IP4 = %d\n"
  869. "\tNo OPT = %d\n",
  870. pMsg,
  871. pSendIp,
  872. fIp4,
  873. fNoOpt ));
  874. //
  875. // set header flags
  876. //
  877. // note: since route sends both queries and responses
  878. // caller must set these flags
  879. //
  880. pmsgHead = &pMsg->MessageHead;
  881. pmsgHead->Reserved = 0;
  882. //
  883. // set send IP (if given)
  884. //
  885. if ( pSendIp )
  886. {
  887. SetMsgRemoteSockaddr(
  888. pMsg,
  889. (PIP6_ADDRESS) pSendIp,
  890. fIp4 );
  891. }
  892. //
  893. // set message length and OPT inclusion
  894. //
  895. // OPT approach is
  896. // - write to pCurrent packet end
  897. // - handles NO OPT written and using OPT
  898. // - unless HAVE written OPT, and specifically excluding
  899. // note, that zero IP (TCP previously connected) gets
  900. // excluded
  901. //
  902. // DCR: we haven't handled OPT for TCP connected and not-aware of IP
  903. // case here
  904. //
  905. // DCR: for now excluding OPT on updates, because harder to detect on
  906. // the recv end why the reason for the failure
  907. //
  908. {
  909. PCHAR pend = pMsg->pCurrent;
  910. if ( pMsg->pPreOptEnd
  911. &&
  912. ( fNoOpt
  913. ||
  914. g_UseEdns == 0
  915. ||
  916. pMsg->MessageHead.Opcode == DNS_OPCODE_UPDATE
  917. ||
  918. Dns_IsServerOptExclude( MSG_REMOTE_IP4(pMsg) ) ) )
  919. {
  920. ASSERT( pMsg->pPreOptEnd > (PCHAR)pmsgHead );
  921. ASSERT( pMsg->pPreOptEnd < pend );
  922. pend = pMsg->pPreOptEnd;
  923. pmsgHead->AdditionalCount--;
  924. fexcludedOpt = TRUE;
  925. }
  926. sendLength = (WORD)(pend - (PCHAR)pmsgHead);
  927. pMsg->fLastSendOpt = (pMsg->pPreOptEnd && (pend != pMsg->pPreOptEnd));
  928. }
  929. IF_DNSDBG( SEND )
  930. {
  931. pMsg->MessageLength = sendLength;
  932. DnsDbg_Message(
  933. "Sending packet",
  934. pMsg );
  935. }
  936. //
  937. // flip header count bytes
  938. //
  939. DNS_BYTE_FLIP_HEADER_COUNTS( pmsgHead );
  940. //
  941. // TCP -- send until all info transmitted
  942. //
  943. if ( pMsg->fTcp )
  944. {
  945. PCHAR psend;
  946. //
  947. // TCP message always begins with bytes being sent
  948. //
  949. // - send length = message length plus two byte size
  950. // - flip bytes in message length
  951. // - send starting at message length
  952. //
  953. pMsg->MessageLength = htons( sendLength );
  954. sendLength += sizeof(WORD);
  955. psend = (PCHAR) &pMsg->MessageLength;
  956. while ( sendLength )
  957. {
  958. err = send(
  959. pMsg->Socket,
  960. psend,
  961. (INT) sendLength,
  962. 0 );
  963. if ( err == 0 || err == SOCKET_ERROR )
  964. {
  965. err = GetLastError();
  966. //
  967. // WSAESHUTDOWN is ok, client got timed out connection and
  968. // closed
  969. //
  970. // WSAENOTSOCK may also occur if FIN recv'd and connection
  971. // closed by TCP receive thread before the send
  972. //
  973. if ( err == WSAESHUTDOWN )
  974. {
  975. IF_DNSDBG( ANY )
  976. {
  977. DNS_PRINT((
  978. "WARNING: send() failed on shutdown socket %d.\n"
  979. "\tpMsgInfo at %p\n",
  980. pMsg->Socket,
  981. pMsg ));
  982. }
  983. }
  984. else if ( err == WSAENOTSOCK )
  985. {
  986. IF_DNSDBG( ANY )
  987. {
  988. DNS_PRINT((
  989. "ERROR: send() on closed socket %d.\n"
  990. "\tpMsgInfo at %p\n",
  991. pMsg->Socket,
  992. pMsg ));
  993. }
  994. }
  995. else
  996. {
  997. DNS_LOG_EVENT(
  998. DNS_EVENT_SEND_CALL_FAILED,
  999. 0,
  1000. NULL,
  1001. err );
  1002. IF_DNSDBG( ANY )
  1003. {
  1004. DNS_PRINT(( "ERROR: TCP send() failed, err = %d.\n" ));
  1005. }
  1006. }
  1007. goto Done;
  1008. }
  1009. sendLength -= (WORD)err;
  1010. psend += err;
  1011. }
  1012. }
  1013. //
  1014. // UDP
  1015. //
  1016. else
  1017. {
  1018. DNS_ASSERT( sendLength <= DNS_RFC_MAX_UDP_PACKET_LENGTH );
  1019. err = sendto(
  1020. pMsg->Socket,
  1021. (PCHAR) pmsgHead,
  1022. sendLength,
  1023. 0,
  1024. (PSOCKADDR) &pMsg->RemoteAddress,
  1025. pMsg->RemoteAddressLength
  1026. );
  1027. if ( err == SOCKET_ERROR )
  1028. {
  1029. err = GetLastError();
  1030. DNS_LOG_EVENT(
  1031. DNS_EVENT_SENDTO_CALL_FAILED,
  1032. 0,
  1033. NULL,
  1034. err );
  1035. IF_DNSDBG( ANY )
  1036. {
  1037. DNS_PRINT(( "ERROR: UDP sendto() failed.\n" ));
  1038. DnsDbg_SockaddrIn(
  1039. "sendto() failed sockaddr\n",
  1040. (PSOCKADDR_IN) &pMsg->RemoteAddress,
  1041. pMsg->RemoteAddressLength );
  1042. DnsDbg_Message(
  1043. "sendto() failed message",
  1044. pMsg );
  1045. }
  1046. goto Done;
  1047. }
  1048. }
  1049. err = ERROR_SUCCESS;
  1050. Done:
  1051. DNS_BYTE_FLIP_HEADER_COUNTS( pmsgHead );
  1052. // restore OPT in count if required
  1053. if ( fexcludedOpt )
  1054. {
  1055. pmsgHead->AdditionalCount++;
  1056. }
  1057. Trace_LogSendEvent( pMsg, err );
  1058. return( (DNS_STATUS)err );
  1059. }
  1060. DNS_STATUS
  1061. Dns_SendEx(
  1062. IN OUT PDNS_MSG_BUF pMsg,
  1063. IN IP4_ADDRESS SendIp, OPTIONAL
  1064. IN BOOL fNoOpt
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. Send a DNS packet.
  1069. This is the generic send routine used for ANY send of a DNS message.
  1070. It assumes nothing about the message type, but does assume:
  1071. - pCurrent points at byte following end of desired data
  1072. - RR count bytes are in HOST byte order
  1073. Note: EXPORTED function
  1074. DCR: Remove Dns_SendEx() from export when ICS fixed
  1075. Arguments:
  1076. pMsg - message info for message to send
  1077. SendIp - IP to send to; OPTIONAL, required only if UDP
  1078. and message sockaddr not set
  1079. fNoOpt - TRUE if OPT send is forbidden
  1080. Return Value:
  1081. TRUE if successful.
  1082. FALSE on send error.
  1083. --*/
  1084. {
  1085. IP4_ADDRESS ip4 = SendIp;
  1086. return SendMessagePrivate(
  1087. pMsg,
  1088. (PCHAR) &ip4,
  1089. TRUE, // sending IP4
  1090. fNoOpt
  1091. );
  1092. }
  1093. //
  1094. // UDP routines
  1095. //
  1096. VOID
  1097. Dns_SendMultipleUdp(
  1098. IN OUT PDNS_MSG_BUF pMsg,
  1099. IN PIP_ARRAY aipSendAddrs
  1100. )
  1101. /*++
  1102. Routine Description:
  1103. Send a DNS packet to multiple destinations.
  1104. Assumes packet is in same state as normal send
  1105. - host order count and XID
  1106. - pCurrent pointing at byte after desired data
  1107. Arguments:
  1108. pMsg - message info for message to send and reuse
  1109. aipSendAddrs - IP array of addrs to send to
  1110. Return Value:
  1111. None.
  1112. --*/
  1113. {
  1114. DWORD i;
  1115. //
  1116. // no targets
  1117. //
  1118. if ( !aipSendAddrs )
  1119. {
  1120. return;
  1121. }
  1122. //
  1123. // send the to each address specified in IP array
  1124. //
  1125. for ( i=0; i < aipSendAddrs->AddrCount; i++ )
  1126. {
  1127. SendMessagePrivate(
  1128. pMsg,
  1129. (PCHAR) &aipSendAddrs->AddrArray[i],
  1130. TRUE, // IP4
  1131. 0 );
  1132. }
  1133. }
  1134. DNS_STATUS
  1135. Dns_RecvUdp(
  1136. IN OUT PDNS_MSG_BUF pMsg
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. Receives DNS message
  1141. Arguments:
  1142. pMsg - message buffer for recv
  1143. Return Value:
  1144. ERROR_SUCCESS if successful.
  1145. Error status on failure.
  1146. --*/
  1147. {
  1148. SOCKET s;
  1149. PDNS_HEADER pdnsHeader;
  1150. LONG err = ERROR_SUCCESS;
  1151. struct timeval selectTimeout;
  1152. struct fd_set fdset;
  1153. DNSDBG( RECV, (
  1154. "Enter Dns_RecvUdp( %p )\n",
  1155. pMsg ));
  1156. DNS_ASSERT( !pMsg->fTcp );
  1157. //
  1158. // verify socket
  1159. //
  1160. s = pMsg->Socket;
  1161. if ( s == 0 || s == INVALID_SOCKET )
  1162. {
  1163. return( ERROR_INVALID_PARAMETER );
  1164. }
  1165. FD_ZERO( &fdset );
  1166. FD_SET( s, &fdset );
  1167. if ( pMsg->Timeout > HARD_TIMEOUT_LIMIT &&
  1168. pMsg->Timeout != ONE_HOUR_TIMEOUT )
  1169. {
  1170. DNSDBG( RECV, (
  1171. "ERROR: timeout %d, exceeded hard limit.\n",
  1172. pMsg->Timeout ));
  1173. return( ERROR_TIMEOUT );
  1174. }
  1175. selectTimeout.tv_usec = 0;
  1176. selectTimeout.tv_sec = pMsg->Timeout;
  1177. pdnsHeader = &pMsg->MessageHead;
  1178. //
  1179. // wait for stack to indicate packet reception
  1180. //
  1181. err = select( 0, &fdset, NULL, NULL, &selectTimeout );
  1182. if ( err <= 0 )
  1183. {
  1184. if ( err < 0 )
  1185. {
  1186. // select error
  1187. err = WSAGetLastError();
  1188. DNS_PRINT(( "ERROR: select() error = %d\n", err ));
  1189. return( err );
  1190. }
  1191. else
  1192. {
  1193. DNS_PRINT(( "ERROR: timeout on response %p\n", pMsg ));
  1194. return( ERROR_TIMEOUT );
  1195. }
  1196. }
  1197. //
  1198. // receive
  1199. //
  1200. err = recvfrom(
  1201. s,
  1202. (PCHAR) pdnsHeader,
  1203. DNS_MAX_UDP_PACKET_BUFFER_LENGTH,
  1204. 0,
  1205. (PSOCKADDR) &pMsg->RemoteAddress,
  1206. &pMsg->RemoteAddressLength );
  1207. if ( err == SOCKET_ERROR )
  1208. {
  1209. err = GetLastError();
  1210. Trace_LogRecvEvent(
  1211. pMsg,
  1212. err,
  1213. FALSE // UDP
  1214. );
  1215. if ( err == WSAECONNRESET )
  1216. {
  1217. //DNS_ASSERT( MSG_REMOTE_IP4(pMsg) != 0 );
  1218. DNSDBG( RECV, (
  1219. "Leave Dns_RecvUdp( %p ) with CONNRESET\n",
  1220. pMsg ));
  1221. return( err );
  1222. }
  1223. // message sent was too big
  1224. // sender was in error -- should have sent TCP
  1225. if ( err == WSAEMSGSIZE )
  1226. {
  1227. pMsg->MessageLength = DNS_MAX_UDP_PACKET_BUFFER_LENGTH;
  1228. DnsDbg_Message(
  1229. "ERROR: Recv UDP packet over 512 bytes.\n",
  1230. pMsg );
  1231. }
  1232. IF_DNSDBG( ANY )
  1233. {
  1234. DnsDbg_Lock();
  1235. DNS_PRINT((
  1236. "ERROR: recvfrom(sock=%d) of UDP request failed.\n"
  1237. "\tGetLastError() = 0x%08lx.\n",
  1238. socket,
  1239. err ));
  1240. DnsDbg_SockaddrIn(
  1241. "recvfrom failed sockaddr\n",
  1242. &pMsg->RemoteAddress,
  1243. pMsg->RemoteAddressLength );
  1244. DnsDbg_Unlock();
  1245. }
  1246. return( err );
  1247. }
  1248. else
  1249. {
  1250. //DNS_ASSERT( MSG_REMOTE_IP4(pMsg) != 0 );
  1251. DNS_ASSERT( err <= DNS_MAX_UDP_PACKET_BUFFER_LENGTH );
  1252. pMsg->MessageLength = (WORD)err;
  1253. err = ERROR_SUCCESS;
  1254. }
  1255. //
  1256. // put header fields in host order
  1257. //
  1258. DNS_BYTE_FLIP_HEADER_COUNTS( &pMsg->MessageHead );
  1259. //pMsg->fSwapped = FALSE;
  1260. Trace_LogRecvEvent(
  1261. pMsg,
  1262. 0,
  1263. FALSE // UDP
  1264. );
  1265. IF_DNSDBG( RECV )
  1266. {
  1267. DnsDbg_Message(
  1268. "Received message",
  1269. pMsg );
  1270. }
  1271. return( err );
  1272. }
  1273. DNS_STATUS
  1274. Dns_SendAndRecvUdp(
  1275. IN OUT PDNS_MSG_BUF pMsgSend,
  1276. OUT PDNS_MSG_BUF pMsgRecv,
  1277. IN DWORD dwFlags,
  1278. IN PIP_ARRAY aipServers,
  1279. IN OUT PDNS_NETINFO pNetInfo
  1280. )
  1281. /*++
  1282. Routine Description:
  1283. Sends to and waits to recv from remote DNS.
  1284. Arguments:
  1285. pMsgSend - message to send
  1286. ppMsgRecv - and reuse
  1287. dwFlags -- query flags
  1288. aipServers - servers to use; if no adapter info is specified this
  1289. list is used
  1290. pNetInfo -- adapter list DNS server info
  1291. Return Value:
  1292. ERROR_SUCCESS if successful response.
  1293. Error status for "best RCODE" response if rcode.
  1294. ERROR_TIMEOUT on timeout.
  1295. Error status on send\recv failure.
  1296. --*/
  1297. {
  1298. SOCKET s;
  1299. INT fcreatedSocket = FALSE;
  1300. INT retry;
  1301. DWORD timeout;
  1302. DNS_STATUS status = ERROR_TIMEOUT;
  1303. //IP6_ADDRESS recvIp = 0;
  1304. //PIP6_ADDRESS recvIp = 0;
  1305. IP4_ADDRESS recvIp = 0;
  1306. DWORD rcode = 0;
  1307. DWORD ignoredRcode = 0;
  1308. DWORD sendCount;
  1309. DWORD sentCount;
  1310. DWORD sendTime;
  1311. BOOL frecvRetry;
  1312. BOOL fupdate = FALSE; // prefix
  1313. PDNS_NETINFO ptempNetInfo = NULL;
  1314. DNSDBG( SEND, (
  1315. "Enter Dns_SendAndRecvUdp()\n"
  1316. "\ttime %d\n"
  1317. "\tsend msg at %p\n"
  1318. "\tsocket %d\n"
  1319. "\trecv msg at %p\n"
  1320. "\tflags %08x\n"
  1321. "\tserver IP arrap %p\n"
  1322. "\tadapter info at %p\n",
  1323. Dns_GetCurrentTimeInSeconds(),
  1324. pMsgSend,
  1325. pMsgSend->Socket,
  1326. pMsgRecv,
  1327. dwFlags,
  1328. aipServers,
  1329. pNetInfo ));
  1330. // verify params
  1331. if ( !pMsgSend || !pMsgRecv || (!pNetInfo && !aipServers) )
  1332. {
  1333. return( ERROR_INVALID_PARAMETER );
  1334. }
  1335. //
  1336. // server IP array? if given build temp adapter info
  1337. //
  1338. if ( aipServers )
  1339. {
  1340. ptempNetInfo = NetInfo_CreateFromIpArray(
  1341. aipServers,
  1342. 0, // no single IP
  1343. FALSE, // no search info
  1344. NULL );
  1345. if ( !ptempNetInfo )
  1346. {
  1347. return( DNS_ERROR_NO_MEMORY );
  1348. }
  1349. pNetInfo = ptempNetInfo;
  1350. }
  1351. // create socket if necessary
  1352. s = pMsgSend->Socket;
  1353. if ( s == 0 || s == INVALID_SOCKET )
  1354. {
  1355. s = Dns_GetUdpSocket();
  1356. if ( s == INVALID_SOCKET )
  1357. {
  1358. status = GetLastError();
  1359. goto Done;
  1360. }
  1361. pMsgSend->Socket = s;
  1362. pMsgSend->fTcp = FALSE;
  1363. fcreatedSocket = TRUE;
  1364. }
  1365. // if already have TCP socket -- invalid
  1366. //
  1367. // problem is we either leak TCP socket, or we close
  1368. // it here and may screw things up at higher level
  1369. else if ( pMsgSend->fTcp )
  1370. {
  1371. status = ERROR_INVALID_PARAMETER;
  1372. goto Done;
  1373. }
  1374. pMsgRecv->Socket = s;
  1375. pMsgRecv->fTcp = FALSE;
  1376. // determine UPDATE or standard QUERY
  1377. fupdate = ( pMsgSend->MessageHead.Opcode == DNS_OPCODE_UPDATE );
  1378. //
  1379. // loop sending until
  1380. // - receive successful response
  1381. // or
  1382. // - receive errors response from all servers
  1383. // or
  1384. // - reach final timeout on all servers
  1385. //
  1386. //
  1387. // DCR: should support setting of timeouts on individual queries
  1388. //
  1389. retry = 0;
  1390. sendCount = 0;
  1391. while ( 1 )
  1392. {
  1393. if ( fupdate )
  1394. {
  1395. timeout = UpdateTimeouts[retry];
  1396. }
  1397. else
  1398. {
  1399. if ( dwFlags & DNS_QUERY_USE_QUICK_TIMEOUTS )
  1400. {
  1401. timeout = g_QuickQueryTimeouts[retry];
  1402. }
  1403. else
  1404. {
  1405. timeout = g_QueryTimeouts[retry];
  1406. }
  1407. }
  1408. //
  1409. // zero timeout indicates end of retries for this query type
  1410. //
  1411. if ( timeout == 0 )
  1412. {
  1413. // save timeout for adapter?
  1414. //
  1415. // if multiple adapters and some timed out and some
  1416. // didn't then saving timeout is relevant
  1417. //
  1418. // DCR: this doesn't make much sense
  1419. // the actual test i moved inside the function
  1420. if ( pNetInfo &&
  1421. pNetInfo->AdapterCount > 1 &&
  1422. ignoredRcode &&
  1423. status == ERROR_TIMEOUT )
  1424. {
  1425. resetOnFinalTimeout( pNetInfo );
  1426. }
  1427. break;
  1428. }
  1429. //
  1430. // send to best DNS servers in adapter list
  1431. // - servers sent to varies according to retry
  1432. // - send in previous timeout, if some servers did not respond
  1433. //
  1434. status = SendUdpToNextDnsServers(
  1435. pMsgSend,
  1436. pNetInfo,
  1437. retry,
  1438. sendCount ? pMsgRecv->Timeout : 0,
  1439. & sendCount );
  1440. sentCount = sendCount;
  1441. if ( status != ERROR_SUCCESS )
  1442. {
  1443. // if no more servers to send to, done
  1444. DNSDBG( RECV, (
  1445. "No more DNS servers to send message %p\n"
  1446. "\tprevious RCODE = %d\n",
  1447. pMsgSend,
  1448. ignoredRcode ));
  1449. goto ErrorReturn;
  1450. }
  1451. retry++;
  1452. recvIp = 0;
  1453. rcode = DNS_RCODE_NO_ERROR;
  1454. pMsgRecv->Timeout = timeout;
  1455. DNS_ASSERT( sendCount != 0 );
  1456. frecvRetry = FALSE;
  1457. sendTime = GetCurrentTimeInSeconds();
  1458. //
  1459. // receive response
  1460. //
  1461. // note: the loop is strictly to allow us to drop back into
  1462. // receive if one server is misbehaving;
  1463. // in that case we go back into the receive without resending
  1464. // to allow other servers to respond
  1465. //
  1466. while ( sendCount )
  1467. {
  1468. //
  1469. // if have to retry recv, adjust down timeout
  1470. // - note, one second granularity is handled by
  1471. // rounding up at zero so we wait 0-1s beyond official
  1472. // timeout value
  1473. //
  1474. // DCR: calculate timeouts in ms?
  1475. //
  1476. if ( frecvRetry )
  1477. {
  1478. DWORD timeLeft;
  1479. timeLeft = timeout + sendTime - GetCurrentTimeInSeconds();
  1480. if ( (LONG)timeLeft < 0 )
  1481. {
  1482. status = ERROR_TIMEOUT;
  1483. break;
  1484. }
  1485. else if ( timeLeft == 0 )
  1486. {
  1487. timeLeft = 1;
  1488. }
  1489. pMsgRecv->Timeout = timeLeft;
  1490. }
  1491. frecvRetry = TRUE;
  1492. status = Dns_RecvUdp( pMsgRecv );
  1493. recvIp = MSG_REMOTE_IP4(pMsgRecv);
  1494. // recv wait completed
  1495. // - if timeout, commence next retry
  1496. // - if CONNRESET
  1497. // - indicate NO server on IP
  1498. // - back to recv if more DNS servers outstanding,
  1499. // - if success, verify packet
  1500. if ( status != ERROR_SUCCESS )
  1501. {
  1502. if ( status == ERROR_TIMEOUT )
  1503. {
  1504. break;
  1505. }
  1506. if ( status == WSAECONNRESET )
  1507. {
  1508. ResetDnsServerPriority(
  1509. pNetInfo,
  1510. recvIp,
  1511. status );
  1512. #if 0
  1513. // old deal when didn't know about IP back in sockaddr
  1514. if ( sendCount == 1 )
  1515. {
  1516. pMsgRecv->Timeout = NO_DNS_PRIORITY_DROP;
  1517. status = ERROR_TIMEOUT;
  1518. break;
  1519. }
  1520. #endif
  1521. sendCount--;
  1522. continue;
  1523. }
  1524. }
  1525. DNS_ASSERT( recvIp != 0 );
  1526. // check XID match
  1527. if ( pMsgRecv->MessageHead.Xid != pMsgSend->MessageHead.Xid )
  1528. {
  1529. DNS_PRINT(( "WARNING: Incorrect XID in response. Ignoring.\n" ));
  1530. continue;
  1531. }
  1532. // check DNS server IP match
  1533. // this may or may NOT be desired
  1534. if ( fQueryIpMatching &&
  1535. sentCount == 1 &&
  1536. MSG_REMOTE_IP4(pMsgSend) != recvIp )
  1537. {
  1538. DNS_PRINT((
  1539. "WARNING: Ignoring response from %08x to query %p\n"
  1540. "\tIP does not match queried IP %08x\n",
  1541. recvIp,
  1542. pMsgSend,
  1543. MSG_REMOTE_IP4(pMsgSend)
  1544. ));
  1545. continue;
  1546. }
  1547. // valid receive, drop outstanding send count
  1548. sendCount--;
  1549. //
  1550. // check question match
  1551. // - this is "Maggs Bug" check
  1552. // - ASSERT here just to investigate issue locally
  1553. // and make sure check is not bogus
  1554. // - specifically doing after sendCount decrement
  1555. // as this server will NOT send us a valid response
  1556. // - some servers don't reply with question so ignore
  1557. // if QuestionCount == 0
  1558. //
  1559. if ( pMsgRecv->MessageHead.QuestionCount != 0
  1560. &&
  1561. !Dns_IsSamePacketQuestion(
  1562. pMsgRecv,
  1563. pMsgSend ))
  1564. {
  1565. DNS_PRINT((
  1566. "ERROR: Bad question response from server %08x!\n"
  1567. "\tXID match, but question does not match question sent!\n",
  1568. recvIp ));
  1569. DNS_ASSERT( FALSE );
  1570. continue;
  1571. }
  1572. // suck out RCODE
  1573. rcode = pMsgRecv->MessageHead.ResponseCode;
  1574. //
  1575. // good response?
  1576. //
  1577. // special case AUTH-EMPTY and delegations
  1578. //
  1579. // - AUTH-EMPTY gets similar treatment to name error
  1580. // (this adapter can be considered to be finished)
  1581. //
  1582. // - referrals can be treated like SERVER_FAILURE
  1583. // (avoid this server for rest of query; server may
  1584. // be fine for direct lookup, so don't drop priority)
  1585. //
  1586. //
  1587. // DCR_CLEANUP: functionalize packet-categorization
  1588. // this would be standard errors
  1589. // plus AUTH-EMPTY versus referral
  1590. // plus OPT issues, etc
  1591. // could be called from TCP side also
  1592. //
  1593. // then would have separate determination about whether
  1594. // packet was terminal (below)
  1595. //
  1596. if ( rcode == DNS_RCODE_NO_ERROR )
  1597. {
  1598. if ( pMsgRecv->MessageHead.AnswerCount != 0 || fupdate )
  1599. {
  1600. goto GoodRecv;
  1601. }
  1602. //
  1603. // auth-empty
  1604. // - authoritative
  1605. // - or from cache, recursive response (hence not delegation)
  1606. //
  1607. // note: using dummy RCODE here as "ignored RCODE" serves
  1608. // the role of "best saved status" and roughly
  1609. // prioritizes in the way we want
  1610. //
  1611. // DCR: could change to "best saved status" as mapping is
  1612. // pretty much the same; would explicitly have to
  1613. // check
  1614. if ( pMsgRecv->MessageHead.Authoritative == 1 ||
  1615. ( pMsgRecv->MessageHead.RecursionAvailable == 1 &&
  1616. pMsgRecv->MessageHead.RecursionDesired ) )
  1617. {
  1618. DNSDBG( RECV, (
  1619. "Recv AUTH-EMPTY response from %s\n",
  1620. IP_STRING(recvIp) ));
  1621. rcode = DNS_RCODE_AUTH_EMPTY_RESPONSE;
  1622. status = DNS_INFO_NO_RECORDS;
  1623. }
  1624. // referral
  1625. else if ( pMsgRecv->MessageHead.RecursionAvailable == 0 )
  1626. {
  1627. DNSDBG( RECV, (
  1628. "Recv referral response from %s\n",
  1629. IP_STRING(recvIp) ));
  1630. rcode = DNS_RCODE_SERVER_FAILURE;
  1631. status = DNS_ERROR_REFERRAL_RESPONSE;
  1632. }
  1633. // bogus (bad packet) response
  1634. else
  1635. {
  1636. rcode = DNS_RCODE_SERVER_FAILURE;
  1637. status = DNS_ERROR_BAD_PACKET;
  1638. }
  1639. }
  1640. else
  1641. {
  1642. status = Dns_MapRcodeToStatus( (UCHAR)rcode );
  1643. }
  1644. //
  1645. // OPT failure screening
  1646. //
  1647. // DCR: FORMERR overload on OPT for update
  1648. // unless we read result to see if OPT, no way
  1649. // to determine if this is update problem or
  1650. // OPT problem
  1651. //
  1652. // - note, that checking if in list doesn't work because
  1653. // of MT issue (another query adds setting)
  1654. //
  1655. // - could be fixed by setting flag in network info
  1656. //
  1657. if ( rcode == DNS_RCODE_FORMAT_ERROR &&
  1658. !fupdate )
  1659. {
  1660. Dns_SetServerOptExclude( recvIp );
  1661. // redo send but explicitly force OPT excluse
  1662. Dns_SendEx(
  1663. pMsgSend,
  1664. recvIp,
  1665. TRUE // exclude OPT
  1666. );
  1667. sendCount++;
  1668. continue;
  1669. }
  1670. //
  1671. // error RCODE do NOT terminate query
  1672. // - SERVER_FAILUREs
  1673. // - malfunctioning server
  1674. // - disjoint nets \ DNS namespace issues
  1675. //
  1676. // RCODE error removes particular server from further consideration
  1677. // during THIS query
  1678. //
  1679. // generally the higher RCODEs are more interesting
  1680. // NAME_ERROR > SERVER_FAILURE
  1681. // and
  1682. // update RCODEs > NAME_ERROR
  1683. // save the highest as return when no ERROR_SUCCESS response
  1684. //
  1685. // however for query NAME_ERROR is the highest RCODE,
  1686. // IF it is received on all adapters (if not REFUSED on one
  1687. // adapter may indicate that there really is a name)
  1688. //
  1689. // for UPDATE, REFUSED and higher are terminal RCODEs.
  1690. // downlevel servers (non-UPDATE-aware) servers would give
  1691. // FORMERR or NOTIMPL, so these are either valid responses or
  1692. // the zone has a completely busted server which must be detected
  1693. // and removed
  1694. //
  1695. //
  1696. // DCR_CLEANUP: functionalize packet-termination
  1697. // essentially is this type of packet terminal for
  1698. // this query;
  1699. // could be called from TCP side also
  1700. //
  1701. if ( rcode > ignoredRcode )
  1702. {
  1703. ignoredRcode = rcode;
  1704. }
  1705. //
  1706. // reset server priority for good recv
  1707. // - return ERROR_SUCCESS unless all adapters
  1708. // are
  1709. //
  1710. status = ResetDnsServerPriority(
  1711. pNetInfo,
  1712. recvIp,
  1713. status );
  1714. //
  1715. // if all adapters are done (NAME_ERROR or NO_RECORDS)
  1716. // - return NAME_ERROR\NO_RECORDS rcode
  1717. // NO_RECORDS highest priority
  1718. // then NAME_ERROR
  1719. // then anything else
  1720. if ( status == DNS_ERROR_RCODE_NAME_ERROR )
  1721. {
  1722. if ( !fupdate && ignoredRcode != DNS_RCODE_AUTH_EMPTY_RESPONSE )
  1723. {
  1724. ignoredRcode = DNS_RCODE_NAME_ERROR;
  1725. }
  1726. goto ErrorReturn;
  1727. }
  1728. //
  1729. // update RCODEs are terminal
  1730. //
  1731. if ( fupdate && rcode >= DNS_RCODE_REFUSED )
  1732. {
  1733. goto ErrorReturn;
  1734. }
  1735. // continue wait for any other outstanding servers
  1736. }
  1737. DNSDBG( RECV, (
  1738. "Failed retry = %d for message %p\n"
  1739. "\tstatus = %d\n"
  1740. "\ttimeout = %d\n"
  1741. "\tservers out = %d\n"
  1742. "\tlast rcode = %d\n"
  1743. "\tignored RCODE = %d\n\n",
  1744. (retry - 1),
  1745. pMsgSend,
  1746. status,
  1747. timeout,
  1748. sendCount,
  1749. rcode,
  1750. ignoredRcode ));
  1751. continue;
  1752. } // end loop sending/recving packets
  1753. //
  1754. // falls here on retry exhausted
  1755. //
  1756. // note that any ignored RCODE takes precendence over failing
  1757. // status (which may be winsock error, timeout, or bogus
  1758. // NAME_ERROR from resetServerPriorities())
  1759. //
  1760. ErrorReturn:
  1761. // this can also hit on winsock error in DnsSend()
  1762. //
  1763. //DNS_ASSERT( ignoredRcode || status == ERROR_TIMEOUT );
  1764. //
  1765. // error responses from all servers or timeouts
  1766. //
  1767. DNSDBG( RECV, (
  1768. "Error or timeouts from all servers for message %p\n"
  1769. "\treturning RCODE = %d\n",
  1770. pMsgSend,
  1771. ignoredRcode ));
  1772. if ( ignoredRcode )
  1773. {
  1774. // empty-auth reponse is tracked with bogus RCODE,
  1775. // switch to status code -- DNS_INFO_NO_RECORDS
  1776. if ( !fupdate && ignoredRcode == DNS_RCODE_AUTH_EMPTY_RESPONSE )
  1777. {
  1778. status = DNS_INFO_NO_RECORDS;
  1779. }
  1780. else
  1781. {
  1782. status = Dns_MapRcodeToStatus( (UCHAR)ignoredRcode );
  1783. }
  1784. }
  1785. goto Done;
  1786. GoodRecv:
  1787. ResetDnsServerPriority(
  1788. pNetInfo,
  1789. recvIp,
  1790. rcode );
  1791. DNSDBG( RECV, (
  1792. "Recv'd response for query at %p from DNS %s\n",
  1793. pMsgSend,
  1794. IP_STRING(recvIp) ));
  1795. Done:
  1796. //
  1797. // if created socket -- close it
  1798. //
  1799. // DCR_ENHANCE: allow for possibility of keeping socket alive
  1800. //
  1801. if ( fcreatedSocket )
  1802. {
  1803. DNSDBG( SEND, (
  1804. "Closing socket %d after recv.\n", s ));
  1805. Dns_ReturnUdpSocket( s );
  1806. pMsgSend->Socket = 0;
  1807. pMsgRecv->Socket = 0;
  1808. }
  1809. IF_DNSDBG( RECV )
  1810. {
  1811. DNSDBG( SEND, (
  1812. "Leave Dns_SendAndRecvUdp()\n"
  1813. "\tstatus = %d\n"
  1814. "\ttime = %d\n"
  1815. "\tsend msg = %p\n"
  1816. "\trecv msg = %p\n",
  1817. status,
  1818. Dns_GetCurrentTimeInSeconds(),
  1819. pMsgSend,
  1820. pMsgRecv ));
  1821. DnsDbg_NetworkInfo(
  1822. "Network info after UDP recv\n",
  1823. pNetInfo );
  1824. }
  1825. // if allocated adapter list free it
  1826. if ( ptempNetInfo )
  1827. {
  1828. NetInfo_Free( ptempNetInfo );
  1829. }
  1830. // should not return NXRRSET except on update
  1831. ASSERT( fupdate || status != DNS_ERROR_RCODE_NXRRSET );
  1832. return( status );
  1833. }
  1834. DNS_STATUS
  1835. Dns_SendAndRecvMulticast(
  1836. IN OUT PDNS_MSG_BUF pMsgSend,
  1837. OUT PDNS_MSG_BUF pMsgRecv,
  1838. IN OUT PDNS_NETINFO pNetInfo OPTIONAL
  1839. )
  1840. /*++
  1841. Routine Description:
  1842. Sends to and waits to recv from remote DNS.
  1843. Arguments:
  1844. pMsgSend - message to send
  1845. ppMsgRecv - and reuse
  1846. pNetInfo -- adapter list DNS server info
  1847. DCR - pNetInfo parameter could be leveraged to
  1848. identify specific networks to target a multicast
  1849. query against. For example, there could be a multihomed
  1850. machine that is configured to only multicast on one
  1851. of many adapters, thus filtering out useless mDNS packets.
  1852. Return Value:
  1853. ERROR_SUCCESS if successful response.
  1854. NAME_ERROR on timeout.
  1855. Error status on send\recv failure.
  1856. --*/
  1857. {
  1858. SOCKET s;
  1859. INT fcreatedSocket = FALSE;
  1860. INT retry;
  1861. DWORD timeout;
  1862. DNS_STATUS status = ERROR_TIMEOUT;
  1863. IP_ADDRESS recvIp = 0;
  1864. DWORD rcode = 0;
  1865. DWORD ignoredRcode = 0;
  1866. DNSDBG( SEND, (
  1867. "Enter Dns_SendAndRecvMulticast()\n"
  1868. "\tsend msg at %p\n"
  1869. "\tsocket %d\n"
  1870. "\trecv msg at %p\n",
  1871. pMsgSend,
  1872. pMsgSend->Socket,
  1873. pMsgRecv ));
  1874. // verify params
  1875. if ( !pMsgSend || !pMsgRecv )
  1876. {
  1877. return( ERROR_INVALID_PARAMETER );
  1878. }
  1879. if ( pMsgSend->MessageHead.Opcode == DNS_OPCODE_UPDATE )
  1880. {
  1881. return( ERROR_INVALID_PARAMETER );
  1882. }
  1883. // create socket if necessary
  1884. s = pMsgSend->Socket;
  1885. if ( s == 0 || s == INVALID_SOCKET )
  1886. {
  1887. s = Dns_CreateSocket(
  1888. SOCK_DGRAM,
  1889. INADDR_ANY,
  1890. 0 );
  1891. if ( s == INVALID_SOCKET )
  1892. {
  1893. status = GetLastError();
  1894. goto Done;
  1895. }
  1896. pMsgSend->Socket = s;
  1897. pMsgSend->fTcp = FALSE;
  1898. fcreatedSocket = TRUE;
  1899. }
  1900. // if already have TCP socket -- invalid
  1901. //
  1902. // problem is we either leak TCP socket, or we close
  1903. // it here and may screw things up at higher level
  1904. else if ( pMsgSend->fTcp )
  1905. {
  1906. status = ERROR_INVALID_PARAMETER;
  1907. goto Done;
  1908. }
  1909. pMsgRecv->Socket = s;
  1910. pMsgRecv->fTcp = FALSE;
  1911. //
  1912. // loop sending until
  1913. // - receive successful response
  1914. // or
  1915. // - receive errors response from all servers
  1916. // or
  1917. // - reach final timeout on all servers
  1918. //
  1919. retry = 0;
  1920. while ( 1 )
  1921. {
  1922. timeout = g_MulticastQueryTimeouts[retry];
  1923. //
  1924. // zero timeout indicates end of retries for this query type
  1925. //
  1926. if ( timeout == 0 )
  1927. {
  1928. break;
  1929. }
  1930. //
  1931. // send to multicast DNS address
  1932. //
  1933. if ( retry == 0 )
  1934. {
  1935. Dns_InitializeMsgRemoteSockaddr( pMsgSend, MULTICAST_DNS_RADDR );
  1936. Dns_Send( pMsgSend );
  1937. }
  1938. else
  1939. {
  1940. Dns_Send( pMsgSend );
  1941. }
  1942. retry++;
  1943. recvIp = 0;
  1944. rcode = DNS_RCODE_NO_ERROR;
  1945. pMsgRecv->Timeout = timeout;
  1946. //
  1947. // receive response
  1948. //
  1949. // note: the loop is strictly to allow us to drop back into
  1950. // receive if one server is misbehaving;
  1951. // in that case we go back into the receive without resending
  1952. // to allow other servers to respond
  1953. //
  1954. status = Dns_RecvUdp( pMsgRecv );
  1955. // recv wait completed
  1956. // - if timeout, commence next retry
  1957. // - if CONNRESET
  1958. // - back to recv if more DNS servers outstanding,
  1959. // - otherwise equivalent treat as timeout, except with
  1960. // very long timeout
  1961. // - if success, verify packet
  1962. if ( status != ERROR_SUCCESS )
  1963. {
  1964. if ( status == ERROR_TIMEOUT )
  1965. {
  1966. continue;
  1967. }
  1968. if ( status == WSAECONNRESET )
  1969. {
  1970. pMsgRecv->Timeout = NO_DNS_PRIORITY_DROP;
  1971. status = ERROR_TIMEOUT;
  1972. continue;
  1973. }
  1974. goto Done;
  1975. }
  1976. // check XID match
  1977. if ( pMsgRecv->MessageHead.Xid != pMsgSend->MessageHead.Xid )
  1978. {
  1979. DNS_PRINT(( "WARNING: Incorrect XID in response. Ignoring.\n" ));
  1980. continue;
  1981. }
  1982. // suck out the IP of the machine that responded
  1983. recvIp = MSG_REMOTE_IP4(pMsgRecv);
  1984. // suck out RCODE
  1985. rcode = pMsgRecv->MessageHead.ResponseCode;
  1986. //
  1987. // good response?
  1988. //
  1989. // special case AUTH-EMPTY and delegations
  1990. //
  1991. // - AUTH-EMPTY gets similar treatment to name error
  1992. // (this adapter can be considered to be finished)
  1993. //
  1994. // - referrals can be treated like SERVER_FAILURE
  1995. // (avoid this server for rest of query; server may
  1996. // be fine for direct lookup, so don't drop priority)
  1997. //
  1998. if ( rcode == DNS_RCODE_NO_ERROR )
  1999. {
  2000. if ( pMsgRecv->MessageHead.AnswerCount != 0 )
  2001. {
  2002. goto Done;
  2003. }
  2004. // auth-empty
  2005. if ( pMsgRecv->MessageHead.Authoritative == 1 )
  2006. {
  2007. DNSDBG( RECV, (
  2008. "Recv AUTH-EMPTY response from %s\n",
  2009. IP_STRING(recvIp) ));
  2010. rcode = DNS_RCODE_AUTH_EMPTY_RESPONSE;
  2011. }
  2012. }
  2013. } // end loop sending/recving packets
  2014. Done:
  2015. //
  2016. // if created socket -- close it
  2017. //
  2018. // DCR_ENHANCE: allow for possibility of keeping socket alive
  2019. //
  2020. if ( fcreatedSocket )
  2021. {
  2022. DNSDBG( SEND, (
  2023. "Closing socket %d after recv.\n", s ));
  2024. Dns_CloseSocket( s );
  2025. pMsgSend->Socket = 0;
  2026. pMsgRecv->Socket = 0;
  2027. }
  2028. IF_DNSDBG( RECV )
  2029. {
  2030. DNSDBG( SEND, (
  2031. "Leave Dns_SendAndRecvMulticast()\n"
  2032. "\tstatus = %d\n"
  2033. "\ttime = %d\n"
  2034. "\tsend msg at %p\n"
  2035. "\trecv msg at %p\n",
  2036. status,
  2037. Dns_GetCurrentTimeInSeconds(),
  2038. pMsgSend,
  2039. pMsgRecv ));
  2040. }
  2041. if ( status == ERROR_TIMEOUT )
  2042. {
  2043. status = DNS_ERROR_RCODE_NAME_ERROR;
  2044. }
  2045. return( status );
  2046. }
  2047. //
  2048. // TCP routines
  2049. //
  2050. DNS_STATUS
  2051. Dns_OpenTcpConnectionAndSend(
  2052. IN OUT PDNS_MSG_BUF pMsg,
  2053. IN IP_ADDRESS ipServer,
  2054. IN BOOL fBlocking
  2055. )
  2056. /*++
  2057. Routine Description:
  2058. Connect via TCP to desired server.
  2059. Arguments:
  2060. pMsg -- message info to set with connection socket
  2061. ipServer -- IP of DNS server to connect to
  2062. fBlocking -- blocking connection
  2063. Return Value:
  2064. TRUE if successful.
  2065. FALSE on connect error.
  2066. --*/
  2067. {
  2068. SOCKET s;
  2069. INT err;
  2070. // Note: currently blocking flag is unused and default to blocking
  2071. // connection; later want to allow async hence flag
  2072. UNREFERENCED_PARAMETER( fBlocking );
  2073. //
  2074. // setup a TCP socket
  2075. // - INADDR_ANY -- let stack select source IP
  2076. //
  2077. s = Dns_CreateSocket(
  2078. SOCK_STREAM,
  2079. INADDR_ANY, // any address
  2080. 0 // any port
  2081. );
  2082. if ( s == INVALID_SOCKET )
  2083. {
  2084. DNS_PRINT((
  2085. "ERROR: unable to create TCP socket to create TCP"
  2086. "\tconnection to %s.\n",
  2087. IP_STRING( ipServer ) ));
  2088. pMsg->Socket = 0;
  2089. err = WSAGetLastError();
  2090. if ( !err )
  2091. {
  2092. DNS_ASSERT( FALSE );
  2093. err = WSAENOTSOCK;
  2094. }
  2095. return( err );
  2096. }
  2097. //
  2098. // set TCP params
  2099. // - do before connect(), so can directly use sockaddr buffer
  2100. //
  2101. pMsg->fTcp = TRUE;
  2102. Dns_InitializeMsgRemoteSockaddr( pMsg, ipServer );
  2103. //
  2104. // connect
  2105. //
  2106. err = connect(
  2107. s,
  2108. (struct sockaddr *) &pMsg->RemoteAddress,
  2109. sizeof( SOCKADDR_IN )
  2110. );
  2111. if ( err )
  2112. {
  2113. PCHAR pchIpString;
  2114. err = GetLastError();
  2115. pchIpString = IP_STRING( MSG_REMOTE_IP4(pMsg) );
  2116. DNS_LOG_EVENT(
  2117. DNS_EVENT_CANNOT_CONNECT_TO_SERVER,
  2118. 1,
  2119. &pchIpString,
  2120. err );
  2121. DNSDBG( TCP, (
  2122. "Unable to establish TCP connection to %s.\n"
  2123. "\tstatus = %d\n",
  2124. pchIpString,
  2125. err ));
  2126. Dns_CloseSocket( s );
  2127. pMsg->Socket = 0;
  2128. if ( !err )
  2129. {
  2130. err = WSAENOTCONN;
  2131. }
  2132. return( err );
  2133. }
  2134. DNSDBG( TCP, (
  2135. "Connected to %s for message at %p.\n"
  2136. "\tsocket = %d\n",
  2137. IP_STRING( MSG_REMOTE_IP4(pMsg) ),
  2138. pMsg,
  2139. s ));
  2140. pMsg->Socket = s;
  2141. //
  2142. // send desired packet
  2143. //
  2144. err = Dns_Send( pMsg );
  2145. return( (DNS_STATUS)err );
  2146. } // Dns_OpenTcpConnectionAndSend
  2147. DNS_STATUS
  2148. Dns_RecvTcp(
  2149. IN OUT PDNS_MSG_BUF pMsg
  2150. )
  2151. /*++
  2152. Routine Description:
  2153. Receive TCP DNS message.
  2154. Arguments:
  2155. pMsg - message info buffer to receive packet; must contain connected
  2156. TCP socket
  2157. Return Value:
  2158. ERROR_SUCCESS if successfully receive a message.
  2159. Error code on failure.
  2160. --*/
  2161. {
  2162. PCHAR pchrecv; // ptr to recv location
  2163. INT recvLength; // length left to recv()
  2164. SOCKET socket;
  2165. INT err;
  2166. WORD messageLength;
  2167. struct timeval selectTimeout;
  2168. struct fd_set fdset;
  2169. DNS_ASSERT( pMsg );
  2170. socket = pMsg->Socket;
  2171. DNSDBG( RECV, (
  2172. "Enter Dns_RecvTcp( %p )\n"
  2173. "\tRecv on socket = %d.\n"
  2174. "\tBytes left to receive = %d\n"
  2175. "\tTimeout = %d\n",
  2176. pMsg,
  2177. socket,
  2178. pMsg->BytesToReceive,
  2179. pMsg->Timeout
  2180. ));
  2181. //
  2182. // verify socket, setup fd_set and select timeout
  2183. //
  2184. if ( socket == 0 || socket == INVALID_SOCKET )
  2185. {
  2186. return( ERROR_INVALID_PARAMETER );
  2187. }
  2188. FD_ZERO( &fdset );
  2189. FD_SET( socket, &fdset );
  2190. selectTimeout.tv_usec = 0;
  2191. selectTimeout.tv_sec = pMsg->Timeout;
  2192. //
  2193. // new message -- set to receive message length
  2194. // - reusing buffer
  2195. // - new buffer
  2196. //
  2197. // continuing receive of message
  2198. //
  2199. if ( !pMsg->pchRecv )
  2200. {
  2201. DNS_ASSERT( pMsg->fMessageComplete || pMsg->MessageLength == 0 );
  2202. pchrecv = (PCHAR) &pMsg->MessageLength;
  2203. recvLength = (INT) sizeof( WORD );
  2204. }
  2205. else
  2206. {
  2207. pchrecv = (PCHAR) pMsg->pchRecv;
  2208. recvLength = (INT) pMsg->BytesToReceive;
  2209. }
  2210. DNS_ASSERT( recvLength );
  2211. //
  2212. // loop until receive the entire message
  2213. //
  2214. while ( 1 )
  2215. {
  2216. //
  2217. // wait for stack to indicate packet reception
  2218. //
  2219. err = select( 0, &fdset, NULL, NULL, &selectTimeout );
  2220. if ( err <= 0 )
  2221. {
  2222. if ( err < 0 )
  2223. {
  2224. // select error
  2225. err = WSAGetLastError();
  2226. DNS_PRINT(( "ERROR: select() error = %p\n", err ));
  2227. return( err );
  2228. }
  2229. else
  2230. {
  2231. Trace_LogRecvEvent(
  2232. pMsg,
  2233. ERROR_TIMEOUT,
  2234. TRUE // TCP
  2235. );
  2236. DNS_PRINT(( "ERROR: timeout on response %p\n", pMsg ));
  2237. return( ERROR_TIMEOUT );
  2238. }
  2239. }
  2240. //
  2241. // Only recv() exactly as much data as indicated.
  2242. // Another message could follow during zone transfer.
  2243. //
  2244. err = recv(
  2245. socket,
  2246. pchrecv,
  2247. recvLength,
  2248. 0 );
  2249. DNSDBG( TCP, (
  2250. "\nRecv'd %d bytes on TCP socket %d\n",
  2251. err,
  2252. socket ));
  2253. //
  2254. // TCP FIN received -- error in the middle of a message.
  2255. //
  2256. if ( err == 0 )
  2257. {
  2258. goto FinReceived;
  2259. }
  2260. //
  2261. // recv error
  2262. // - perfectly reasonable if shutting down
  2263. // - otherwise actual recv() error
  2264. //
  2265. if ( err == SOCKET_ERROR )
  2266. {
  2267. goto SockError;
  2268. }
  2269. //
  2270. // update buffer params
  2271. //
  2272. recvLength -= err;
  2273. pchrecv += err;
  2274. DNS_ASSERT( recvLength >= 0 );
  2275. //
  2276. // received message or message length
  2277. //
  2278. if ( recvLength == 0 )
  2279. {
  2280. // done receiving message
  2281. if ( pchrecv > (PCHAR)&pMsg->MessageHead )
  2282. {
  2283. break;
  2284. }
  2285. //
  2286. // recv'd message length, setup to recv() message
  2287. // - byte flip length
  2288. // - continue reception with this length
  2289. //
  2290. DNS_ASSERT( pchrecv == (PCHAR)&pMsg->MessageHead );
  2291. messageLength = pMsg->MessageLength;
  2292. pMsg->MessageLength = messageLength = ntohs( messageLength );
  2293. if ( messageLength < sizeof(DNS_HEADER) )
  2294. {
  2295. DNS_PRINT((
  2296. "ERROR: Received TCP message with bad message"
  2297. " length %d.\n",
  2298. messageLength ));
  2299. goto BadTcpMessage;
  2300. }
  2301. recvLength = messageLength;
  2302. DNSDBG( TCP, (
  2303. "Received TCP message length %d, on socket %d,\n"
  2304. "\tfor msg at %p.\n",
  2305. messageLength,
  2306. socket,
  2307. pMsg ));
  2308. // starting recv of valid message length
  2309. if ( messageLength <= pMsg->BufferLength )
  2310. {
  2311. continue;
  2312. }
  2313. // note: currently do not realloc
  2314. goto BadTcpMessage;
  2315. #if 0
  2316. //
  2317. // DCR: allow TCP realloc
  2318. // - change call signature OR
  2319. // - return pMsg with ptr to realloced
  2320. // perhaps better to ignore and do 64K buffer all the time
  2321. //
  2322. // realloc, if existing message too small
  2323. //
  2324. pMsg = Dns_ReallocateTcpMessage( pMsg, messageLength );
  2325. if ( !pMsg )
  2326. {
  2327. return( GetLastError() );
  2328. }
  2329. #endif
  2330. }
  2331. }
  2332. //
  2333. // Message received
  2334. // recv ptr serves as flag, clear to start new message on reuse
  2335. //
  2336. pMsg->fMessageComplete = TRUE;
  2337. pMsg->pchRecv = NULL;
  2338. //
  2339. // return message information
  2340. // - flip count bytes
  2341. //
  2342. DNS_BYTE_FLIP_HEADER_COUNTS( &pMsg->MessageHead );
  2343. Trace_LogRecvEvent(
  2344. pMsg,
  2345. 0,
  2346. TRUE // TCP
  2347. );
  2348. IF_DNSDBG( RECV )
  2349. {
  2350. DnsDbg_Message(
  2351. "Received TCP packet",
  2352. pMsg );
  2353. }
  2354. return( ERROR_SUCCESS );
  2355. SockError:
  2356. err = GetLastError();
  2357. #if 0
  2358. //
  2359. // note: want non-blocking sockets if doing full async
  2360. //
  2361. // WSAEWOULD block is NORMAL return for message not fully recv'd.
  2362. // - save state of message reception
  2363. //
  2364. // We use non-blocking sockets, so bad client (that fails to complete
  2365. // message) doesn't hang TCP receiver.
  2366. //
  2367. if ( err == WSAEWOULDBLOCK )
  2368. {
  2369. pMsg->pchRecv = pchrecv;
  2370. pMsg->BytesToReceive = recvLength;
  2371. DNSDBG( TCP, (
  2372. "Leave ReceiveTcpMessage() after WSAEWOULDBLOCK.\n"
  2373. "\tSocket=%d, Msg=%p\n"
  2374. "\tBytes left to receive = %d\n",
  2375. socket,
  2376. pMsg,
  2377. pMsg->BytesToReceive
  2378. ));
  2379. goto CleanupConnection;
  2380. }
  2381. #endif
  2382. //
  2383. // cancelled connection
  2384. // -- perfectly legal, question is why
  2385. //
  2386. if ( pchrecv == (PCHAR) &pMsg->MessageLength
  2387. &&
  2388. ( err == WSAESHUTDOWN ||
  2389. err == WSAECONNABORTED ||
  2390. err == WSAECONNRESET ) )
  2391. {
  2392. DNSDBG( TCP, (
  2393. "WARNING: Recv RESET (%d) on socket %d\n",
  2394. err,
  2395. socket ));
  2396. goto CleanupConnection;
  2397. }
  2398. // anything else is our problem
  2399. DNS_LOG_EVENT(
  2400. DNS_EVENT_RECV_CALL_FAILED,
  2401. 0,
  2402. NULL,
  2403. err );
  2404. DNSDBG( ANY, (
  2405. "ERROR: recv() of TCP message failed.\n"
  2406. "\t%d bytes recvd\n"
  2407. "\t%d bytes left\n"
  2408. "\tGetLastError = 0x%08lx.\n",
  2409. pchrecv - (PCHAR)&pMsg->MessageLength,
  2410. recvLength,
  2411. err ));
  2412. DNS_ASSERT( FALSE );
  2413. goto CleanupConnection;
  2414. FinReceived:
  2415. //
  2416. // valid FIN -- if recv'd between messages (before message length)
  2417. //
  2418. DNSDBG( TCP, (
  2419. "ERROR: Recv TCP FIN (0 bytes) on socket %d\n",
  2420. socket,
  2421. recvLength ));
  2422. if ( !pMsg->MessageLength && pchrecv == (PCHAR)&pMsg->MessageLength )
  2423. {
  2424. err = DNS_ERROR_NO_PACKET;
  2425. goto CleanupConnection;
  2426. }
  2427. //
  2428. // FIN during message -- invalid message
  2429. //
  2430. DNSDBG( ANY, (
  2431. "ERROR: TCP message received has incorrect length.\n"
  2432. "\t%d bytes left when recv'd FIN.\n",
  2433. recvLength ));
  2434. goto BadTcpMessage;
  2435. BadTcpMessage:
  2436. {
  2437. PCHAR pchServer = IP_STRING( MSG_REMOTE_IP4(pMsg) );
  2438. DNS_LOG_EVENT(
  2439. DNS_EVENT_BAD_TCP_MESSAGE,
  2440. 1,
  2441. & pchServer,
  2442. 0 );
  2443. }
  2444. err = DNS_ERROR_BAD_PACKET;
  2445. CleanupConnection:
  2446. // close connection and socket, indicate this by zeroing socket
  2447. // in message buffer
  2448. Dns_CloseConnection( socket );
  2449. pMsg->Socket = 0;
  2450. return( DNS_ERROR_BAD_PACKET );
  2451. }
  2452. DNS_STATUS
  2453. Dns_SendAndRecvTcp(
  2454. IN PDNS_MSG_BUF pMsgSend,
  2455. OUT PDNS_MSG_BUF pMsgRecv,
  2456. IN PIP_ARRAY aipServers,
  2457. IN OUT PDNS_NETINFO pNetInfo
  2458. )
  2459. /*++
  2460. Routine Description:
  2461. Sends to and waits to recv from remote DNS.
  2462. Arguments:
  2463. pMsgSend - message to send
  2464. pMsgRecv - and reuse
  2465. aipServers -- counted array of DNS server IP addrs
  2466. pNetInfo -- adapter info list; ignored if aipServers given
  2467. Return Value:
  2468. ERROR_SUCCESS if successful packet reception.
  2469. Error status on failure.
  2470. --*/
  2471. {
  2472. DWORD i;
  2473. DNS_STATUS status;
  2474. PIP_ARRAY pallocatedServerIpArray = NULL;
  2475. DNSDBG( SEND, (
  2476. "Enter Dns_SendAndRecvTcp()\n"
  2477. "\tsend msg at %p\n"
  2478. "\tsocket %d\n"
  2479. "\trecv msg at %p\n"
  2480. "\tserver IP array %p\n"
  2481. "\tadapter info at %p\n",
  2482. pMsgSend,
  2483. pMsgSend->Socket,
  2484. pMsgRecv,
  2485. aipServers,
  2486. pNetInfo ));
  2487. //
  2488. // verify params
  2489. //
  2490. if ( !pMsgSend || !pMsgRecv || (!pNetInfo && !aipServers) )
  2491. {
  2492. return( ERROR_INVALID_PARAMETER );
  2493. }
  2494. //
  2495. // build server IP array?
  2496. //
  2497. if ( !aipServers )
  2498. {
  2499. pallocatedServerIpArray = NetInfo_ConvertToIpArray( pNetInfo );
  2500. if ( !pallocatedServerIpArray )
  2501. {
  2502. return( DNS_ERROR_NO_MEMORY );
  2503. }
  2504. aipServers = pallocatedServerIpArray;
  2505. }
  2506. // init remote sockaddr and socket
  2507. // setup receive buffer for TCP
  2508. Dns_InitializeMsgRemoteSockaddr(
  2509. pMsgSend,
  2510. aipServers->AddrArray[0] );
  2511. pMsgSend->Socket = 0;
  2512. pMsgRecv->Socket = 0;
  2513. pMsgSend->fTcp = TRUE;
  2514. SET_MESSAGE_FOR_TCP_RECV( pMsgRecv );
  2515. //
  2516. // loop sending until
  2517. // - receive successful response
  2518. // or
  2519. // - receive errors response from all servers
  2520. // or
  2521. // - reach final timeout on all servers
  2522. //
  2523. if ( pMsgRecv->Timeout == 0 )
  2524. {
  2525. pMsgRecv->Timeout = DEFAULT_TCP_TIMEOUT;
  2526. }
  2527. for( i=0; i<aipServers->AddrCount; i++ )
  2528. {
  2529. //
  2530. // close any previous connection
  2531. //
  2532. if ( pMsgSend->Socket )
  2533. {
  2534. Dns_CloseConnection( pMsgSend->Socket );
  2535. pMsgSend->Socket = 0;
  2536. pMsgRecv->Socket = 0;
  2537. }
  2538. //
  2539. // connect and send to next server
  2540. //
  2541. status = Dns_OpenTcpConnectionAndSend(
  2542. pMsgSend,
  2543. aipServers->AddrArray[i],
  2544. TRUE
  2545. );
  2546. if ( status != ERROR_SUCCESS )
  2547. {
  2548. continue;
  2549. }
  2550. DNS_ASSERT( pMsgSend->Socket != INVALID_SOCKET && pMsgSend->Socket != 0 );
  2551. //
  2552. // receive response
  2553. // - if successful receive, done
  2554. // - if timeout continue
  2555. // - other errors indicate some setup or system level problem
  2556. // note: Dns_RecvTcp will close and zero msg->socket on error!
  2557. //
  2558. pMsgRecv->Socket = pMsgSend->Socket;
  2559. status = Dns_RecvTcp( pMsgRecv );
  2560. if ( pMsgRecv->Socket == 0 )
  2561. {
  2562. // socket error -> socket has been closed
  2563. pMsgSend->Socket = 0;
  2564. }
  2565. //
  2566. // timed out (or error)
  2567. // - if end of timeout, quit
  2568. // - otherwise double timeout and resend
  2569. //
  2570. switch( status )
  2571. {
  2572. case ERROR_SUCCESS:
  2573. break;
  2574. case ERROR_TIMEOUT:
  2575. DNS_PRINT((
  2576. "ERROR: connected to server at %s\n"
  2577. "\tbut no response to packet at %p\n",
  2578. IP_STRING( MSG_REMOTE_IP4(pMsgSend) ),
  2579. pMsgSend
  2580. ));
  2581. continue;
  2582. default:
  2583. DNS_PRINT((
  2584. "ERROR: connected to server at %s to send packet %p\n"
  2585. "\tbut error %d encountered on receive.\n",
  2586. IP_STRING( MSG_REMOTE_IP4(pMsgSend) ),
  2587. pMsgSend,
  2588. status
  2589. ));
  2590. continue;
  2591. }
  2592. //
  2593. // verify XID match
  2594. //
  2595. if ( pMsgRecv->MessageHead.Xid != pMsgSend->MessageHead.Xid )
  2596. {
  2597. DNS_PRINT((
  2598. "ERROR: Incorrect XID in response. Ignoring.\n" ));
  2599. continue;
  2600. }
  2601. //
  2602. // verify question match
  2603. // - this is "Maggs Bug" check
  2604. // - ASSERT here just to investigate issue locally
  2605. // and make sure check is not bogus
  2606. //
  2607. if ( !Dns_IsSamePacketQuestion(
  2608. pMsgRecv,
  2609. pMsgSend ))
  2610. {
  2611. DNS_PRINT((
  2612. "ERROR: Bad question response from server %08x!\n"
  2613. "\tXID match, but question does not match question sent!\n",
  2614. MSG_REMOTE_IP4(pMsgSend) ));
  2615. DNS_ASSERT( FALSE );
  2616. continue;
  2617. }
  2618. //
  2619. // check response code
  2620. // - some move to next server, others terminal
  2621. //
  2622. // DCR_FIX1: bring TCP RCODE handling in-line with UDP
  2623. //
  2624. // DCR_FIX: save best TCP RCODE
  2625. // preserve RCODE (and message) for useless TCP response
  2626. // would need to then reset TIMEOUT to success at end
  2627. // or use these RCODEs as status returns
  2628. //
  2629. switch( pMsgRecv->MessageHead.ResponseCode )
  2630. {
  2631. case DNS_RCODE_SERVER_FAILURE:
  2632. case DNS_RCODE_NOT_IMPLEMENTED:
  2633. case DNS_RCODE_REFUSED:
  2634. DNS_PRINT((
  2635. "WARNING: Servers have responded with failure.\n" ));
  2636. continue;
  2637. default:
  2638. break;
  2639. }
  2640. break;
  2641. } // end loop sending/recving UPDATEs
  2642. //
  2643. // close up final connection
  2644. // unless set to keep open for reuse
  2645. //
  2646. Dns_CloseConnection( pMsgSend->Socket );
  2647. pMsgSend->Socket = 0;
  2648. pMsgRecv->Socket = 0;
  2649. // if allocated adapter list free it
  2650. if ( pallocatedServerIpArray )
  2651. {
  2652. FREE_HEAP( pallocatedServerIpArray );
  2653. }
  2654. DNSDBG( SEND, (
  2655. "Leaving Dns_SendAndRecvTcp()\n"
  2656. "\tstatus = %d\n",
  2657. status ));
  2658. return( status );
  2659. }
  2660. #if 0
  2661. DNS_STATUS
  2662. Dns_AsyncRecv(
  2663. IN OUT PDNS_MSG_BUF pMsgRecv
  2664. )
  2665. /*++
  2666. Routine Description:
  2667. Drop recv on async socket.
  2668. Arguments:
  2669. pMsgRecv - message to receive; OPTIONAL, if NULL message buffer
  2670. is allocated;
  2671. in either case global pDnsAsyncRecvMsg points at buffer
  2672. Return Value:
  2673. ERROR_SUCCESS if successful.
  2674. Error status on failure.
  2675. --*/
  2676. {
  2677. WSABUF wsabuf;
  2678. DWORD bytesRecvd;
  2679. DWORD flags = 0;
  2680. IF_DNSDBG( RECV )
  2681. {
  2682. DNS_PRINT((
  2683. "Enter Dns_AsyncRecv( %p )\n",
  2684. pMsgRecv ));
  2685. }
  2686. //
  2687. // allocate buffer if none given
  2688. //
  2689. if ( !pMsgRecv )
  2690. {
  2691. pMsgRecv = Dns_AllocateMsgBuf( MAXWORD );
  2692. if ( !pMsgRecv )
  2693. {
  2694. return( GetLastError() ):
  2695. }
  2696. }
  2697. pDnsAsyncRecvMsg = pMsgRecv;
  2698. //
  2699. // reset i/o completion event
  2700. //
  2701. ResetEvent( hDnsSocketEvent );
  2702. DNS_ASSERT( hDnsSocketEvent == Dns_SocketOverlapped.hEvent );
  2703. //
  2704. // drop down recv
  2705. //
  2706. status = WSARecvFrom(
  2707. DnsSocket,
  2708. & wsabuf,
  2709. 1,
  2710. & bytesRecvd, // dummy
  2711. & flags,
  2712. & pMsgRecv->RemoteAddress,
  2713. & pMsgRecv->RemoteAddressLength,
  2714. & DnsSocketOverlapped,
  2715. NULL // no completion routine
  2716. );
  2717. return( ERROR_SUCCESS );
  2718. Failed:
  2719. return( status );
  2720. }
  2721. #endif
  2722. DNS_STATUS
  2723. Dns_SendAndRecv(
  2724. IN OUT PDNS_MSG_BUF pMsgSend,
  2725. OUT PDNS_MSG_BUF * ppMsgRecv,
  2726. OUT PDNS_RECORD * ppResponseRecords,
  2727. IN DWORD dwFlags,
  2728. IN PIP_ARRAY aipServers,
  2729. IN OUT PDNS_NETINFO pNetInfo
  2730. )
  2731. /*++
  2732. Routine Description:
  2733. Send message, receive response.
  2734. Arguments:
  2735. pMsgSend -- message to send
  2736. ppMsgResponse -- addr to recv ptr to response buffer; caller MUST
  2737. free buffer
  2738. ppResponseRecord -- address to receive ptr to record list returned from query
  2739. dwFlags -- query flags
  2740. aipDnsServers -- specific DNS servers to query;
  2741. OPTIONAL, if specified overrides normal list associated with machine
  2742. pDnsNetAdapters -- DNS servers to query; if NULL get current list
  2743. Return Value:
  2744. ERROR_SUCCESS if successful.
  2745. Error code on failure.
  2746. --*/
  2747. {
  2748. PDNS_MSG_BUF precvMsg = NULL;
  2749. PDNS_MSG_BUF psavedUdpResponse = NULL;
  2750. DNS_STATUS statusFromUdp = ERROR_SUCCESS;
  2751. DNS_STATUS status = ERROR_TIMEOUT;
  2752. DNS_STATUS parseStatus;
  2753. BOOL ftcp;
  2754. IP_ARRAY tempArray;
  2755. DNSDBG( QUERY, (
  2756. "Dns_SendAndRecv()\n"
  2757. "\tsend msg %p\n"
  2758. "\trecv msg %p\n"
  2759. "\trecv records %p\n"
  2760. "\tflags %08x\n"
  2761. "\tserver %p\n"
  2762. "\tadapter list %p\n",
  2763. pMsgSend,
  2764. ppMsgRecv,
  2765. ppResponseRecords,
  2766. dwFlags,
  2767. aipServers,
  2768. pNetInfo ));
  2769. // response buf passed in?
  2770. // if not allocate one -- big enough for TCP
  2771. if ( ppMsgRecv && *ppMsgRecv )
  2772. {
  2773. precvMsg = *ppMsgRecv;
  2774. }
  2775. if ( !precvMsg )
  2776. {
  2777. precvMsg = Dns_AllocateMsgBuf( DNS_TCP_DEFAULT_PACKET_LENGTH );
  2778. if ( !precvMsg )
  2779. {
  2780. status = DNS_ERROR_NO_MEMORY;
  2781. goto Cleanup;
  2782. }
  2783. }
  2784. //
  2785. // send packet and get response
  2786. // - try UDP first unless TCP only
  2787. //
  2788. ftcp = ( dwFlags & DNS_QUERY_USE_TCP_ONLY ) ||
  2789. ( DNS_MESSAGE_CURRENT_OFFSET(pMsgSend) >= DNS_RFC_MAX_UDP_PACKET_LENGTH );
  2790. if ( !ftcp )
  2791. {
  2792. if ( dwFlags & DNS_QUERY_MULTICAST_ONLY )
  2793. {
  2794. //
  2795. // If the multicast query fails, then ERROR_TIMEOUT will
  2796. // be returned
  2797. //
  2798. goto DoMulticast;
  2799. }
  2800. status = Dns_SendAndRecvUdp(
  2801. pMsgSend,
  2802. precvMsg,
  2803. dwFlags,
  2804. aipServers,
  2805. pNetInfo );
  2806. statusFromUdp = status;
  2807. if ( status != ERROR_SUCCESS &&
  2808. status != DNS_ERROR_RCODE_NAME_ERROR &&
  2809. status != DNS_INFO_NO_RECORDS )
  2810. {
  2811. //
  2812. // DCR: this multicast ON_NAME_ERROR test is bogus
  2813. // this isn't NAME_ERROR this is pretty much any error
  2814. //
  2815. if ( pNetInfo &&
  2816. pNetInfo->InfoFlags & DNS_FLAG_MULTICAST_ON_NAME_ERROR )
  2817. {
  2818. goto DoMulticast;
  2819. }
  2820. else
  2821. {
  2822. goto Cleanup;
  2823. }
  2824. }
  2825. // if truncated response switch to TCP
  2826. if ( precvMsg->MessageHead.Truncation &&
  2827. ! (dwFlags & DNS_QUERY_ACCEPT_PARTIAL_UDP) )
  2828. {
  2829. ftcp = TRUE;
  2830. tempArray.AddrCount = 1;
  2831. tempArray.AddrArray[0] = MSG_REMOTE_IP4(precvMsg);
  2832. aipServers = &tempArray;
  2833. psavedUdpResponse = precvMsg;
  2834. precvMsg = NULL;
  2835. }
  2836. }
  2837. //
  2838. // TCP send
  2839. // - for TCP queries
  2840. // - or truncation on UDP unless accepting partial response
  2841. //
  2842. // DCR_FIX: this precvMsg Free is bad
  2843. // if message was passed in we shouldn't have it, we should
  2844. // just do our own thing and ignore this recv buffer somehow
  2845. // ideally that buffer action is at much higher level
  2846. //
  2847. if ( ftcp )
  2848. {
  2849. if ( precvMsg &&
  2850. precvMsg->BufferLength < DNS_TCP_DEFAULT_PACKET_LENGTH )
  2851. {
  2852. FREE_HEAP( precvMsg );
  2853. precvMsg = NULL;
  2854. }
  2855. if ( !precvMsg )
  2856. {
  2857. precvMsg = Dns_AllocateMsgBuf( DNS_TCP_DEFAULT_PACKET_LENGTH );
  2858. if ( !precvMsg )
  2859. {
  2860. status = DNS_ERROR_NO_MEMORY;
  2861. goto Cleanup;
  2862. }
  2863. }
  2864. pMsgSend->fTcp = TRUE;
  2865. precvMsg->fTcp = TRUE;
  2866. #if 0
  2867. if ( dwFlags & DNS_QUERY_SOCKET_KEEPALIVE )
  2868. {
  2869. precvMsg->fSocketKeepalive = TRUE;
  2870. }
  2871. #endif
  2872. status = Dns_SendAndRecvTcp(
  2873. pMsgSend,
  2874. precvMsg,
  2875. aipServers,
  2876. pNetInfo );
  2877. //
  2878. // if recursing following truncated UDP query, then
  2879. // must make sure we actually have better data
  2880. // - if successful, but RCODE is different and bad
  2881. // => use UDP response
  2882. // - if failed TCP => use UDP
  2883. // - successful with good RCODE => parse TCP response
  2884. //
  2885. if ( psavedUdpResponse )
  2886. {
  2887. if ( status == ERROR_SUCCESS )
  2888. {
  2889. DWORD rcode = precvMsg->MessageHead.ResponseCode;
  2890. if ( rcode == ERROR_SUCCESS ||
  2891. rcode == psavedUdpResponse->MessageHead.ResponseCode ||
  2892. ( rcode != DNS_RCODE_SERVER_FAILURE &&
  2893. rcode != DNS_RCODE_FORMAT_ERROR &&
  2894. rcode != DNS_RCODE_REFUSED ) )
  2895. {
  2896. goto Parse;
  2897. }
  2898. }
  2899. // TCP failed or returned bum error code
  2900. FREE_HEAP( precvMsg );
  2901. precvMsg = psavedUdpResponse;
  2902. psavedUdpResponse = NULL;
  2903. }
  2904. // direct TCP query
  2905. // - cleanup if failed
  2906. else if ( status != ERROR_SUCCESS )
  2907. {
  2908. goto Cleanup;
  2909. }
  2910. }
  2911. //
  2912. // DCR: this multicast test is bogus (too wide open)
  2913. // essentially ANY error sends us on to multicast
  2914. // even INFO_NO_RECORDS
  2915. //
  2916. // multicast test should be intelligent
  2917. // - adpater with no DNS servers, or NO_RESPONSE
  2918. // from any DNS server
  2919. //
  2920. if ( status == ERROR_SUCCESS )
  2921. {
  2922. DWORD rcode = precvMsg->MessageHead.ResponseCode;
  2923. if ( rcode == ERROR_SUCCESS ||
  2924. ( rcode != DNS_RCODE_SERVER_FAILURE &&
  2925. rcode != DNS_RCODE_FORMAT_ERROR &&
  2926. rcode != DNS_RCODE_REFUSED ) )
  2927. {
  2928. goto Parse;
  2929. }
  2930. }
  2931. //
  2932. // multicast?
  2933. //
  2934. DoMulticast:
  2935. if ( ( pNetInfo &&
  2936. pNetInfo->InfoFlags & DNS_FLAG_ALLOW_MULTICAST )
  2937. ||
  2938. ( ( dwFlags & DNS_QUERY_MULTICAST_ONLY ) &&
  2939. ! pNetInfo ) )
  2940. {
  2941. if ( !pMsgSend ||
  2942. ( pMsgSend &&
  2943. ( pMsgSend->MessageHead.Opcode == DNS_OPCODE_UPDATE ) ) )
  2944. {
  2945. if ( statusFromUdp )
  2946. {
  2947. status = statusFromUdp;
  2948. }
  2949. else
  2950. {
  2951. status = DNS_ERROR_NO_DNS_SERVERS;
  2952. }
  2953. goto Cleanup;
  2954. }
  2955. status = Dns_SendAndRecvMulticast(
  2956. pMsgSend,
  2957. precvMsg,
  2958. pNetInfo );
  2959. if ( status != ERROR_SUCCESS &&
  2960. status != DNS_ERROR_RCODE_NAME_ERROR &&
  2961. status != DNS_INFO_NO_RECORDS )
  2962. {
  2963. if ( statusFromUdp )
  2964. {
  2965. status = statusFromUdp;
  2966. }
  2967. goto Cleanup;
  2968. }
  2969. }
  2970. //
  2971. // parse response (if desired)
  2972. //
  2973. Parse:
  2974. if ( ppResponseRecords )
  2975. {
  2976. parseStatus = Dns_ExtractRecordsFromMessage(
  2977. precvMsg,
  2978. (dwFlags & DNSQUERY_UNICODE_OUT),
  2979. ppResponseRecords );
  2980. if ( !(dwFlags & DNS_QUERY_DONT_RESET_TTL_VALUES ) )
  2981. {
  2982. Dns_NormalizeAllRecordTtls( *ppResponseRecords );
  2983. }
  2984. }
  2985. // not parsing -- just return RCODE as status
  2986. else
  2987. {
  2988. parseStatus = Dns_MapRcodeToStatus( precvMsg->MessageHead.ResponseCode );
  2989. }
  2990. //
  2991. // get "best" status
  2992. // - no-records response beats NAME_ERROR (or other error)
  2993. // dump bogus records from error response
  2994. //
  2995. // DCR: multi-adapter NXDOMAIN\no-records response broken
  2996. // note, here we'd give back a packet with NAME_ERROR
  2997. // or another error
  2998. //
  2999. if ( status != parseStatus )
  3000. {
  3001. // save previous NO_RECORDS response, from underlying query
  3002. // this trumps other errors (FORMERR, SERVFAIL, NXDOMAIN);
  3003. //
  3004. // note, that parsed message shouldn't be HIGHER level RCODE
  3005. // as these should beat out NO_RECORDS in original parsing
  3006. if ( status == DNS_INFO_NO_RECORDS &&
  3007. parseStatus != ERROR_SUCCESS )
  3008. {
  3009. ASSERT( precvMsg->MessageHead.ResponseCode <= DNS_RCODE_NAME_ERROR );
  3010. if ( *ppResponseRecords )
  3011. {
  3012. Dns_RecordListFree( *ppResponseRecords );
  3013. *ppResponseRecords = NULL;
  3014. }
  3015. }
  3016. else
  3017. {
  3018. status = parseStatus;
  3019. }
  3020. }
  3021. Cleanup:
  3022. // cleanup recv buffer?
  3023. if ( ppMsgRecv )
  3024. {
  3025. if ( status == ERROR_SUCCESS || Dns_IsStatusRcode(status) )
  3026. {
  3027. *ppMsgRecv = precvMsg;
  3028. }
  3029. else
  3030. {
  3031. *ppMsgRecv = NULL;
  3032. FREE_HEAP( precvMsg );
  3033. }
  3034. }
  3035. else
  3036. {
  3037. FREE_HEAP( precvMsg );
  3038. }
  3039. if ( psavedUdpResponse )
  3040. {
  3041. FREE_HEAP( psavedUdpResponse );
  3042. }
  3043. DNSDBG( RECV, (
  3044. "Leaving Dns_SendAndRecv(), status = %s (%d)\n",
  3045. Dns_StatusString(status),
  3046. status ));
  3047. return( status );
  3048. }
  3049. VOID
  3050. Dns_InitQueryTimeouts(
  3051. VOID
  3052. )
  3053. {
  3054. HKEY hKey = NULL;
  3055. DWORD status;
  3056. DWORD dwType;
  3057. DWORD ValueSize;
  3058. LPSTR lpTimeouts = NULL;
  3059. DWORD sysVersion;
  3060. DWORD winMajorVersion;
  3061. BOOL fIsWin95 = FALSE;
  3062. g_QueryTimeouts = QueryTimeouts;
  3063. g_QuickQueryTimeouts = QuickQueryTimeouts;
  3064. g_MulticastQueryTimeouts = MulticastQueryTimeouts;
  3065. //
  3066. // determine what kind of OS it is. Win95 or NT
  3067. //
  3068. sysVersion = GetVersion();
  3069. winMajorVersion = (DWORD) (LOBYTE(LOWORD(sysVersion)));
  3070. if (sysVersion < 0x80000000)
  3071. fIsWin95 = FALSE;
  3072. else
  3073. fIsWin95 = TRUE;
  3074. if ( fIsWin95 )
  3075. status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  3076. WIN95_TCPIP_REG_LOCATION,
  3077. 0,
  3078. KEY_QUERY_VALUE,
  3079. &hKey );
  3080. else
  3081. status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  3082. NT_TCPIP_REG_LOCATION,
  3083. 0,
  3084. KEY_QUERY_VALUE,
  3085. &hKey );
  3086. if ( status )
  3087. return;
  3088. if ( !hKey )
  3089. return;
  3090. status = RegQueryValueEx( hKey,
  3091. DNS_QUERY_TIMEOUTS,
  3092. NULL,
  3093. &dwType,
  3094. NULL,
  3095. &ValueSize );
  3096. if ( !status )
  3097. {
  3098. if ( ValueSize == 0 )
  3099. {
  3100. goto GetQuickQueryTimeouts;
  3101. }
  3102. lpTimeouts = ALLOCATE_HEAP( ValueSize );
  3103. if ( lpTimeouts )
  3104. {
  3105. LPSTR StringPtr;
  3106. DWORD StringLen;
  3107. DWORD Timeout;
  3108. DWORD Count = 0;
  3109. status = RegQueryValueEx( hKey,
  3110. DNS_QUERY_TIMEOUTS,
  3111. NULL,
  3112. &dwType,
  3113. lpTimeouts,
  3114. &ValueSize );
  3115. if ( status ||
  3116. dwType != REG_MULTI_SZ )
  3117. {
  3118. FREE_HEAP( lpTimeouts );
  3119. goto GetQuickQueryTimeouts;
  3120. }
  3121. StringPtr = lpTimeouts;
  3122. while ( ( StringLen = strlen( StringPtr ) ) != 0 &&
  3123. Count < DNS_MAX_QUERY_TIMEOUTS )
  3124. {
  3125. Timeout = atoi( StringPtr );
  3126. if ( Timeout )
  3127. RegistryQueryTimeouts[Count++] = Timeout;
  3128. StringPtr += (StringLen + 1);
  3129. }
  3130. RegistryQueryTimeouts[Count] = 0;
  3131. g_QueryTimeouts = RegistryQueryTimeouts;
  3132. FREE_HEAP( lpTimeouts );
  3133. }
  3134. }
  3135. GetQuickQueryTimeouts:
  3136. status = RegQueryValueEx( hKey,
  3137. DNS_QUICK_QUERY_TIMEOUTS,
  3138. NULL,
  3139. &dwType,
  3140. NULL,
  3141. &ValueSize );
  3142. if ( !status )
  3143. {
  3144. if ( ValueSize == 0 )
  3145. {
  3146. goto GetMulticastTimeouts;
  3147. }
  3148. lpTimeouts = ALLOCATE_HEAP( ValueSize );
  3149. if ( lpTimeouts )
  3150. {
  3151. LPSTR StringPtr;
  3152. DWORD StringLen;
  3153. DWORD Timeout;
  3154. DWORD Count = 0;
  3155. status = RegQueryValueEx( hKey,
  3156. DNS_QUICK_QUERY_TIMEOUTS,
  3157. NULL,
  3158. &dwType,
  3159. lpTimeouts,
  3160. &ValueSize );
  3161. if ( status ||
  3162. dwType != REG_MULTI_SZ )
  3163. {
  3164. FREE_HEAP( lpTimeouts );
  3165. goto GetMulticastTimeouts;
  3166. }
  3167. StringPtr = lpTimeouts;
  3168. while ( ( StringLen = strlen( StringPtr ) ) != 0 &&
  3169. Count < DNS_MAX_QUERY_TIMEOUTS )
  3170. {
  3171. Timeout = atoi( StringPtr );
  3172. if ( Timeout )
  3173. RegistryQuickQueryTimeouts[Count++] = Timeout;
  3174. StringPtr += (StringLen + 1);
  3175. }
  3176. RegistryQuickQueryTimeouts[Count] = 0;
  3177. g_QuickQueryTimeouts = RegistryQuickQueryTimeouts;
  3178. FREE_HEAP( lpTimeouts );
  3179. }
  3180. }
  3181. GetMulticastTimeouts:
  3182. status = RegQueryValueEx( hKey,
  3183. DNS_MULTICAST_QUERY_TIMEOUTS,
  3184. NULL,
  3185. &dwType,
  3186. NULL,
  3187. &ValueSize );
  3188. if ( !status )
  3189. {
  3190. if ( ValueSize == 0 )
  3191. {
  3192. RegCloseKey( hKey );
  3193. return;
  3194. }
  3195. lpTimeouts = ALLOCATE_HEAP( ValueSize );
  3196. if ( lpTimeouts )
  3197. {
  3198. LPSTR StringPtr;
  3199. DWORD StringLen;
  3200. DWORD Timeout;
  3201. DWORD Count = 0;
  3202. status = RegQueryValueEx( hKey,
  3203. DNS_MULTICAST_QUERY_TIMEOUTS,
  3204. NULL,
  3205. &dwType,
  3206. lpTimeouts,
  3207. &ValueSize );
  3208. if ( status ||
  3209. dwType != REG_MULTI_SZ )
  3210. {
  3211. FREE_HEAP( lpTimeouts );
  3212. RegCloseKey( hKey );
  3213. return;
  3214. }
  3215. StringPtr = lpTimeouts;
  3216. while ( ( StringLen = strlen( StringPtr ) ) != 0 &&
  3217. Count < DNS_MAX_QUERY_TIMEOUTS )
  3218. {
  3219. Timeout = atoi( StringPtr );
  3220. if ( Timeout )
  3221. RegistryMulticastQueryTimeouts[Count++] = Timeout;
  3222. StringPtr += (StringLen + 1);
  3223. }
  3224. RegistryMulticastQueryTimeouts[Count] = 0;
  3225. g_MulticastQueryTimeouts = RegistryMulticastQueryTimeouts;
  3226. FREE_HEAP( lpTimeouts );
  3227. }
  3228. }
  3229. RegCloseKey( hKey );
  3230. }
  3231. //
  3232. // OPT selection
  3233. //
  3234. // These routines track DNS server OPT awareness.
  3235. //
  3236. // The paradigm here is to default to sending OPTs, then track
  3237. // OPT non-awareness.
  3238. //
  3239. // DCR: RPC over OPT config info
  3240. // - either two lists (local and from-resolver in process)
  3241. // OR
  3242. // - RPC back OPT failures to resolver
  3243. // OR
  3244. // - flag network info blobs to RPC back to resolver
  3245. //
  3246. // security wise, prefer not to get info back
  3247. //
  3248. //
  3249. // DCR: OPT info in network info
  3250. // - then don't have to traverse locks
  3251. // - save is identical to current
  3252. // - could exclude OPT on any non-cache sends to
  3253. // handle problem of not saving OPT failures
  3254. //
  3255. //
  3256. // Global IP array of OPT-failed DNS servers
  3257. //
  3258. PIP_ARRAY g_OptFailServerList = NULL;
  3259. // Allocation size for OptFail IP array.
  3260. // Ten servers nicely covers the typical case.
  3261. #define OPT_FAIL_LIST_SIZE 10
  3262. //
  3263. // Use global lock for OPT list
  3264. //
  3265. #define LOCK_OPT_LIST() LOCK_GENERAL()
  3266. #define UNLOCK_OPT_LIST() UNLOCK_GENERAL()
  3267. BOOL
  3268. Dns_IsServerOptExclude(
  3269. IN IP4_ADDRESS IpAddress
  3270. )
  3271. /*++
  3272. Routine Description:
  3273. Determine if particular server is not OPT aware.
  3274. Arguments:
  3275. IpAddress -- IP address of DNS server
  3276. Return Value:
  3277. TRUE if server should NOT get OPT send.
  3278. FALSE if server should can send OPT
  3279. --*/
  3280. {
  3281. BOOL retval;
  3282. //
  3283. // zero IP -- meaning TCP connect to unknown
  3284. // => must exclude OPT to allow success, otherwise
  3285. // we can't retry non-OPT
  3286. //
  3287. if ( IpAddress == 0 )
  3288. {
  3289. return TRUE;
  3290. }
  3291. //
  3292. // no exclusions?
  3293. // - doing outside lock for perf once we get to
  3294. // the "fully-deployed" case
  3295. //
  3296. if ( !g_OptFailServerList )
  3297. {
  3298. return FALSE;
  3299. }
  3300. //
  3301. // see if IP is in OPT list
  3302. // - only if found do we exclude
  3303. //
  3304. LOCK_OPT_LIST();
  3305. retval = FALSE;
  3306. if ( g_OptFailServerList
  3307. &&
  3308. Dns_IsAddressInIpArray(
  3309. g_OptFailServerList,
  3310. IpAddress ) )
  3311. {
  3312. retval = TRUE;
  3313. }
  3314. UNLOCK_OPT_LIST();
  3315. return retval;
  3316. }
  3317. VOID
  3318. Dns_SetServerOptExclude(
  3319. IN IP4_ADDRESS IpAddress
  3320. )
  3321. /*++
  3322. Routine Description:
  3323. Set server for OPT exclusion.
  3324. Arguments:
  3325. IpAddress -- IP address of DNS server that failed OPT
  3326. Return Value:
  3327. None
  3328. --*/
  3329. {
  3330. //
  3331. // screen zero IP (TCP connect to unknown IP)
  3332. //
  3333. if ( IpAddress == 0 )
  3334. {
  3335. return;
  3336. }
  3337. //
  3338. // put IP in OPT-fail list
  3339. // - create if doesn't exist
  3340. // - resize if won't fit
  3341. // note: add failure means "won't fit"
  3342. //
  3343. // note: only safe to reset global if allocation successful
  3344. // note: only one retry to protect alloc failure looping
  3345. //
  3346. LOCK_OPT_LIST();
  3347. if ( ! g_OptFailServerList
  3348. ||
  3349. ! Dns_AddIpToIpArray(
  3350. g_OptFailServerList,
  3351. IpAddress ) )
  3352. {
  3353. PIP_ARRAY pnewList;
  3354. pnewList = Dns_CopyAndExpandIpArray(
  3355. g_OptFailServerList,
  3356. OPT_FAIL_LIST_SIZE,
  3357. TRUE // free current
  3358. );
  3359. if ( pnewList )
  3360. {
  3361. g_OptFailServerList = pnewList;
  3362. Dns_AddIpToIpArray(
  3363. g_OptFailServerList,
  3364. IpAddress );
  3365. }
  3366. }
  3367. UNLOCK_OPT_LIST();
  3368. }
  3369. //
  3370. // End send.c
  3371. //