DNSCache.cpp
上传用户:woshihumen
上传日期:2013-07-18
资源大小:484k
文件大小:10k
源码类别:

Email服务器

开发平台:

Visual C++

  1. /*
  2.  *  XMail by Davide Libenzi ( Intranet and Internet mail server )
  3.  *  Copyright (C) 1999,..,2004  Davide Libenzi
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  *
  19.  *  Davide Libenzi <davidel@xmailserver.org>
  20.  *
  21.  */
  22. #include "SysInclude.h"
  23. #include "SysDep.h"
  24. #include "SvrDefines.h"
  25. #include "ShBlocks.h"
  26. #include "ResLocks.h"
  27. #include "StrUtils.h"
  28. #include "BuffSock.h"
  29. #include "SList.h"
  30. #include "MailConfig.h"
  31. #include "MessQueue.h"
  32. #include "MailSvr.h"
  33. #include "MiscUtils.h"
  34. #include "SvrUtils.h"
  35. #include "DNS.h"
  36. #include "DNSCache.h"
  37. #define DNS_CACHE_DIRCTORY      "dnscache"
  38. #define DNS_MX_CACHE_DIRCTORY   "mx"
  39. #define DNS_NS_CACHE_DIRCTORY   "ns"
  40. #define DNS_CACHE_LINE_MAX      2048
  41. static int CDNS_CleanupPath(char const *pszCachePath);
  42. static char *CDNS_GetCacheFilePath(char const *pszDomain, char const *pszSubDir,
  43.    char *pszFilePath);
  44. static int CDNS_MxLoad(char const *pszDomain, char *&pszMXDomains);
  45. static int CDNS_MxSave(char const *pszDomain, char const *pszMXDomains, SYS_UINT32 TTL);
  46. static int iNumCacheDirs = DNS_HASH_NUM_DIRS;
  47. static int CDNS_CleanupPath(char const *pszCachePath)
  48. {
  49. return (0);
  50. }
  51. int CDNS_Initialize(int iCacheDirCount)
  52. {
  53. while (!IsPrimeNumber(iCacheDirCount))
  54. ++iCacheDirCount;
  55. iNumCacheDirs = iCacheDirCount;
  56. ///////////////////////////////////////////////////////////////////////////////
  57. //  Setup cache subdirectories
  58. ///////////////////////////////////////////////////////////////////////////////
  59. char szCacheBasePath[SYS_MAX_PATH] = "";
  60. CfgGetRootPath(szCacheBasePath, sizeof(szCacheBasePath));
  61. StrNCat(szCacheBasePath, DNS_CACHE_DIRCTORY, sizeof(szCacheBasePath));
  62. AppendSlash(szCacheBasePath);
  63. for (int ii = 0; ii < iNumCacheDirs; ii++) {
  64. ///////////////////////////////////////////////////////////////////////////////
  65. //  Setup MX cache subdirectories
  66. ///////////////////////////////////////////////////////////////////////////////
  67. char szCachePath[SYS_MAX_PATH] = "";
  68. sprintf(szCachePath, "%s%s" SYS_SLASH_STR "%d",
  69. szCacheBasePath, DNS_MX_CACHE_DIRCTORY, ii);
  70. if (SysExistDir(szCachePath)) {
  71. if (CDNS_CleanupPath(szCachePath) < 0)
  72. return (ErrGetErrorCode());
  73. } else {
  74. if (SysMakeDir(szCachePath) < 0)
  75. return (ErrGetErrorCode());
  76. }
  77. ///////////////////////////////////////////////////////////////////////////////
  78. //  Setup NS cache subdirectories
  79. ///////////////////////////////////////////////////////////////////////////////
  80. }
  81. return (0);
  82. }
  83. static char *CDNS_GetCacheFilePath(char const *pszDomain, char const *pszSubDir,
  84.    char *pszFilePath)
  85. {
  86. char szRootPath[SYS_MAX_PATH] = "";
  87. CfgGetRootPath(szRootPath, sizeof(szRootPath));
  88. ///////////////////////////////////////////////////////////////////////////////
  89. //  Calculate domain string hash
  90. ///////////////////////////////////////////////////////////////////////////////
  91. char *pszLwrDomain = SysStrDup(pszDomain);
  92. if (pszLwrDomain == NULL)
  93. return (NULL);
  94. StrLower(pszLwrDomain);
  95. SYS_UINT32 uStringHash = MscHashString(pszLwrDomain, strlen(pszLwrDomain));
  96. ///////////////////////////////////////////////////////////////////////////////
  97. //  Build cache file path
  98. ///////////////////////////////////////////////////////////////////////////////
  99. SysSNPrintf(pszFilePath, SYS_MAX_PATH - 1,
  100.     "%s%s" SYS_SLASH_STR "%s" SYS_SLASH_STR "%u" SYS_SLASH_STR "%s", szRootPath,
  101.     DNS_CACHE_DIRCTORY, pszSubDir, (unsigned int) (uStringHash % iNumCacheDirs),
  102.     pszLwrDomain);
  103. SysFree(pszLwrDomain);
  104. return (pszFilePath);
  105. }
  106. static int CDNS_MxLoad(char const *pszDomain, char *&pszMXDomains)
  107. {
  108. ///////////////////////////////////////////////////////////////////////////////
  109. //  Build cached file path
  110. ///////////////////////////////////////////////////////////////////////////////
  111. char szFilePath[SYS_MAX_PATH] = "";
  112. if (CDNS_GetCacheFilePath(pszDomain, DNS_MX_CACHE_DIRCTORY, szFilePath) == NULL)
  113. return (ErrGetErrorCode());
  114. ///////////////////////////////////////////////////////////////////////////////
  115. //  Try to get file infos
  116. ///////////////////////////////////////////////////////////////////////////////
  117. SYS_FILE_INFO FI;
  118. if (SysGetFileInfo(szFilePath, FI) < 0)
  119. return (ErrGetErrorCode());
  120. char szResLock[SYS_MAX_PATH] = "";
  121. RLCK_HANDLE hResLock = RLckLockSH(CfgGetBasedPath(szFilePath, szResLock,
  122.   sizeof(szResLock)));
  123. if (hResLock == INVALID_RLCK_HANDLE)
  124. return (ErrGetErrorCode());
  125. FILE *pCacheFile = fopen(szFilePath, "rt");
  126. if (pCacheFile == NULL) {
  127. RLckUnlockSH(hResLock);
  128. ErrSetErrorCode(ERR_FILE_OPEN);
  129. return (ERR_FILE_OPEN);
  130. }
  131. ///////////////////////////////////////////////////////////////////////////////
  132. //  Read TTL line ( 1st ) and check if it's time expired
  133. ///////////////////////////////////////////////////////////////////////////////
  134. char szCacheLine[DNS_CACHE_LINE_MAX] = "";
  135. if (MscFGets(szCacheLine, sizeof(szCacheLine) - 1, pCacheFile) == NULL) {
  136. fclose(pCacheFile);
  137. RLckUnlockSH(hResLock);
  138. ErrSetErrorCode(ERR_DNS_CACHE_FILE_FMT);
  139. return (ERR_DNS_CACHE_FILE_FMT);
  140. }
  141. unsigned long ulCurTime = (unsigned long) time(NULL);
  142. unsigned long ulTTL = (unsigned long) atol(szCacheLine);
  143. if (ulCurTime > ((unsigned long) FI.tMod + ulTTL)) {
  144. fclose(pCacheFile);
  145. RLckUnlockSH(hResLock);
  146. ErrSetErrorCode(ERR_DNS_CACHE_FILE_EXPIRED);
  147. return (ERR_DNS_CACHE_FILE_EXPIRED);
  148. }
  149. ///////////////////////////////////////////////////////////////////////////////
  150. //  Read MX domains line ( 2nd )
  151. ///////////////////////////////////////////////////////////////////////////////
  152. if (MscFGets(szCacheLine, sizeof(szCacheLine) - 1, pCacheFile) == NULL) {
  153. fclose(pCacheFile);
  154. RLckUnlockSH(hResLock);
  155. ErrSetErrorCode(ERR_DNS_CACHE_FILE_FMT);
  156. return (ERR_DNS_CACHE_FILE_FMT);
  157. }
  158. if ((pszMXDomains = SysStrDup(szCacheLine)) == NULL) {
  159. ErrorPush();
  160. fclose(pCacheFile);
  161. RLckUnlockSH(hResLock);
  162. return (ErrorPop());
  163. }
  164. fclose(pCacheFile);
  165. RLckUnlockSH(hResLock);
  166. return (0);
  167. }
  168. static int CDNS_MxSave(char const *pszDomain, char const *pszMXDomains, SYS_UINT32 TTL)
  169. {
  170. ///////////////////////////////////////////////////////////////////////////////
  171. //  Build cached file path
  172. ///////////////////////////////////////////////////////////////////////////////
  173. char szFilePath[SYS_MAX_PATH] = "";
  174. if (CDNS_GetCacheFilePath(pszDomain, DNS_MX_CACHE_DIRCTORY, szFilePath) == NULL)
  175. return (ErrGetErrorCode());
  176. char szResLock[SYS_MAX_PATH] = "";
  177. RLCK_HANDLE hResLock = RLckLockEX(CfgGetBasedPath(szFilePath, szResLock,
  178.   sizeof(szResLock)));
  179. if (hResLock == INVALID_RLCK_HANDLE)
  180. return (ErrGetErrorCode());
  181. FILE *pCacheFile = fopen(szFilePath, "wt");
  182. if (pCacheFile == NULL) {
  183. RLckUnlockEX(hResLock);
  184. ErrSetErrorCode(ERR_FILE_CREATE, szFilePath);
  185. return (ERR_FILE_CREATE);
  186. }
  187. ///////////////////////////////////////////////////////////////////////////////
  188. //  1st line ( TTL )
  189. ///////////////////////////////////////////////////////////////////////////////
  190. fprintf(pCacheFile, "%lun", (unsigned long) TTL);
  191. ///////////////////////////////////////////////////////////////////////////////
  192. //  2nd line ( MX domains )
  193. ///////////////////////////////////////////////////////////////////////////////
  194. fprintf(pCacheFile, "%sn", pszMXDomains);
  195. fclose(pCacheFile);
  196. RLckUnlockEX(hResLock);
  197. return (0);
  198. }
  199. int CDNS_GetDomainMX(char const *pszDomain, char *&pszMXDomains, char const *pszSmartDNS)
  200. {
  201. ///////////////////////////////////////////////////////////////////////////////
  202. //  Try to get the cached copy
  203. ///////////////////////////////////////////////////////////////////////////////
  204. if (CDNS_MxLoad(pszDomain, pszMXDomains) == 0)
  205. return (0);
  206. ///////////////////////////////////////////////////////////////////////////////
  207. //  If the list of smart DNS hosts is NULL, do a full DNS query
  208. ///////////////////////////////////////////////////////////////////////////////
  209. SYS_UINT32 TTL = 0;
  210. if (pszSmartDNS == NULL) {
  211. char szCName[MAX_HOST_NAME] = "";
  212. int iResult = DNS_GetDomainMX(pszDomain, pszMXDomains,
  213.       szCName, &TTL);
  214. if (iResult < 0) {
  215. if (iResult != ERR_DNS_IS_CNAME)
  216. return (ErrGetErrorCode());
  217. if (DNS_GetDomainMX(szCName, pszMXDomains, NULL, &TTL) < 0)
  218. return (ErrGetErrorCode());
  219. }
  220. return (CDNS_MxSave(pszDomain, pszMXDomains, TTL));
  221. }
  222. ///////////////////////////////////////////////////////////////////////////////
  223. //  Parse the list of smart DNS hosts
  224. ///////////////////////////////////////////////////////////////////////////////
  225. char **ppszTokens = StrTokenize(pszSmartDNS, ",:");
  226. if (ppszTokens == NULL)
  227. return (ErrGetErrorCode());
  228. int iTokensCount = StrStringsCount(ppszTokens);
  229. if (iTokensCount < 2) {
  230. StrFreeStrings(ppszTokens);
  231. ErrSetErrorCode(ERR_BAD_SMARTDNSHOST_SYNTAX);
  232. return (ERR_BAD_SMARTDNSHOST_SYNTAX);
  233. }
  234. ///////////////////////////////////////////////////////////////////////////////
  235. //  Walk through the list of smart DNS hosts to find a DNS response
  236. ///////////////////////////////////////////////////////////////////////////////
  237. for (int ii = 0; ii < (iTokensCount - 1); ii += 2) {
  238. int iQuerySockType =
  239.     (stricmp(ppszTokens[ii + 1], "tcp") == 0) ? DNS_QUERY_TCP : DNS_QUERY_UDP;
  240. if (DNS_GetDomainMXDirect(ppszTokens[ii], pszDomain, iQuerySockType,
  241.   pszMXDomains, &TTL) == 0) {
  242. StrFreeStrings(ppszTokens);
  243. return (CDNS_MxSave(pszDomain, pszMXDomains, TTL));
  244. }
  245. }
  246. StrFreeStrings(ppszTokens);
  247. return (ErrGetErrorCode());
  248. }