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.

441 lines
11 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. // Copyright (c) 2002 Microsoft Corporation
  4. //
  5. // Abstract:
  6. //
  7. // Include file for DNS diagnostic tool.
  8. //
  9. // Author:
  10. //
  11. // gpulla
  12. //
  13. //-----------------------------------------------------------------------------
  14. // IISRTL, ATQ APIs
  15. #include <atq.h>
  16. #include <irtlmisc.h>
  17. // Winsock
  18. #include <winsock2.h>
  19. // DNS API
  20. #include <dns.h>
  21. #include <dnsapi.h>
  22. // Metabase property definitions
  23. #include <smtpinet.h>
  24. #include <iiscnfg.h>
  25. // Metabase COM access APIs
  26. #define INITGUID
  27. #include <iadmw.h>
  28. // DSGetDC
  29. #include <lm.h>
  30. #include <lmapibuf.h>
  31. #include <dsgetdc.h>
  32. // ADSI headers
  33. #include <activeds.h>
  34. // ldap stuff
  35. #include <winldap.h>
  36. // SMTP specific stuff
  37. #include <rwnew.h>
  38. // These #defines are needed for cdns.h
  39. #define MAX_EMAIL_NAME 64
  40. #define MAX_DOMAIN_NAME 250
  41. #define MAX_INTERNET_NAME (MAX_EMAIL_NAME + MAX_DOMAIN_NAME + 2)
  42. #include "cdns.h"
  43. //
  44. // Program return codes and descriptions
  45. // 0 is always success and the other error codes indicate some failure.
  46. //
  47. // The name was resolved successfully to one or more IP addresses.
  48. #define DNSDIAG_RESOLVED 0
  49. // The name could not be resolved due to some unspecified error.
  50. #define DNSDIAG_FAILURE 1
  51. // The name does not exist - a "NOT FOUND" error was returned by a server
  52. // authoritative for the domain in which the name is.
  53. #define DNSDIAG_NON_EXISTENT 2
  54. // The name could not be found in DNS.
  55. #define DNSDIAG_NOT_FOUND 3
  56. // Loopback detected
  57. #define DNSDIAG_LOOPBACK 4
  58. extern int g_nProgramStatus;
  59. //
  60. // Helper function to set the global program return status code to a more
  61. // specific error than the generic DNSDIAG_FAILURE. Note that this is not
  62. // thread-safe.
  63. //
  64. inline void SetProgramStatus(DWORD dwCode)
  65. {
  66. if(g_nProgramStatus == DNSDIAG_FAILURE)
  67. g_nProgramStatus = dwCode;
  68. }
  69. extern DWORD g_cDnsObjects;
  70. //
  71. // handy function for DWORD -> stringized IP conversion.
  72. // inet_ntoa is cumbersome to use directly since the DWORD needs to
  73. // be either cast to an in_addr struct, or copied to an in_addr first
  74. // This function casts the *address* of the DWORD to in_addr ptr, and
  75. // then de-references the pointer to make the cast work, before passing
  76. // it to inet_ntoa. The string returned by inet_ntoa is valid till
  77. // another winsock call is made on the thread (see SDK documentation).
  78. //
  79. inline char *iptostring(DWORD dw)
  80. {
  81. return inet_ntoa(
  82. *( (in_addr *) &dw )
  83. );
  84. }
  85. void PrintIPArray(PIP_ARRAY pipArray, char *pszPrefix = "")
  86. {
  87. for(DWORD i = 0; i < pipArray->cAddrCount; i++)
  88. printf("%s%s\n", pszPrefix, iptostring(pipArray->aipAddrs[i]));
  89. }
  90. //------------------------------------------------------------------------------
  91. // Description:
  92. // Utility function to print descriptions of errors that may occur while
  93. // reading from the metabase.
  94. //
  95. // Arguments:
  96. // IN HRESULT hr - Metabase access error HRESULT
  97. //
  98. // Returns:
  99. // String (static) indicating the error that occurred.
  100. //------------------------------------------------------------------------------
  101. inline const char *MDErrorToString(HRESULT hr)
  102. {
  103. static const DWORD dwErrors[] =
  104. {
  105. ERROR_ACCESS_DENIED,
  106. ERROR_INSUFFICIENT_BUFFER,
  107. ERROR_INVALID_PARAMETER,
  108. ERROR_PATH_NOT_FOUND,
  109. MD_ERROR_DATA_NOT_FOUND
  110. };
  111. static const char *szErrors[] =
  112. {
  113. "ERROR_ACCESS_DENIED",
  114. "ERROR_INSUFFICIENT_BUFFER",
  115. "ERROR_INVALID_PARAMETER",
  116. "ERROR_PATH_NOT_FOUND",
  117. "MD_ERROR_DATA_NOT_FOUND"
  118. };
  119. static const char szUnknown[] = "Unknown Error";
  120. for(int i = 0; i < sizeof(dwErrors)/sizeof(DWORD); i++)
  121. {
  122. if(HRESULT_FROM_WIN32(dwErrors[i]) == hr)
  123. return szErrors[i];
  124. }
  125. return szUnknown;
  126. }
  127. inline const char *QueryType(DWORD dwDnsQueryType)
  128. {
  129. DWORD i = 0;
  130. static const DWORD rgdwQueryTypes[] =
  131. {
  132. DNS_TYPE_MX,
  133. DNS_TYPE_A,
  134. DNS_TYPE_CNAME
  135. };
  136. static const char *rgszQueryTypes[] =
  137. {
  138. "MX",
  139. "A",
  140. "CNAME"
  141. };
  142. static const char szUnknown[] = "Unknown Type";
  143. for(i = 0; i < sizeof(rgdwQueryTypes)/sizeof(DWORD); i++)
  144. {
  145. if(rgdwQueryTypes[i] == dwDnsQueryType)
  146. return rgszQueryTypes[i];
  147. }
  148. return szUnknown;
  149. }
  150. inline void GetSmtpFlags(DWORD dwFlags, char *pszFlags, DWORD cchFlags)
  151. {
  152. if(dwFlags == DNS_FLAGS_TCP_ONLY)
  153. {
  154. _snprintf(pszFlags, cchFlags, " TCP only");
  155. return;
  156. }
  157. if(dwFlags == DNS_FLAGS_UDP_ONLY)
  158. {
  159. _snprintf(pszFlags, cchFlags, " UDP only");
  160. return;
  161. }
  162. if(dwFlags == DNS_FLAGS_NONE)
  163. {
  164. _snprintf(pszFlags, cchFlags, " UDP default, TCP on truncation");
  165. return;
  166. }
  167. _snprintf(pszFlags, cchFlags, " Unknown flag");
  168. }
  169. inline void GetDnsFlags(DWORD dwFlags, char *pszFlags, DWORD cchFlags)
  170. {
  171. DWORD i = 0;
  172. DWORD dwScratchFlags = dwFlags; // Copy of dwFlags: will be overwritten
  173. char *pszStartBuffer = pszFlags;
  174. int cchWritten = 0;
  175. BOOL fFlagsSet = FALSE;
  176. static const DWORD rgdwDnsFlags[] =
  177. {
  178. DNS_QUERY_STANDARD,
  179. DNS_QUERY_USE_TCP_ONLY,
  180. DNS_QUERY_NO_RECURSION,
  181. DNS_QUERY_BYPASS_CACHE,
  182. DNS_QUERY_CACHE_ONLY,
  183. DNS_QUERY_TREAT_AS_FQDN,
  184. };
  185. static const char *rgszDnsFlags[] =
  186. {
  187. "DNS_QUERY_STANDARD",
  188. "DNS_QUERY_USE_TCP_ONLY",
  189. "DNS_QUERY_NO_RECURSION",
  190. "DNS_QUERY_BYPASS_CACHE",
  191. "DNS_QUERY_CACHE_ONLY",
  192. "DNS_QUERY_TREAT_AS_FQDN"
  193. };
  194. for(i = 0; i < sizeof(rgdwDnsFlags)/sizeof(DWORD);i++)
  195. {
  196. if(rgdwDnsFlags[i] & dwScratchFlags)
  197. {
  198. fFlagsSet = TRUE;
  199. dwScratchFlags &= ~rgdwDnsFlags[i];
  200. cchWritten = _snprintf(pszFlags, cchFlags, " %s", rgszDnsFlags[i]);
  201. if(cchWritten < 0)
  202. {
  203. sprintf(pszStartBuffer, " %s", "Error");
  204. return;
  205. }
  206. pszFlags += cchWritten;
  207. cchFlags -= cchWritten;
  208. }
  209. }
  210. if(!fFlagsSet)
  211. sprintf(pszStartBuffer, " %s", "No flags");
  212. if(dwScratchFlags)
  213. sprintf(pszStartBuffer, " %x is %s", dwScratchFlags, "Unknown!");
  214. }
  215. void PrintRecordList(PDNS_RECORD pDnsRecordList, char *pszPrefix = "");
  216. void PrintRecord(PDNS_RECORD pDnsRecord, char *pszPrefix = "");
  217. class CSimpleDnsServerList : public CDnsServerList
  218. {
  219. public:
  220. //
  221. // It is meaningful to have this > 1 only if you have several async queries
  222. // pending at the same time. In the DNS tool only 1 async query is
  223. // outstanding at any given time.
  224. //
  225. DWORD ConnectsAllowedInProbation()
  226. { return 1; }
  227. //
  228. // SMTP actually has 3 retries before failing over, but that is because it
  229. // has dozens of queries going out per minute. If even a small percent of
  230. // those fail due to network errors, DNS servers will be quickly marked down.
  231. // This is not a factor here though.
  232. //
  233. DWORD ErrorsBeforeFailover()
  234. { return 1; }
  235. void LogServerDown(
  236. DWORD dwServerIp,
  237. BOOL fUdp,
  238. DWORD dwErr,
  239. DWORD cUpServers)
  240. { return; }
  241. };
  242. class CAsyncTestDns : public CAsyncMxDns
  243. {
  244. private:
  245. BOOL m_fGlobalList;
  246. HANDLE m_hCompletion;
  247. public:
  248. //
  249. // Custom new/delete operators. They simply call into the global operators,
  250. // but additionally they track the number of DNS objects still "alive". This
  251. // is needed so that we know when we can shutdown ATQ/IISRTL. Terminating
  252. // ATQ/IISRTL before all DNS objects have been completely destructed can mean
  253. // leaked ATQ contexts and all sorts of AV's (and ASSERTS in debug). Note that
  254. // it is inadequate to signal termination in ~CAsyncTestDns, since the base
  255. // class destructor ~CAsyncDns is yet to be called at that point.
  256. //
  257. void *operator new(size_t size)
  258. {
  259. void *pvNew = ::new BYTE[sizeof(CAsyncTestDns)];
  260. InterlockedIncrement((PLONG)&g_cDnsObjects);
  261. return pvNew;
  262. }
  263. void operator delete(void *pv, size_t size)
  264. {
  265. ::delete ((CAsyncTestDns *)pv);
  266. InterlockedDecrement((PLONG)&g_cDnsObjects);
  267. }
  268. CAsyncTestDns(char *pszMyFQDN, BOOL fGlobalList, HANDLE hCompletion)
  269. : CAsyncMxDns(pszMyFQDN),
  270. m_fGlobalList(fGlobalList),
  271. m_hCompletion(hCompletion)
  272. { }
  273. ~CAsyncTestDns();
  274. // virtual functions implemented by us
  275. BOOL RetryAsyncDnsQuery(BOOL fUdp);
  276. void HandleCompletedData(DNS_STATUS status);
  277. BOOL IsShuttingDown()
  278. { return FALSE; }
  279. BOOL IsAddressMine(DWORD dwIp);
  280. };
  281. class CDnsLogToFile : public CDnsLogger
  282. {
  283. public:
  284. // Definitions of virtual functions
  285. void DnsPrintfMsg(char *szFormat, ...);
  286. void DnsPrintfErr(char *szFormat, ...);
  287. void DnsPrintfDbg(char *szFormat, ...);
  288. void DnsLogAsyncQuery(
  289. char *pszQuestionName,
  290. WORD wQuestionType,
  291. DWORD dwFlags,
  292. BOOL fUdp,
  293. CDnsServerList *pDnsServerList);
  294. void DnsLogApiQuery(
  295. char *pszQuestionName,
  296. WORD wQuestionType,
  297. DWORD dwApiFlags,
  298. BOOL fGlobal,
  299. PIP_ARRAY pipServers);
  300. void DnsLogResponse(
  301. DWORD dwStatus,
  302. PDNS_RECORD pDnsRecordList,
  303. PBYTE pbMsg,
  304. DWORD wMessageLength);
  305. // Utility functions
  306. void DnsLogServerList(CDnsServerList *pDnsServerList);
  307. void DnsLogRecordList(PDNS_RECORD pDnsRecordList)
  308. { PrintRecordList(pDnsRecordList); }
  309. void DnsPrintRecord(PDNS_RECORD pDnsRecord)
  310. { PrintRecord(pDnsRecord); }
  311. void DnsPrintIPArray(PIP_ARRAY pipArray)
  312. { PrintIPArray(pipArray); }
  313. };
  314. BOOL ParseCommandLine(
  315. int argc,
  316. char *argv[],
  317. char *pszHostName,
  318. DWORD cchHostName,
  319. CDnsLogToFile **ppDnsLogger,
  320. PIP_ARRAY pipArray,
  321. DWORD cMaxServers,
  322. BOOL *pfUdp,
  323. DWORD *pdwDnsFlags,
  324. BOOL *pfGlobalList,
  325. BOOL *pfTryAllServers);
  326. HRESULT HrGetVsiConfig(
  327. LPSTR pszTargetHost,
  328. DWORD dwVsid,
  329. PDWORD pdwFlags,
  330. PIP_ARRAY pipDnsServers,
  331. DWORD cMaxServers,
  332. BOOL *pfUdp,
  333. BOOL *pfGlobalList,
  334. PIP_ARRAY pipServerBindings,
  335. DWORD cMaxServerBindings);
  336. DWORD IsExchangeInstalled(BOOL *pfInstalled);
  337. DWORD DsGetConfiguration(
  338. char *pszServer,
  339. DWORD dwVsid,
  340. PIP_ARRAY pipDnsServers,
  341. DWORD cMaxServers,
  342. PBOOL pfExternal);
  343. DWORD DsFindExchangeServer(
  344. PLDAP pldap,
  345. LPSTR szBaseDN,
  346. LPSTR szHostDnsName,
  347. LPSTR *ppszServerDN,
  348. BOOL *pfFound);
  349. PLDAP BindToDC();
  350. BOOL GetServerBindings(
  351. WCHAR *pwszMultiSzBindings,
  352. PIP_ARRAY pipServerBindings,
  353. DWORD cMaxServerBindings);
  354. void SetMsgColor();
  355. void SetErrColor();
  356. void SetNormalColor();
  357. void msgprintf(char *szFormat, ...);
  358. void errprintf(char *szFormat, ...);
  359. void dbgprintf(char *szFormat, ...);