Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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