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.

549 lines
13 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. servlist.c
  5. Abstract:
  6. Domain Name System (DNS) API
  7. DNS network info routines.
  8. Author:
  9. Jim Gilroy (jamesg) January, 1997
  10. Glenn Curtis (glennc) May, 1997
  11. Revision History:
  12. Jim Gilroy (jamesg) March 2000 slowly cleaning up
  13. --*/
  14. #include "local.h"
  15. #include "registry.h" // Registry reading definitions
  16. //
  17. // Keep copy of DNS server/network info
  18. //
  19. #define CURRENT_ADAPTER_LIST_TIMEOUT (10) // 10 seconds
  20. //
  21. // Registry info
  22. //
  23. #define DNS_REG_READ_BUF_SIZE (1000)
  24. #define LOCALHOST "127.0.0.1"
  25. DNS_STATUS
  26. ParseNameServerList(
  27. IN OUT PIP_ARRAY aipServers,
  28. IN LPSTR pBuffer,
  29. IN BOOL IsMultiSzString
  30. )
  31. /*++
  32. Routine Description:
  33. Parse DNS server list from registry into IP address array.
  34. Arguments:
  35. aipServers -- IP array of DNS servers
  36. pBuffer -- buffer with IP addresses in dotted format
  37. IsMultiSzString -- Determines how to interpret data in buffer
  38. Return Value:
  39. ERROR_SUCCESS if successful.
  40. Error code on failure.
  41. --*/
  42. {
  43. DWORD stringLength;
  44. LPSTR pstring;
  45. DWORD cchBufferSize = 0;
  46. CHAR ch;
  47. PUCHAR pchIpString;
  48. IP_ADDRESS ip;
  49. DWORD countServers = aipServers->AddrCount;
  50. DNSDBG( NETINFO, (
  51. "Parsing name server list %s\n",
  52. pBuffer ));
  53. //
  54. // MULTI_SZ string
  55. //
  56. // IPs are given as individual strings with double NULL termination
  57. //
  58. if ( IsMultiSzString )
  59. {
  60. pstring = pBuffer;
  61. while ( ( stringLength = strlen( pstring ) ) != 0 &&
  62. countServers < DNS_MAX_NAME_SERVERS )
  63. {
  64. ip = inet_addr( pstring );
  65. if ( ip != INADDR_ANY && ip != INADDR_NONE )
  66. {
  67. aipServers->AddrArray[ countServers ] = ip;
  68. countServers++;
  69. }
  70. pstring += (stringLength + 1);
  71. }
  72. }
  73. else
  74. {
  75. //
  76. // extract each IP string in buffer, convert to IP address,
  77. // and add to server IP array
  78. //
  79. cchBufferSize = strlen( pBuffer );
  80. while( ch = *pBuffer && countServers < DNS_MAX_NAME_SERVERS )
  81. {
  82. // skip leading whitespace, find start of IP string
  83. while( cchBufferSize > 0 &&
  84. ( ch == ' ' || ch == '\t' || ch == ',' ) )
  85. {
  86. ch = *++pBuffer;
  87. cchBufferSize--;
  88. }
  89. pchIpString = pBuffer;
  90. //
  91. // find end of string and NULL terminate
  92. //
  93. ch = *pBuffer;
  94. while( cchBufferSize > 0 &&
  95. ( ch != ' ' && ch != '\t' && ch != '\0' && ch != ',' ) )
  96. {
  97. ch = *++pBuffer;
  98. cchBufferSize--;
  99. }
  100. *pBuffer = '\0';
  101. // at end of buffer
  102. if ( pBuffer == pchIpString )
  103. {
  104. DNS_ASSERT( cchBufferSize == 1 || cchBufferSize == 0 );
  105. break;
  106. }
  107. //
  108. // get IP address for string
  109. // - zero or broadcast addresses are bogus
  110. //
  111. ip = inet_addr( pchIpString );
  112. if ( ip == INADDR_ANY || ip == INADDR_NONE )
  113. {
  114. break;
  115. }
  116. aipServers->AddrArray[ countServers ] = ip;
  117. countServers++;
  118. // if more continue
  119. if ( cchBufferSize > 0 )
  120. {
  121. pBuffer++;
  122. cchBufferSize--;
  123. continue;
  124. }
  125. break;
  126. }
  127. }
  128. // reset server count
  129. aipServers->AddrCount = countServers;
  130. if ( aipServers->AddrCount )
  131. {
  132. return( ERROR_SUCCESS );
  133. }
  134. else
  135. {
  136. return( DNS_ERROR_NO_DNS_SERVERS );
  137. }
  138. }
  139. //
  140. // Network info structure routines
  141. //
  142. #if 0
  143. PSEARCH_LIST
  144. Dns_GetDnsSearchList(
  145. IN LPSTR pszPrimaryDomainName,
  146. IN HKEY hKey,
  147. IN PDNS_NETINFO pNetworkInfo,
  148. IN BOOL fUseDomainNameDevolution,
  149. IN BOOL fUseDotLocalDomain
  150. )
  151. /*++
  152. Dumb stub because this function is exposed in dnslib.h
  153. and in stmpdns\servlist.cpp in iis project
  154. DCR: eliminate this routine (stupid)
  155. --*/
  156. {
  157. return SearchList_Build(
  158. pszPrimaryDomainName,
  159. NULL, // no reg session
  160. hKey,
  161. pNetworkInfo,
  162. fUseDomainNameDevolution,
  163. fUseDotLocalDomain );
  164. }
  165. #endif
  166. VOID
  167. Dns_ResetNetworkInfo(
  168. IN PDNS_NETINFO pNetworkInfo
  169. )
  170. /*++
  171. Routine Description:
  172. Clear the flags for each adapter.
  173. Arguments:
  174. pNetworkInfo -- pointer to a DNS network info structure.
  175. Return Value:
  176. Nothing
  177. --*/
  178. {
  179. DWORD iter;
  180. DNSDBG( TRACE, ( "Dns_ResetNetworkInfo()\n" ));
  181. if ( ! pNetworkInfo )
  182. {
  183. return;
  184. }
  185. for ( iter = 0; iter < pNetworkInfo->AdapterCount; iter++ )
  186. {
  187. pNetworkInfo->AdapterArray[iter]->RunFlags = 0;
  188. }
  189. pNetworkInfo->ReturnFlags = 0;
  190. }
  191. BOOL
  192. Dns_DisableTimedOutAdapters(
  193. IN OUT PDNS_NETINFO pNetworkInfo
  194. )
  195. /*++
  196. Routine Description:
  197. For each adapter with status ERROR_TIMEOUT, disable it from
  198. further retry queries till Dns_ResetNetworkInfo is called.
  199. Arguments:
  200. pNetworkInfo -- pointer to a DNS network info structure.
  201. Return Value:
  202. True if a timed out adapter was found and disabled
  203. --*/
  204. {
  205. DWORD iter;
  206. PDNS_ADAPTER padapter;
  207. BOOL fSetAdapter = FALSE;
  208. DNSDBG( TRACE, ( "Dns_DisableTimedOutAdapters()\n" ));
  209. if ( ! pNetworkInfo )
  210. {
  211. return FALSE;
  212. }
  213. for ( iter = 0; iter < pNetworkInfo->AdapterCount; iter++ )
  214. {
  215. padapter = pNetworkInfo->AdapterArray[iter];
  216. if ( padapter->Status == ERROR_TIMEOUT )
  217. {
  218. //
  219. // See if the given adapters are really timing out or not.
  220. //
  221. // Sometimes a given name query will take a long time and
  222. // we timeout waiting for the response, though the server
  223. // will quicky respond to other name queries. Other times
  224. // the default gateway doesn't let us reach the DNS servers
  225. // on a given adapter, or they are plain dead.
  226. //
  227. // Pinging the given DNS servers to see if they can respond
  228. // to a simple query helps to avoid the confusion.
  229. //
  230. if ( !Dns_PingAdapterServers( padapter ) )
  231. {
  232. padapter->RunFlags |= RUN_FLAG_IGNORE_ADAPTER;
  233. padapter->RunFlags |= RUN_FLAG_RESET_SERVER_PRIORITY;
  234. fSetAdapter = TRUE;
  235. }
  236. }
  237. }
  238. if ( fSetAdapter )
  239. {
  240. pNetworkInfo->ReturnFlags = RUN_FLAG_RESET_SERVER_PRIORITY;
  241. }
  242. return fSetAdapter;
  243. }
  244. BOOL
  245. Dns_ShouldNameErrorBeCached(
  246. IN PDNS_NETINFO pNetworkInfo
  247. )
  248. /*++
  249. Routine Description:
  250. This routine is used in conjuction with a given query's NAME_ERROR
  251. response to see if the error was one that occured on all adapters.
  252. This is used to decide if the name error response should be cached
  253. or not. If the machine was multihomed, and one of the adapters had
  254. a timeout error, then the name error should not be cached as a
  255. negative response.
  256. Arguments:
  257. pNetworkInfo -- pointer to a DNS network info structure.
  258. Return Value:
  259. False if a timed out adapter was found, and name error should not
  260. be negatively cached.
  261. --*/
  262. {
  263. DWORD iter;
  264. PDNS_ADAPTER padapter;
  265. DNSDBG( TRACE, ( "Dns_DidNameErrorOccurEverywhere()\n" ));
  266. if ( ! pNetworkInfo )
  267. {
  268. return TRUE;
  269. }
  270. if ( pNetworkInfo->ReturnFlags & RUN_FLAG_RESET_SERVER_PRIORITY )
  271. {
  272. for ( iter = 0; iter < pNetworkInfo->AdapterCount; iter++ )
  273. {
  274. padapter = pNetworkInfo->AdapterArray[iter];
  275. if ( !( padapter->InfoFlags & DNS_FLAG_IGNORE_ADAPTER ) &&
  276. padapter->Status == ERROR_TIMEOUT )
  277. {
  278. return FALSE;
  279. }
  280. }
  281. }
  282. return TRUE;
  283. }
  284. BOOL
  285. Dns_PingAdapterServers(
  286. IN PDNS_ADAPTER pAdapterInfo
  287. )
  288. //
  289. // DCR: Dns_PingAdapterServers() is stupid
  290. // why are we doing this?
  291. //
  292. {
  293. BOOL fPing = TRUE;
  294. PDNS_NETINFO pnetworkInfo = NULL;
  295. PDNS_ADAPTER padapterCopy = NULL;
  296. DNS_STATUS Status = NO_ERROR;
  297. DNSDBG( TRACE, ( "Dns_PingAdapterServers()\n" ));
  298. pnetworkInfo = NetInfo_Alloc( 1 );
  299. if ( !pnetworkInfo )
  300. {
  301. return FALSE;
  302. }
  303. padapterCopy = AdapterInfo_Copy( pAdapterInfo );
  304. if ( !padapterCopy )
  305. {
  306. NetInfo_Free( pnetworkInfo );
  307. return FALSE;
  308. }
  309. padapterCopy->InfoFlags = DNS_FLAG_IS_AUTONET_ADAPTER;
  310. NetInfo_AddAdapter(
  311. pnetworkInfo,
  312. padapterCopy );
  313. //
  314. // query adapter's DNS servers
  315. // - query for loopback which always exists
  316. //
  317. Status = QueryDirectEx(
  318. NULL, // no message
  319. NULL, // no results
  320. NULL, // no header
  321. 0, // no header counts
  322. "1.0.0.127.in-addr.arpa.",
  323. DNS_TYPE_PTR,
  324. NULL, // no input records
  325. DNS_QUERY_ACCEPT_PARTIAL_UDP |
  326. DNS_QUERY_NO_RECURSION,
  327. NULL, // no server list
  328. pnetworkInfo );
  329. NetInfo_Free( pnetworkInfo );
  330. if ( Status == ERROR_TIMEOUT )
  331. {
  332. fPing = FALSE;
  333. }
  334. return fPing;
  335. }
  336. #if 0
  337. //
  338. // this is some stuff Glenn wrote for the case where you
  339. // don't have a DNS server list and will get it through mcast
  340. //
  341. // it was in the middle of the NetworkInfo building routine
  342. //
  343. else
  344. {
  345. //
  346. // DCR: functionalize multicast query attempt
  347. //
  348. //
  349. // See if we can find a DNS server address to put on this
  350. // adapter by multicasting for it . . .
  351. //
  352. // LevonE is still debating this method for
  353. // server detection. If this is ultimately utilized, it
  354. // might be better to direct the multicast query out the
  355. // specific adapter IP address to try to get an address
  356. // relevant to the specific adapter's network. This
  357. // could be done by building a dummy pNetworkInfo
  358. // parameter to pass down to Dns_QueryLib. The helper
  359. // routine Dns_SendAndRecvMulticast could be revised to
  360. // support specific adapter multicasting, etc.
  361. PDNS_RECORD pServer = NULL;
  362. status = Dns_QueryLib(
  363. NULL,
  364. &pServer,
  365. (PDNS_NAME) MULTICAST_DNS_SRV_RECORD_NAME,
  366. DNS_TYPE_SRV,
  367. DNS_QUERY_MULTICAST_ONLY,
  368. NULL,
  369. NULL, // May want to specify network!
  370. 0 );
  371. if ( status )
  372. {
  373. //
  374. // This adapter is not going to have any configured
  375. // DNS servers. No point trying any DNS queries on
  376. // it then.
  377. //
  378. adapterFlags |= DNS_FLAG_IGNORE_ADAPTER;
  379. }
  380. else
  381. {
  382. if ( pServer &&
  383. pServer->Flags.S.Section == DNSREC_ANSWER &&
  384. pServer->wType == DNS_TYPE_SRV &&
  385. pServer->Data.SRV.wPort == DNS_PORT_HOST_ORDER )
  386. {
  387. PDNS_RECORD pNext = pServer->pNext;
  388. while ( pNext )
  389. {
  390. if ( pNext->Flags.S.Section == DNSREC_ADDITIONAL &&
  391. pNext->wType == DNS_TYPE_A &&
  392. Dns_NameCompare( pServer ->
  393. Data.SRV.pNameTarget,
  394. pNext->pName ) )
  395. {
  396. pserverIpArray->AddrCount = 1;
  397. pserverIpArray->AddrArray[0] =
  398. pNext->Data.A.IpAddress;
  399. adapterFlags |= DNS_FLAG_AUTO_SERVER_DETECTED;
  400. break;
  401. }
  402. pNext = pNext->pNext;
  403. }
  404. }
  405. Dns_RecordListFree( pServer );
  406. if ( pserverIpArray->AddrCount == 0 )
  407. {
  408. //
  409. // This adapter is not going to have any configured
  410. // DNS servers. No point trying any DNS queries on
  411. // it then.
  412. //
  413. adapterFlags |= DNS_FLAG_IGNORE_ADAPTER;
  414. }
  415. }
  416. }
  417. #endif // multicast attempt
  418. //
  419. // End servlist.c
  420. //