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

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 "StrUtils.h"
  27. #include "BuffSock.h"
  28. #include "SList.h"
  29. #include "MailConfig.h"
  30. #include "MessQueue.h"
  31. #include "MailSvr.h"
  32. #include "MiscUtils.h"
  33. #include "SvrUtils.h"
  34. #include "DNS.h"
  35. #define DNS_PORTNO              53
  36. #define DNS_SOCKET_TIMEOUT      16
  37. #define DNS_QUERY_EXTRA         512
  38. #define DNS_MAX_RESP_PACKET     1024
  39. #define DNS_SEND_RETRIES        3
  40. #define DNS_MAX_RR_DATA         256
  41. #define DNS_RESPDATA_EXTRA      (2 * sizeof(int))
  42. #if defined(BIG_ENDIAN_CPU)
  43. #define DNS_LABEL_LEN_MASK      0x3fff
  44. #else // #if defined(BIG_ENDIAN_CPU)
  45. #define DNS_LABEL_LEN_MASK      0xff3f
  46. #endif // #if defined(BIG_ENDIAN_CPU)
  47. #define DNS_LABEL_LEN_INVMASK   0xc0
  48. #define ROOTS_FILE              "dnsroots"
  49. struct DNSQuery {
  50. DNS_HEADER DNSH;
  51. SYS_UINT8 QueryData[DNS_QUERY_EXTRA];
  52. };
  53. struct DNSResourceRecord {
  54. char szName[MAX_HOST_NAME];
  55. SYS_UINT16 Type;
  56. SYS_UINT16 Class;
  57. SYS_UINT32 TTL;
  58. SYS_UINT16 Lenght;
  59. SYS_UINT8 const *pRespData;
  60. };
  61. struct DNSNameNode {
  62. LISTLINK LL;
  63. char *pszServer;
  64. char *pszQuery;
  65. };
  66. static SYS_UINT8 *DNS_AllocRespData(int iSize);
  67. static int DNS_FreeRespData(SYS_UINT8 * pRespData);
  68. static int DNS_RespDataSize(SYS_UINT8 const *pRespData);
  69. static DNSNameNode *DNS_AllocNameNode(char const *pszServer, char const *pszQuery);
  70. static void DNS_FreeNameNode(DNSNameNode * pDNSNN);
  71. static void DNS_FreeNameList(HSLIST & hNameList);
  72. static DNSNameNode *DNS_GetNameNode(HSLIST & hNameList, char const *pszServer,
  73.     char const *pszQuery);
  74. static int DNS_AddNameNode(HSLIST & hNameList, char const *pszServer, char const *pszQuery);
  75. static int DNS_GetResourceRecord(SYS_UINT8 const *pBaseData, SYS_UINT8 const *pRespData,
  76.  DNSResourceRecord * pRR = NULL, int *piRRLength = NULL);
  77. static int DNS_GetName(SYS_UINT8 const *pBaseData, SYS_UINT8 const *pRespData,
  78.        char *pszInetName = NULL, int *piRRLength = NULL);
  79. static int DNS_GetQuery(SYS_UINT8 const *pBaseData, SYS_UINT8 const *pRespData,
  80. char *pszInetName = NULL, SYS_UINT16 * pType = NULL,
  81. SYS_UINT16 * pClass = NULL, int *piRRLength = NULL);
  82. static int DNS_NameCopy(SYS_UINT8 * pDNSQName, char const *pszInetName);
  83. static SYS_UINT16 DNS_GetUniqueQueryId(void);
  84. static int DNS_RequestSetup(DNSQuery & DNSQ, unsigned int uOpCode,
  85.     unsigned int uQType, char const *pszInetName,
  86.     int &iQueryLenght, bool bQueryRecursion = false);
  87. static SYS_UINT8 *DNS_QueryExec(char const *pszDNSServer, int iPortNo, int iTimeout,
  88. unsigned int uOpCode, unsigned int uQType,
  89. char const *pszInetName, bool bQueryRecursion = false);
  90. static SYS_UINT8 *DNS_QuerySendStream(char const *pszDNSServer, int iPortNo, int iTimeout,
  91.       DNSQuery const &DNSQ, int iQueryLenght);
  92. static SYS_UINT8 *DNS_QuerySendDGram(char const *pszDNSServer, int iPortNo, int iTimeout,
  93.      DNSQuery const &DNSQ, int iQueryLenght, bool & bTruncated);
  94. static int DNS_DecodeResponseMX(SYS_UINT8 * pRespData, char const *pszDomain,
  95. HSLIST & hNameList, char const *pszRespFile,
  96. char *pszCName, SYS_UINT32 * pTTL = NULL);
  97. static int DNS_DecodeDirResponseMX(SYS_UINT8 * pRespData, char const *pszRespFile,
  98.    SYS_UINT32 * pTTL = NULL);
  99. static int DNS_DecodeResponseNS(SYS_UINT8 * pRespData, char const *pszRespFile,
  100. bool & bAuth, char *pszCName, SYS_UINT32 * pTTL = NULL);
  101. static int DNS_FindDomainMX(char const *pszDNSServer, char const *pszDomain,
  102.     HSLIST & hNameList, char const *pszRespFile, char *pszCName,
  103.     SYS_UINT32 * pTTL = NULL);
  104. static int DNS_QueryDomainMX(char const *pszDNSServer, char const *pszDomain,
  105.      char *&pszMXDomains, char *pszCName, SYS_UINT32 * pTTL = NULL);
  106. static int DNS_AppendHosts(FILE *pFile, char const *pszDestPath);
  107. static int DNS_GetNameServersLL(char const *pszDNSServer, char const *pszDomain,
  108. char const *pszRespFile, HSLIST & hNameList,
  109. char *pszCName, SYS_UINT32 * pTTL = NULL);
  110. static char *DNS_GetRootsFile(char *pszRootsFilePath, int iMaxPath);
  111. static SYS_UINT8 *DNS_AllocRespData(int iSize)
  112. {
  113. int iSizeExtra = DNS_RESPDATA_EXTRA;
  114. SYS_UINT8 *pBaseData = (SYS_UINT8 *) SysAlloc(iSize + iSizeExtra);
  115. if (pBaseData == NULL)
  116. return (NULL);
  117. ((int *) pBaseData)[0] = iSize;
  118. return (pBaseData + iSizeExtra);
  119. }
  120. static int DNS_FreeRespData(SYS_UINT8 * pRespData)
  121. {
  122. SYS_UINT8 *pBaseData = pRespData - DNS_RESPDATA_EXTRA;
  123. SysFree(pBaseData);
  124. return (0);
  125. }
  126. static int DNS_RespDataSize(SYS_UINT8 const *pRespData)
  127. {
  128. SYS_UINT8 const *pBaseData = pRespData - DNS_RESPDATA_EXTRA;
  129. return (((int *) pBaseData)[0]);
  130. }
  131. static DNSNameNode *DNS_AllocNameNode(char const *pszServer, char const *pszQuery)
  132. {
  133. DNSNameNode *pDNSNN = (DNSNameNode *) SysAlloc(sizeof(DNSNameNode));
  134. if (pDNSNN == NULL)
  135. return (NULL);
  136. ListLinkInit(pDNSNN);
  137. if ((pDNSNN->pszServer = SysStrDup(pszServer)) == NULL) {
  138. SysFree(pDNSNN);
  139. return (NULL);
  140. }
  141. if ((pDNSNN->pszQuery = SysStrDup(pszQuery)) == NULL) {
  142. SysFree(pDNSNN->pszServer);
  143. SysFree(pDNSNN);
  144. return (NULL);
  145. }
  146. return (pDNSNN);
  147. }
  148. static void DNS_FreeNameNode(DNSNameNode * pDNSNN)
  149. {
  150. SysFree(pDNSNN->pszQuery);
  151. SysFree(pDNSNN->pszServer);
  152. SysFree(pDNSNN);
  153. }
  154. static void DNS_FreeNameList(HSLIST & hNameList)
  155. {
  156. DNSNameNode *pDNSNN;
  157. while ((pDNSNN = (DNSNameNode *) ListRemove(hNameList)) != INVALID_SLIST_PTR)
  158. DNS_FreeNameNode(pDNSNN);
  159. }
  160. static DNSNameNode *DNS_GetNameNode(HSLIST & hNameList, char const *pszServer,
  161.     char const *pszQuery)
  162. {
  163. DNSNameNode *pDNSNN = (DNSNameNode *) ListFirst(hNameList);
  164. for (; pDNSNN != INVALID_SLIST_PTR; pDNSNN = (DNSNameNode *)
  165.      ListNext(hNameList, (PLISTLINK) pDNSNN))
  166. if ((stricmp(pDNSNN->pszServer, pszServer) == 0) &&
  167.     (stricmp(pDNSNN->pszQuery, pszQuery) == 0))
  168. return (pDNSNN);
  169. return (NULL);
  170. }
  171. static int DNS_AddNameNode(HSLIST & hNameList, char const *pszServer, char const *pszQuery)
  172. {
  173. DNSNameNode *pDNSNN = DNS_AllocNameNode(pszServer, pszQuery);
  174. if (pDNSNN == NULL)
  175. return (ErrGetErrorCode());
  176. ListAddTail(hNameList, (PLISTLINK) pDNSNN);
  177. return (0);
  178. }
  179. static int DNS_GetResourceRecord(SYS_UINT8 const *pBaseData, SYS_UINT8 const *pRespData,
  180.  DNSResourceRecord * pRR, int *piRRLength)
  181. {
  182. if (pRR != NULL)
  183. ZeroData(*pRR);
  184. ///////////////////////////////////////////////////////////////////////////////
  185. //  Read name field
  186. ///////////////////////////////////////////////////////////////////////////////
  187. int iRRLen = 0;
  188. char *pszName = (pRR != NULL) ? pRR->szName : NULL;
  189. if (DNS_GetName(pBaseData, pRespData, pszName, &iRRLen) < 0)
  190. return (ErrGetErrorCode());
  191. pRespData += iRRLen;
  192. ///////////////////////////////////////////////////////////////////////////////
  193. //  Read type field
  194. ///////////////////////////////////////////////////////////////////////////////
  195. if (pRR != NULL)
  196. pRR->Type = ntohs(MscReadUint16(pRespData));
  197. pRespData += sizeof(SYS_UINT16);
  198. iRRLen += sizeof(SYS_UINT16);
  199. ///////////////////////////////////////////////////////////////////////////////
  200. //  Read class field
  201. ///////////////////////////////////////////////////////////////////////////////
  202. if (pRR != NULL)
  203. pRR->Class = ntohs(MscReadUint16(pRespData));
  204. pRespData += sizeof(SYS_UINT16);
  205. iRRLen += sizeof(SYS_UINT16);
  206. ///////////////////////////////////////////////////////////////////////////////
  207. //  Read TTL field
  208. ///////////////////////////////////////////////////////////////////////////////
  209. if (pRR != NULL)
  210. pRR->TTL = ntohl(MscReadUint32(pRespData));
  211. pRespData += sizeof(SYS_UINT32);
  212. iRRLen += sizeof(SYS_UINT32);
  213. ///////////////////////////////////////////////////////////////////////////////
  214. //  Read lenght field
  215. ///////////////////////////////////////////////////////////////////////////////
  216. SYS_UINT16 Lenght = ntohs(MscReadUint16(pRespData));
  217. if (pRR != NULL)
  218. pRR->Lenght = Lenght;
  219. pRespData += sizeof(SYS_UINT16);
  220. iRRLen += sizeof(SYS_UINT16);
  221. ///////////////////////////////////////////////////////////////////////////////
  222. //  Read RR data
  223. ///////////////////////////////////////////////////////////////////////////////
  224. if (pRR != NULL)
  225. pRR->pRespData = pRespData;
  226. iRRLen += (int) Lenght;
  227. if (piRRLength != NULL)
  228. *piRRLength = iRRLen;
  229. return (0);
  230. }
  231. static int DNS_GetName(SYS_UINT8 const *pBaseData, SYS_UINT8 const *pRespData,
  232.        char *pszInetName, int *piRRLength)
  233. {
  234. char szNameBuffer[MAX_HOST_NAME] = "";
  235. if (pszInetName == NULL)
  236. pszInetName = szNameBuffer;
  237. int iBaseLength = DNS_RespDataSize(pBaseData);
  238. int iCurrOffset = (int) (pRespData - pBaseData);
  239. int iDataLength = 0;
  240. int iNameLength = 0;
  241. int iBackLink = 0;
  242. while (*pRespData != 0) {
  243. if (*pRespData & DNS_LABEL_LEN_INVMASK) {
  244. ///////////////////////////////////////////////////////////////////////////////
  245. //  Got displacement from base-data ( boundary checked )
  246. ///////////////////////////////////////////////////////////////////////////////
  247. if ((iCurrOffset = (int)
  248.      ntohs(MscReadUint16(pRespData) & DNS_LABEL_LEN_MASK)) >= iBaseLength) {
  249. ErrSetErrorCode(ERR_BAD_DNS_NAME_RECORD);
  250. return (ERR_BAD_DNS_NAME_RECORD);
  251. }
  252. pRespData = pBaseData + iCurrOffset;
  253. if (!iBackLink)
  254. iDataLength += sizeof(SYS_UINT16), ++iBackLink;
  255. continue;
  256. }
  257. ///////////////////////////////////////////////////////////////////////////////
  258. //  Extract label length ( boundary checked )
  259. ///////////////////////////////////////////////////////////////////////////////
  260. int iLabelLength = (int) *pRespData;
  261. if (((iNameLength + iLabelLength + 2) >= MAX_HOST_NAME) ||
  262.     ((iCurrOffset + iLabelLength + 1) >= iBaseLength)) {
  263. ErrSetErrorCode(ERR_BAD_DNS_NAME_RECORD);
  264. return (ERR_BAD_DNS_NAME_RECORD);
  265. }
  266. ///////////////////////////////////////////////////////////////////////////////
  267. //  Append to name and update pointers
  268. ///////////////////////////////////////////////////////////////////////////////
  269. memcpy(pszInetName, pRespData + 1, iLabelLength);
  270. pszInetName[iLabelLength] = '.';
  271. iNameLength += iLabelLength + 1;
  272. pszInetName += iLabelLength + 1;
  273. ///////////////////////////////////////////////////////////////////////////////
  274. //  If we've not got a back-jump, update the data length
  275. ///////////////////////////////////////////////////////////////////////////////
  276. if (!iBackLink)
  277. iDataLength += iLabelLength + 1;
  278. ///////////////////////////////////////////////////////////////////////////////
  279. //  Move pointers
  280. ///////////////////////////////////////////////////////////////////////////////
  281. iCurrOffset += iLabelLength + 1;
  282. pRespData += iLabelLength + 1;
  283. }
  284. *pszInetName = '';
  285. if (piRRLength != NULL)
  286. *piRRLength = (!iBackLink) ? iDataLength + 1 : iDataLength;
  287. return (0);
  288. }
  289. static int DNS_GetQuery(SYS_UINT8 const *pBaseData, SYS_UINT8 const *pRespData,
  290. char *pszInetName, SYS_UINT16 * pType, SYS_UINT16 * pClass,
  291. int *piRRLength)
  292. {
  293. ///////////////////////////////////////////////////////////////////////////////
  294. //  Read name field
  295. ///////////////////////////////////////////////////////////////////////////////
  296. int iQueryLen = 0;
  297. if (DNS_GetName(pBaseData, pRespData, pszInetName, &iQueryLen) < 0)
  298. return (ErrGetErrorCode());
  299. pRespData += iQueryLen;
  300. ///////////////////////////////////////////////////////////////////////////////
  301. //  Read type field
  302. ///////////////////////////////////////////////////////////////////////////////
  303. if (pType != NULL)
  304. *pType = ntohs(MscReadUint16(pRespData));
  305. pRespData += sizeof(SYS_UINT16);
  306. iQueryLen += sizeof(SYS_UINT16);
  307. ///////////////////////////////////////////////////////////////////////////////
  308. //  Read class field
  309. ///////////////////////////////////////////////////////////////////////////////
  310. if (pClass != NULL)
  311. *pClass = ntohs(MscReadUint16(pRespData));
  312. pRespData += sizeof(SYS_UINT16);
  313. iQueryLen += sizeof(SYS_UINT16);
  314. if (piRRLength != NULL)
  315. *piRRLength = iQueryLen;
  316. return (0);
  317. }
  318. static int DNS_NameCopy(SYS_UINT8 * pDNSQName, char const *pszInetName)
  319. {
  320. char *pszNameCopy = SysStrDup(pszInetName);
  321. if (pszNameCopy == NULL)
  322. return (ErrGetErrorCode());
  323. int iNameLen = 0;
  324. char *pszToken = NULL;
  325. char *pszSavePtr = NULL;
  326. pszToken = SysStrTok(pszNameCopy, ".", &pszSavePtr);
  327. while (pszToken != NULL) {
  328. int iTokLen = strlen(pszToken);
  329. *pDNSQName = (SYS_UINT8) iTokLen;
  330. strcpy((char *) pDNSQName + 1, pszToken);
  331. pDNSQName += iTokLen + 1;
  332. iNameLen += iTokLen + 1;
  333. pszToken = SysStrTok(NULL, ".", &pszSavePtr);
  334. }
  335. *pDNSQName = 0;
  336. SysFree(pszNameCopy);
  337. return (iNameLen + 1);
  338. }
  339. static SYS_UINT16 DNS_GetUniqueQueryId(void)
  340. {
  341. static SYS_UINT16 uDnsQueryId = 0;
  342. return ((SYS_UINT16) (++uDnsQueryId * SysGetCurrentThreadId()));
  343. }
  344. static int DNS_RequestSetup(DNSQuery & DNSQ, unsigned int uOpCode,
  345.     unsigned int uQType, char const *pszInetName,
  346.     int &iQueryLenght, bool bQueryRecursion)
  347. {
  348. ///////////////////////////////////////////////////////////////////////////////
  349. //  Setup query header
  350. ///////////////////////////////////////////////////////////////////////////////
  351. ZeroData(DNSQ);
  352. DNSQ.DNSH.Id = DNS_GetUniqueQueryId();
  353. DNSQ.DNSH.QR = 0;
  354. DNSQ.DNSH.RD = (bQueryRecursion) ? 1 : 0;
  355. DNSQ.DNSH.OpCode = uOpCode;
  356. DNSQ.DNSH.QDCount = htons(1);
  357. DNSQ.DNSH.ANCount = htons(0);
  358. DNSQ.DNSH.NSCount = htons(0);
  359. DNSQ.DNSH.ARCount = htons(0);
  360. SYS_UINT8 *pQueryData = DNSQ.QueryData;
  361. ///////////////////////////////////////////////////////////////////////////////
  362. //  Copy name to query
  363. ///////////////////////////////////////////////////////////////////////////////
  364. int iNameLen = DNS_NameCopy(pQueryData, pszInetName);
  365. if (iNameLen < 0)
  366. return (ErrGetErrorCode());
  367. pQueryData += iNameLen;
  368. ///////////////////////////////////////////////////////////////////////////////
  369. //  Set query type
  370. ///////////////////////////////////////////////////////////////////////////////
  371. MscWriteUint16(pQueryData, (SYS_UINT16) htons(uQType));
  372. pQueryData += sizeof(SYS_UINT16);
  373. ///////////////////////////////////////////////////////////////////////////////
  374. //  Set query class
  375. ///////////////////////////////////////////////////////////////////////////////
  376. MscWriteUint16(pQueryData, (SYS_UINT16) htons(QCLASS_IN));
  377. pQueryData += sizeof(SYS_UINT16);
  378. iQueryLenght = (int) (pQueryData - (SYS_UINT8 *) & DNSQ);
  379. return (0);
  380. }
  381. static SYS_UINT8 *DNS_QueryExec(char const *pszDNSServer, int iPortNo, int iTimeout,
  382. unsigned int uOpCode, unsigned int uQType,
  383. char const *pszInetName, bool bQueryRecursion)
  384. {
  385. int iQueryLenght;
  386. DNSQuery DNSQ;
  387. if (DNS_RequestSetup(DNSQ, uOpCode, uQType, pszInetName, iQueryLenght,
  388.      bQueryRecursion) < 0)
  389. return (NULL);
  390. bool bTruncated = false;
  391. SYS_UINT8 *pRespData = DNS_QuerySendDGram(pszDNSServer, iPortNo, iTimeout,
  392.   DNSQ, iQueryLenght, bTruncated);
  393. if ((pRespData == NULL) && bTruncated)
  394. pRespData = DNS_QuerySendStream(pszDNSServer, iPortNo, iTimeout,
  395. DNSQ, iQueryLenght);
  396. return (pRespData);
  397. }
  398. static SYS_UINT8 *DNS_QuerySendStream(char const *pszDNSServer, int iPortNo, int iTimeout,
  399.       DNSQuery const &DNSQ, int iQueryLenght)
  400. {
  401. ///////////////////////////////////////////////////////////////////////////////
  402. //  Open DNS server socket
  403. ///////////////////////////////////////////////////////////////////////////////
  404. SYS_SOCKET SockFD;
  405. SYS_INET_ADDR SvrAddr;
  406. SYS_INET_ADDR SockAddr;
  407. if (MscCreateClientSocket(pszDNSServer, iPortNo, SOCK_STREAM, &SockFD, &SvrAddr,
  408.   &SockAddr, iTimeout) < 0)
  409. return (NULL);
  410. SYS_UINT16 QLenght = (SYS_UINT16) htons(iQueryLenght);
  411. ///////////////////////////////////////////////////////////////////////////////
  412. //  Send packet lenght
  413. ///////////////////////////////////////////////////////////////////////////////
  414. if (SysSend(SockFD, (char *) &QLenght, sizeof(QLenght), iTimeout) != sizeof(QLenght)) {
  415. ErrorPush();
  416. SysCloseSocket(SockFD);
  417. ErrSetErrorCode(ErrorFetch());
  418. return (NULL);
  419. }
  420. ///////////////////////////////////////////////////////////////////////////////
  421. //  Send packet
  422. ///////////////////////////////////////////////////////////////////////////////
  423. if (SysSend(SockFD, (char const *) &DNSQ, iQueryLenght, iTimeout) != iQueryLenght) {
  424. ErrorPush();
  425. SysCloseSocket(SockFD);
  426. ErrSetErrorCode(ErrorFetch());
  427. return (NULL);
  428. }
  429. ///////////////////////////////////////////////////////////////////////////////
  430. //  Receive packet lenght
  431. ///////////////////////////////////////////////////////////////////////////////
  432. if (SysRecv(SockFD, (char *) &QLenght, sizeof(QLenght), iTimeout) != sizeof(QLenght)) {
  433. ErrorPush();
  434. SysCloseSocket(SockFD);
  435. ErrSetErrorCode(ErrorFetch());
  436. return (NULL);
  437. }
  438. int iPacketLenght = (int) ntohs(QLenght);
  439. SYS_UINT8 *pRespData = DNS_AllocRespData(iPacketLenght + 1);
  440. if (pRespData == NULL) {
  441. ErrorPush();
  442. SysCloseSocket(SockFD);
  443. ErrSetErrorCode(ErrorFetch());
  444. return (NULL);
  445. }
  446. ///////////////////////////////////////////////////////////////////////////////
  447. //  Receive packet
  448. ///////////////////////////////////////////////////////////////////////////////
  449. if (SysRecv(SockFD, (char *) pRespData, iPacketLenght, iTimeout) != iPacketLenght) {
  450. ErrorPush();
  451. DNS_FreeRespData(pRespData);
  452. SysCloseSocket(SockFD);
  453. ErrSetErrorCode(ErrorFetch());
  454. return (NULL);
  455. }
  456. SysCloseSocket(SockFD);
  457. DNS_HEADER *pDNSH = (DNS_HEADER *) pRespData;
  458. if (DNSQ.DNSH.RD && !pDNSH->RA) {
  459. DNS_FreeRespData(pRespData);
  460. ErrSetErrorCode(ERR_DNS_RECURSION_NOT_AVAILABLE);
  461. return (NULL);
  462. }
  463. return (pRespData);
  464. }
  465. static SYS_UINT8 *DNS_QuerySendDGram(char const *pszDNSServer, int iPortNo, int iTimeout,
  466.      DNSQuery const &DNSQ, int iQueryLenght, bool & bTruncated)
  467. {
  468. bTruncated = false;
  469. ///////////////////////////////////////////////////////////////////////////////
  470. //  Open DNS server socket
  471. ///////////////////////////////////////////////////////////////////////////////
  472. SYS_SOCKET SockFD;
  473. SYS_INET_ADDR SvrAddr;
  474. SYS_INET_ADDR SockAddr;
  475. if (MscCreateClientSocket(pszDNSServer, iPortNo, SOCK_DGRAM, &SockFD, &SvrAddr,
  476.   &SockAddr, iTimeout) < 0)
  477. return (NULL);
  478. ///////////////////////////////////////////////////////////////////////////////
  479. //  Query loop
  480. ///////////////////////////////////////////////////////////////////////////////
  481. for (int iSendLoops = 0; iSendLoops < DNS_SEND_RETRIES; iSendLoops++) {
  482. ///////////////////////////////////////////////////////////////////////////////
  483. //  Send packet
  484. ///////////////////////////////////////////////////////////////////////////////
  485. if (SysSendData(SockFD, (char const *) &DNSQ, iQueryLenght, iTimeout) !=
  486.     iQueryLenght)
  487. continue;
  488. ///////////////////////////////////////////////////////////////////////////////
  489. //  Receive packet lenght
  490. ///////////////////////////////////////////////////////////////////////////////
  491. SYS_INET_ADDR RecvAddr;
  492. SYS_UINT8 RespBuffer[1024];
  493. ZeroData(RecvAddr);
  494. int iPacketLenght =
  495.     SysRecvDataFrom(SockFD, (struct sockaddr *) &RecvAddr, sizeof(RecvAddr),
  496.     (char *) RespBuffer, sizeof(RespBuffer), iTimeout);
  497. if ((iPacketLenght < 0) || (iPacketLenght < sizeof(DNS_HEADER)))
  498. continue;
  499. DNS_HEADER *pDNSH = (DNS_HEADER *) RespBuffer;
  500. if (pDNSH->Id != DNSQ.DNSH.Id)
  501. continue;
  502. if (DNSQ.DNSH.RD && !pDNSH->RA) {
  503. SysCloseSocket(SockFD);
  504. ErrSetErrorCode(ERR_DNS_RECURSION_NOT_AVAILABLE);
  505. return (NULL);
  506. }
  507. if (pDNSH->TC) {
  508. bTruncated = true;
  509. SysCloseSocket(SockFD);
  510. ErrSetErrorCode(ERR_TRUNCATED_DGRAM_DNS_RESPONSE);
  511. return (NULL);
  512. }
  513. SYS_UINT8 *pRespData = DNS_AllocRespData(iPacketLenght + 1);
  514. if (pRespData == NULL) {
  515. ErrorPush();
  516. SysCloseSocket(SockFD);
  517. ErrSetErrorCode(ErrorFetch());
  518. return (NULL);
  519. }
  520. memcpy(pRespData, RespBuffer, iPacketLenght);
  521. SysCloseSocket(SockFD);
  522. return (pRespData);
  523. }
  524. SysCloseSocket(SockFD);
  525. ErrSetErrorCode(ERR_NO_DGRAM_DNS_RESPONSE);
  526. return (NULL);
  527. }
  528. static int DNS_DecodeResponseMX(SYS_UINT8 * pRespData, char const *pszDomain,
  529. HSLIST & hNameList, char const *pszRespFile,
  530. char *pszCName, SYS_UINT32 * pTTL)
  531. {
  532. SYS_UINT8 *pBaseData = pRespData;
  533. DNSQuery *pDNSQ = (DNSQuery *) pRespData;
  534. if (pDNSQ->DNSH.RCode != 0) {
  535. int iErrorCode = ERR_BAD_DNS_RESPONSE;
  536. if (pDNSQ->DNSH.RCode == RCODE_NXDOMAIN)
  537. iErrorCode = ERR_DNS_NXDOMAIN;
  538. ErrSetErrorCode(iErrorCode);
  539. return (iErrorCode);
  540. }
  541. pDNSQ->DNSH.QDCount = ntohs(pDNSQ->DNSH.QDCount);
  542. pDNSQ->DNSH.ANCount = ntohs(pDNSQ->DNSH.ANCount);
  543. pDNSQ->DNSH.NSCount = ntohs(pDNSQ->DNSH.NSCount);
  544. pDNSQ->DNSH.ARCount = ntohs(pDNSQ->DNSH.ARCount);
  545. FILE *pMXFile = fopen(pszRespFile, "wb");
  546. if (pMXFile == NULL) {
  547. ErrSetErrorCode(ERR_FILE_CREATE, pszRespFile);
  548. return (ERR_FILE_CREATE);
  549. }
  550. pRespData = pDNSQ->QueryData;
  551. ///////////////////////////////////////////////////////////////////////////////
  552. //  Scan query data
  553. ///////////////////////////////////////////////////////////////////////////////
  554. int ii;
  555. for (ii = 0; ii < (int) pDNSQ->DNSH.QDCount; ii++) {
  556. int iQLenght = 0;
  557. SYS_UINT16 Type = 0;
  558. SYS_UINT16 Class = 0;
  559. char szInetName[MAX_HOST_NAME] = "";
  560. if (DNS_GetQuery(pBaseData, pRespData, szInetName, &Type, &Class, &iQLenght) < 0) {
  561. ErrorPush();
  562. fclose(pMXFile);
  563. SysRemove(pszRespFile);
  564. return (ErrorPop());
  565. }
  566. pRespData += iQLenght;
  567. }
  568. ///////////////////////////////////////////////////////////////////////////////
  569. //  Scan answer data
  570. ///////////////////////////////////////////////////////////////////////////////
  571. int iMXRecords = 0;
  572. SYS_UINT32 TTL = 0;
  573. for (ii = 0; ii < (int) pDNSQ->DNSH.ANCount; ii++) {
  574. int iRRLenght = 0;
  575. DNSResourceRecord RR;
  576. if (DNS_GetResourceRecord(pBaseData, pRespData, &RR, &iRRLenght) < 0) {
  577. ErrorPush();
  578. fclose(pMXFile);
  579. SysRemove(pszRespFile);
  580. return (ErrorPop());
  581. }
  582. pRespData += iRRLenght;
  583. SYS_UINT8 const *pRRData = RR.pRespData;
  584. char szRRName[MAX_HOST_NAME] = "";
  585. if (RR.Type == QTYPE_MX) {
  586. SYS_UINT16 Preference = ntohs(MscReadUint16(pRRData));
  587. pRRData += sizeof(SYS_UINT16);
  588. if (DNS_GetName(pBaseData, pRRData, szRRName) < 0) {
  589. ErrorPush();
  590. fclose(pMXFile);
  591. SysRemove(pszRespFile);
  592. return (ErrorPop());
  593. }
  594. if (ii == 0)
  595. fprintf(pMXFile, "%d:%s", (int) Preference, szRRName);
  596. else
  597. fprintf(pMXFile, ",%d:%s", (int) Preference, szRRName);
  598. if ((TTL == 0) || (RR.TTL < TTL))
  599. TTL = RR.TTL;
  600. ++iMXRecords;
  601. } else if (RR.Type == QTYPE_CNAME) {
  602. if (DNS_GetName(pBaseData, pRRData, szRRName) < 0) {
  603. ErrorPush();
  604. fclose(pMXFile);
  605. SysRemove(pszRespFile);
  606. return (ErrorPop());
  607. }
  608. if (pszCName != NULL)
  609. strcpy(pszCName, szRRName);
  610. fclose(pMXFile);
  611. SysRemove(pszRespFile);
  612. ErrSetErrorCode(ERR_DNS_IS_CNAME);
  613. return (ERR_DNS_IS_CNAME);
  614. }
  615. }
  616. fclose(pMXFile);
  617. ///////////////////////////////////////////////////////////////////////////////
  618. //  Got answers ?
  619. ///////////////////////////////////////////////////////////////////////////////
  620. if (iMXRecords) {
  621. if (pTTL != NULL)
  622. *pTTL = TTL;
  623. return (0);
  624. }
  625. SysRemove(pszRespFile);
  626. ///////////////////////////////////////////////////////////////////////////////
  627. //  Scan name servers data
  628. ///////////////////////////////////////////////////////////////////////////////
  629. for (ii = 0; ii < (int) pDNSQ->DNSH.NSCount; ii++) {
  630. int iRRLenght = 0;
  631. DNSResourceRecord RR;
  632. if (DNS_GetResourceRecord(pBaseData, pRespData, &RR, &iRRLenght) < 0)
  633. return (ErrGetErrorCode());
  634. pRespData += iRRLenght;
  635. SYS_UINT8 const *pNSData = RR.pRespData;
  636. char szNSName[MAX_HOST_NAME] = "";
  637. if (DNS_GetName(pBaseData, pNSData, szNSName) < 0)
  638. return (ErrGetErrorCode());
  639. ///////////////////////////////////////////////////////////////////////////////
  640. //  Recursively try authority name servers
  641. ///////////////////////////////////////////////////////////////////////////////
  642. if (DNS_GetNameNode(hNameList, szNSName, pszDomain) == NULL) {
  643. int iFindResult = DNS_FindDomainMX(szNSName, pszDomain,
  644.    hNameList, pszRespFile,
  645.    pszCName, pTTL);
  646. if ((iFindResult == 0) || (iFindResult == ERR_DNS_NXDOMAIN) ||
  647.     (iFindResult == ERR_DNS_IS_CNAME))
  648. return (iFindResult);
  649. }
  650. }
  651. ///////////////////////////////////////////////////////////////////////////////
  652. //  Scan additional records data
  653. ///////////////////////////////////////////////////////////////////////////////
  654. for (ii = 0; ii < (int) pDNSQ->DNSH.ARCount; ii++) {
  655. int iRRLenght = 0;
  656. DNSResourceRecord RR;
  657. if (DNS_GetResourceRecord(pBaseData, pRespData, &RR, &iRRLenght) < 0)
  658. return (ErrGetErrorCode());
  659. pRespData += iRRLenght;
  660. }
  661. ErrSetErrorCode(ERR_BAD_DNS_RESPONSE);
  662. return (ERR_BAD_DNS_RESPONSE);
  663. }
  664. static int DNS_DecodeDirResponseMX(SYS_UINT8 * pRespData, char const *pszRespFile,
  665.    SYS_UINT32 * pTTL)
  666. {
  667. SYS_UINT8 *pBaseData = pRespData;
  668. DNSQuery *pDNSQ = (DNSQuery *) pRespData;
  669. if (pDNSQ->DNSH.RCode != 0) {
  670. int iErrorCode = ERR_BAD_DNS_RESPONSE;
  671. if (pDNSQ->DNSH.RCode == RCODE_NXDOMAIN)
  672. iErrorCode = ERR_DNS_NXDOMAIN;
  673. ErrSetErrorCode(iErrorCode);
  674. return (iErrorCode);
  675. }
  676. pDNSQ->DNSH.QDCount = ntohs(pDNSQ->DNSH.QDCount);
  677. pDNSQ->DNSH.ANCount = ntohs(pDNSQ->DNSH.ANCount);
  678. pDNSQ->DNSH.NSCount = ntohs(pDNSQ->DNSH.NSCount);
  679. pDNSQ->DNSH.ARCount = ntohs(pDNSQ->DNSH.ARCount);
  680. if (pDNSQ->DNSH.ANCount == 0) {
  681. ErrSetErrorCode(ERR_EMPTY_DNS_RESPONSE);
  682. return (ERR_EMPTY_DNS_RESPONSE);
  683. }
  684. FILE *pMXFile = fopen(pszRespFile, "wb");
  685. if (pMXFile == NULL) {
  686. ErrSetErrorCode(ERR_FILE_CREATE);
  687. return (ERR_FILE_CREATE);
  688. }
  689. pRespData = pDNSQ->QueryData;
  690. ///////////////////////////////////////////////////////////////////////////////
  691. //  Scan query data
  692. ///////////////////////////////////////////////////////////////////////////////
  693. int ii;
  694. for (ii = 0; ii < (int) pDNSQ->DNSH.QDCount; ii++) {
  695. int iQLenght = 0;
  696. SYS_UINT16 Type = 0;
  697. SYS_UINT16 Class = 0;
  698. char szInetName[MAX_HOST_NAME] = "";
  699. if (DNS_GetQuery(pBaseData, pRespData, szInetName, &Type, &Class, &iQLenght) < 0) {
  700. ErrorPush();
  701. fclose(pMXFile);
  702. return (ErrorPop());
  703. }
  704. pRespData += iQLenght;
  705. }
  706. ///////////////////////////////////////////////////////////////////////////////
  707. //  Scan answer data
  708. ///////////////////////////////////////////////////////////////////////////////
  709. int iMXRecords = 0;
  710. SYS_UINT32 TTL = 0;
  711. for (ii = 0; ii < (int) pDNSQ->DNSH.ANCount; ii++) {
  712. int iRRLenght = 0;
  713. DNSResourceRecord RR;
  714. if (DNS_GetResourceRecord(pBaseData, pRespData, &RR, &iRRLenght) < 0) {
  715. ErrorPush();
  716. fclose(pMXFile);
  717. return (ErrorPop());
  718. }
  719. pRespData += iRRLenght;
  720. SYS_UINT8 const *pRRData = RR.pRespData;
  721. if (RR.Type == QTYPE_MX) {
  722. SYS_UINT16 Preference = ntohs(MscReadUint16(pRRData));
  723. char szRRName[MAX_HOST_NAME] = "";
  724. pRRData += sizeof(SYS_UINT16);
  725. if (DNS_GetName(pBaseData, pRRData, szRRName) < 0) {
  726. ErrorPush();
  727. fclose(pMXFile);
  728. return (ErrorPop());
  729. }
  730. if (ii == 0)
  731. fprintf(pMXFile, "%d:%s", (int) Preference, szRRName);
  732. else
  733. fprintf(pMXFile, ",%d:%s", (int) Preference, szRRName);
  734. if ((TTL == 0) || (RR.TTL < TTL))
  735. TTL = RR.TTL;
  736. ++iMXRecords;
  737. }
  738. }
  739. fclose(pMXFile);
  740. if (iMXRecords == 0) {
  741. SysRemove(pszRespFile);
  742. ErrSetErrorCode(ERR_EMPTY_DNS_RESPONSE);
  743. return (ERR_EMPTY_DNS_RESPONSE);
  744. }
  745. if (pTTL != NULL)
  746. *pTTL = TTL;
  747. return (0);
  748. }
  749. static int DNS_DecodeResponseNS(SYS_UINT8 * pRespData, char const *pszRespFile,
  750. bool & bAuth, char *pszCName, SYS_UINT32 * pTTL)
  751. {
  752. SYS_UINT8 *pBaseData = pRespData;
  753. DNSQuery *pDNSQ = (DNSQuery *) pRespData;
  754. if (pDNSQ->DNSH.RCode != 0) {
  755. int iErrorCode = ERR_BAD_DNS_RESPONSE;
  756. if (pDNSQ->DNSH.RCode == RCODE_NXDOMAIN)
  757. iErrorCode = ERR_DNS_NXDOMAIN;
  758. ErrSetErrorCode(iErrorCode);
  759. return (iErrorCode);
  760. }
  761. FILE *pNSFile = fopen(pszRespFile, "wt");
  762. if (pNSFile == NULL) {
  763. ErrSetErrorCode(ERR_FILE_CREATE, pszRespFile);
  764. return (ERR_FILE_CREATE);
  765. }
  766. pDNSQ->DNSH.QDCount = ntohs(pDNSQ->DNSH.QDCount);
  767. pDNSQ->DNSH.ANCount = ntohs(pDNSQ->DNSH.ANCount);
  768. pDNSQ->DNSH.NSCount = ntohs(pDNSQ->DNSH.NSCount);
  769. pDNSQ->DNSH.ARCount = ntohs(pDNSQ->DNSH.ARCount);
  770. pRespData = pDNSQ->QueryData;
  771. ///////////////////////////////////////////////////////////////////////////////
  772. //  Scan query data
  773. ///////////////////////////////////////////////////////////////////////////////
  774. int ii;
  775. for (ii = 0; ii < (int) pDNSQ->DNSH.QDCount; ii++) {
  776. int iQLenght = 0;
  777. SYS_UINT16 Type = 0;
  778. SYS_UINT16 Class = 0;
  779. char szInetName[MAX_HOST_NAME] = "";
  780. if (DNS_GetQuery(pBaseData, pRespData, szInetName, &Type, &Class, &iQLenght) < 0) {
  781. ErrorPush();
  782. fclose(pNSFile);
  783. return (ErrorPop());
  784. }
  785. pRespData += iQLenght;
  786. }
  787. ///////////////////////////////////////////////////////////////////////////////
  788. //  Scan answer data
  789. ///////////////////////////////////////////////////////////////////////////////
  790. int iNSRecords = 0;
  791. SYS_UINT32 TTL = 0;
  792. for (ii = 0; ii < (int) pDNSQ->DNSH.ANCount; ii++) {
  793. int iRRLenght = 0;
  794. DNSResourceRecord RR;
  795. if (DNS_GetResourceRecord(pBaseData, pRespData, &RR, &iRRLenght) < 0) {
  796. ErrorPush();
  797. fclose(pNSFile);
  798. return (ErrorPop());
  799. }
  800. pRespData += iRRLenght;
  801. SYS_UINT8 const *pNSData = RR.pRespData;
  802. char szRRName[MAX_HOST_NAME] = "";
  803. if (DNS_GetName(pBaseData, pNSData, szRRName) < 0) {
  804. ErrorPush();
  805. fclose(pNSFile);
  806. return (ErrorPop());
  807. }
  808. if (RR.Type == QTYPE_NS) {
  809. fprintf(pNSFile, "%sn", szRRName);
  810. if ((TTL == 0) || (RR.TTL < TTL))
  811. TTL = RR.TTL;
  812. ++iNSRecords;
  813. } else if (RR.Type == QTYPE_CNAME) {
  814. if (pszCName != NULL)
  815. strcpy(pszCName, szRRName);
  816. fclose(pNSFile);
  817. ErrSetErrorCode(ERR_DNS_IS_CNAME);
  818. return (ERR_DNS_IS_CNAME);
  819. }
  820. }
  821. ///////////////////////////////////////////////////////////////////////////////
  822. //  Got answers ?
  823. ///////////////////////////////////////////////////////////////////////////////
  824. if (iNSRecords > 0) {
  825. fclose(pNSFile);
  826. bAuth = true;
  827. if (pTTL != NULL)
  828. *pTTL = TTL;
  829. return (0);
  830. }
  831. ///////////////////////////////////////////////////////////////////////////////
  832. //  Scan name servers data
  833. ///////////////////////////////////////////////////////////////////////////////
  834. for (ii = 0; ii < (int) pDNSQ->DNSH.NSCount; ii++) {
  835. int iRRLenght = 0;
  836. DNSResourceRecord RR;
  837. if (DNS_GetResourceRecord(pBaseData, pRespData, &RR, &iRRLenght) < 0) {
  838. ErrorPush();
  839. fclose(pNSFile);
  840. return (ErrorPop());
  841. }
  842. pRespData += iRRLenght;
  843. SYS_UINT8 const *pNSData = RR.pRespData;
  844. char szRRName[MAX_HOST_NAME] = "";
  845. if (DNS_GetName(pBaseData, pNSData, szRRName) < 0) {
  846. ErrorPush();
  847. fclose(pNSFile);
  848. return (ErrorPop());
  849. }
  850. if (RR.Type == QTYPE_NS) {
  851. fprintf(pNSFile, "%sn", szRRName);
  852. if ((TTL == 0) || (RR.TTL < TTL))
  853. TTL = RR.TTL;
  854. ++iNSRecords;
  855. }
  856. }
  857. ///////////////////////////////////////////////////////////////////////////////
  858. //  Got answers ?
  859. ///////////////////////////////////////////////////////////////////////////////
  860. if (iNSRecords > 0) {
  861. fclose(pNSFile);
  862. bAuth = false;
  863. if (pTTL != NULL)
  864. *pTTL = TTL;
  865. return (0);
  866. }
  867. ///////////////////////////////////////////////////////////////////////////////
  868. //  Scan additional records data
  869. ///////////////////////////////////////////////////////////////////////////////
  870. for (ii = 0; ii < (int) pDNSQ->DNSH.ARCount; ii++) {
  871. int iRRLenght = 0;
  872. DNSResourceRecord RR;
  873. if (DNS_GetResourceRecord(pBaseData, pRespData, &RR, &iRRLenght) < 0) {
  874. ErrorPush();
  875. fclose(pNSFile);
  876. return (ErrorPop());
  877. }
  878. pRespData += iRRLenght;
  879. }
  880. fclose(pNSFile);
  881. ErrSetErrorCode(ERR_BAD_DNS_RESPONSE);
  882. return (ERR_BAD_DNS_RESPONSE);
  883. }
  884. static int DNS_FindDomainMX(char const *pszDNSServer, char const *pszDomain,
  885.     HSLIST & hNameList, char const *pszRespFile,
  886.     char *pszCName, SYS_UINT32 * pTTL)
  887. {
  888. ///////////////////////////////////////////////////////////////////////////////
  889. //  Send query and read result
  890. ///////////////////////////////////////////////////////////////////////////////
  891. SYS_UINT8 *pRespData = DNS_QueryExec(pszDNSServer, DNS_PORTNO, DNS_SOCKET_TIMEOUT,
  892.      0, QTYPE_MX, pszDomain);
  893. if (pRespData == NULL)
  894. return (ErrGetErrorCode());
  895. ///////////////////////////////////////////////////////////////////////////////
  896. //  Add this server to the visited list
  897. ///////////////////////////////////////////////////////////////////////////////
  898. DNS_AddNameNode(hNameList, pszDNSServer, pszDomain);
  899. ///////////////////////////////////////////////////////////////////////////////
  900. //  Decode server response ( recursive )
  901. ///////////////////////////////////////////////////////////////////////////////
  902. int iDecodeResult = DNS_DecodeResponseMX(pRespData, pszDomain,
  903.  hNameList, pszRespFile,
  904.  pszCName, pTTL);
  905. DNS_FreeRespData(pRespData);
  906. return (iDecodeResult);
  907. }
  908. static int DNS_QueryDomainMX(char const *pszDNSServer, char const *pszDomain,
  909.      char *&pszMXDomains, char *pszCName, SYS_UINT32 * pTTL)
  910. {
  911. HSLIST hNameList;
  912. char szMXFileName[SYS_MAX_PATH] = "";
  913. SysGetTmpFile(szMXFileName);
  914. ListInit(hNameList);
  915. if (DNS_FindDomainMX(pszDNSServer, pszDomain, hNameList,
  916.      szMXFileName, pszCName, pTTL) < 0) {
  917. ErrorPush();
  918. DNS_FreeNameList(hNameList);
  919. SysRemove(szMXFileName);
  920. return (ErrorPop());
  921. }
  922. DNS_FreeNameList(hNameList);
  923. FILE *pMXFile = fopen(szMXFileName, "rb");
  924. if (pMXFile == NULL) {
  925. SysRemove(szMXFileName);
  926. ErrSetErrorCode(ERR_FILE_OPEN);
  927. return (ERR_FILE_OPEN);
  928. }
  929. fseek(pMXFile, 0, SEEK_END);
  930. unsigned int uFileSize = (unsigned int) ftell(pMXFile);
  931. if ((pszMXDomains = (char *) SysAlloc(uFileSize + 1)) == NULL) {
  932. fclose(pMXFile);
  933. SysRemove(szMXFileName);
  934. return (ErrGetErrorCode());
  935. }
  936. fseek(pMXFile, 0, SEEK_SET);
  937. fread(pszMXDomains, uFileSize, 1, pMXFile);
  938. pszMXDomains[uFileSize] = '';
  939. fclose(pMXFile);
  940. SysRemove(szMXFileName);
  941. return (0);
  942. }
  943. int DNS_QueryNameServers(char const *pszDNSServer, char const *pszDomain,
  944.  char const *pszRespFile, bool & bAuth, char *pszCName, SYS_UINT32 * pTTL)
  945. {
  946. ///////////////////////////////////////////////////////////////////////////////
  947. //  Send query and read result
  948. ///////////////////////////////////////////////////////////////////////////////
  949. SYS_UINT8 *pRespData = DNS_QueryExec(pszDNSServer, DNS_PORTNO, DNS_SOCKET_TIMEOUT,
  950.      0, QTYPE_NS, pszDomain);
  951. if (pRespData == NULL)
  952. return (ErrGetErrorCode());
  953. if (DNS_DecodeResponseNS(pRespData, pszRespFile, bAuth, pszCName, pTTL) < 0) {
  954. ErrorPush();
  955. DNS_FreeRespData(pRespData);
  956. return (ErrorPop());
  957. }
  958. DNS_FreeRespData(pRespData);
  959. return (0);
  960. }
  961. static int DNS_AppendHosts(FILE *pFile, char const *pszDestPath)
  962. {
  963. FILE *pDest = fopen(pszDestPath, "a+t");
  964. if (pDest == NULL) {
  965. ErrSetErrorCode(ERR_FILE_OPEN);
  966. return (ERR_FILE_OPEN);
  967. }
  968. rewind(pFile);
  969. char szHost[MAX_HOST_NAME] = "";
  970. while (MscFGets(szHost, sizeof(szHost) - 1, pFile) != NULL)
  971. fprintf(pDest, "%sn", szHost);
  972. fclose(pDest);
  973. return (0);
  974. }
  975. static int DNS_GetNameServersLL(char const *pszDNSServer, char const *pszDomain,
  976. char const *pszRespFile, HSLIST & hNameList,
  977. char *pszCName, SYS_UINT32 * pTTL)
  978. {
  979. char szRespFile[SYS_MAX_PATH] = "";
  980. SysGetTmpFile(szRespFile);
  981. bool bAuth = false;
  982. if (DNS_QueryNameServers(pszDNSServer, pszDomain, szRespFile, bAuth, pszCName, pTTL) < 0) {
  983. ErrorPush();
  984. CheckRemoveFile(szRespFile);
  985. return (ErrorPop());
  986. }
  987. if (bAuth) {
  988. if (MscCopyFile(pszRespFile, szRespFile) < 0) {
  989. ErrorPush();
  990. SysRemove(szRespFile);
  991. return (ErrorPop());
  992. }
  993. SysRemove(szRespFile);
  994. return (0);
  995. }
  996. ///////////////////////////////////////////////////////////////////////////////
  997. //  Add this server to the visited list
  998. ///////////////////////////////////////////////////////////////////////////////
  999. DNS_AddNameNode(hNameList, pszDNSServer, pszDomain);
  1000. FILE *pNSFile = fopen(szRespFile, "rt");
  1001. if (pNSFile == NULL) {
  1002. SysRemove(szRespFile);
  1003. ErrSetErrorCode(ERR_FILE_OPEN);
  1004. return (ERR_FILE_OPEN);
  1005. }
  1006. char szNS[MAX_HOST_NAME] = "";
  1007. while (MscFGets(szNS, sizeof(szNS) - 1, pNSFile) != NULL) {
  1008. if (DNS_GetNameNode(hNameList, szNS, pszDomain) == NULL) {
  1009. int iQueryResult = DNS_GetNameServersLL(szNS, pszDomain,
  1010. pszRespFile, hNameList,
  1011. pszCName, pTTL);
  1012. if ((iQueryResult == 0) || (iQueryResult == ERR_DNS_NXDOMAIN) ||
  1013.     (iQueryResult == ERR_DNS_IS_CNAME)) {
  1014. ///////////////////////////////////////////////////////////////////////////////
  1015. //  If the result code is zero (success), add the non-auth servers at the end
  1016. //  of the list. They will be tried only after a failure from all the auth ones
  1017. ///////////////////////////////////////////////////////////////////////////////
  1018. if (iQueryResult == 0)
  1019. iQueryResult = DNS_AppendHosts(pNSFile, pszRespFile);
  1020. fclose(pNSFile);
  1021. SysRemove(szRespFile);
  1022. return (iQueryResult);
  1023. }
  1024. }
  1025. }
  1026. fclose(pNSFile);
  1027. ///////////////////////////////////////////////////////////////////////////////
  1028. //  We have got non-auth servers, better than nothing
  1029. ///////////////////////////////////////////////////////////////////////////////
  1030. if (MscCopyFile(pszRespFile, szRespFile) < 0) {
  1031. ErrorPush();
  1032. SysRemove(szRespFile);
  1033. return (ErrorPop());
  1034. }
  1035. SysRemove(szRespFile);
  1036. return (0);
  1037. }
  1038. int DNS_GetNameServers(char const *pszDNSServer, char const *pszDomain,
  1039.        char const *pszRespFile, char *pszCName, SYS_UINT32 * pTTL)
  1040. {
  1041. HSLIST hNameList;
  1042. ListInit(hNameList);
  1043. int iQueryResult = DNS_GetNameServersLL(pszDNSServer, pszDomain,
  1044. pszRespFile, hNameList, pszCName, pTTL);
  1045. DNS_FreeNameList(hNameList);
  1046. return (iQueryResult);
  1047. }
  1048. int DNS_DomainNameServers(char const *pszDomain, char const *pszRespFile,
  1049.   char *pszCName, SYS_UINT32 * pTTL)
  1050. {
  1051. char szRootsFile[SYS_MAX_PATH] = "";
  1052. char szRespFile[SYS_MAX_PATH] = "";
  1053. DNS_GetRootsFile(szRootsFile, sizeof(szRootsFile));
  1054. StrSNCpy(szRespFile, szRootsFile);
  1055. char **ppszDomains = StrTokenize(pszDomain, ". t");
  1056. if (ppszDomains == NULL)
  1057. return (ErrGetErrorCode());
  1058. int iSubDomains = StrStringsCount(ppszDomains);
  1059. int iLastNSResult = ERR_DNS_NXDOMAIN;
  1060. char szPrevDomain[MAX_HOST_NAME] = "";
  1061. for (--iSubDomains; iSubDomains >= 0; iSubDomains--) {
  1062. char szCurrDomain[MAX_HOST_NAME] = "";
  1063. SysSNPrintf(szCurrDomain, sizeof(szCurrDomain) - 1, "%s.%s",
  1064.     ppszDomains[iSubDomains], szPrevDomain);
  1065. StrSNCpy(szPrevDomain, szCurrDomain);
  1066. FILE *pNSFile = fopen(szRespFile, "rt");
  1067. if (pNSFile == NULL) {
  1068. StrFreeStrings(ppszDomains);
  1069. if (strcmp(szRespFile, szRootsFile) != 0)
  1070. SysRemove(szRespFile);
  1071. ErrSetErrorCode(ERR_FILE_OPEN);
  1072. return (ERR_FILE_OPEN);
  1073. }
  1074. char szRespFile2[SYS_MAX_PATH] = "";
  1075. SysGetTmpFile(szRespFile2);
  1076. int iNSGetResult = -1;
  1077. char szNS[MAX_HOST_NAME] = "";
  1078. while (MscFGets(szNS, sizeof(szNS) - 1, pNSFile) != NULL) {
  1079. iNSGetResult = DNS_GetNameServers(szNS, szCurrDomain,
  1080.   szRespFile2, pszCName, pTTL);
  1081. if ((iNSGetResult == 0) || (iNSGetResult == ERR_DNS_NXDOMAIN))
  1082. break;
  1083. if (iNSGetResult == ERR_DNS_IS_CNAME) {
  1084. fclose(pNSFile);
  1085. StrFreeStrings(ppszDomains);
  1086. if (strcmp(szRespFile, szRootsFile) != 0)
  1087. SysRemove(szRespFile);
  1088. ErrSetErrorCode(iNSGetResult);
  1089. return (iNSGetResult);
  1090. }
  1091. }
  1092. fclose(pNSFile);
  1093. ///////////////////////////////////////////////////////////////////////////////
  1094. //  Not getting a valid response at level N does not mean that we will not
  1095. //  succeed at level N+1. It might happen that mid-level subdomains do not
  1096. //  have NS records while low-level will do
  1097. ///////////////////////////////////////////////////////////////////////////////
  1098. if ((iLastNSResult = iNSGetResult) < 0)
  1099. SysRemove(szRespFile2);
  1100. else {
  1101. if (strcmp(szRespFile, szRootsFile) != 0)
  1102. SysRemove(szRespFile);
  1103. StrSNCpy(szRespFile, szRespFile2);
  1104. }
  1105. }
  1106. StrFreeStrings(ppszDomains);
  1107. ///////////////////////////////////////////////////////////////////////////////
  1108. //  If we did not get any valid response walking down the hierarchy we bounce
  1109. //  back with the latest error that we received
  1110. ///////////////////////////////////////////////////////////////////////////////
  1111. if (strcmp(szRespFile, szRootsFile) == 0) {
  1112. ErrSetErrorCode(iLastNSResult);
  1113. return (iLastNSResult);
  1114. }
  1115. if (MscCopyFile(pszRespFile, szRespFile) < 0) {
  1116. ErrorPush();
  1117. SysRemove(szRespFile);
  1118. return (ErrorPop());
  1119. }
  1120. SysRemove(szRespFile);
  1121. return (0);
  1122. }
  1123. static char *DNS_GetRootsFile(char *pszRootsFilePath, int iMaxPath)
  1124. {
  1125. CfgGetRootPath(pszRootsFilePath, iMaxPath);
  1126. StrNCat(pszRootsFilePath, ROOTS_FILE, iMaxPath);
  1127. return (pszRootsFilePath);
  1128. }
  1129. int DNS_GetRoots(char const *pszDNSServer, char const *pszRespFile)
  1130. {
  1131. return (DNS_GetNameServers(pszDNSServer, ".", pszRespFile, NULL));
  1132. }
  1133. int DNS_GetDomainMX(char const *pszDomain, char *&pszMXDomains, char *pszCName, SYS_UINT32 * pTTL)
  1134. {
  1135. char szRespFile[SYS_MAX_PATH] = "";
  1136. SysGetTmpFile(szRespFile);
  1137. if (DNS_DomainNameServers(pszDomain, szRespFile, pszCName) < 0) {
  1138. ErrorPush();
  1139. SysRemove(szRespFile);
  1140. return (ErrorPop());
  1141. }
  1142. FILE *pNSFile = fopen(szRespFile, "rt");
  1143. if (pNSFile == NULL) {
  1144. SysRemove(szRespFile);
  1145. ErrSetErrorCode(ERR_FILE_OPEN);
  1146. return (ERR_FILE_OPEN);
  1147. }
  1148. char szNS[MAX_HOST_NAME] = "";
  1149. while (MscFGets(szNS, sizeof(szNS) - 1, pNSFile) != NULL) {
  1150. int iQueryResult = DNS_QueryDomainMX(szNS, pszDomain, pszMXDomains,
  1151.      pszCName, pTTL);
  1152. if ((iQueryResult == 0) || (iQueryResult == ERR_DNS_NXDOMAIN) ||
  1153.     (iQueryResult == ERR_DNS_IS_CNAME)) {
  1154. fclose(pNSFile);
  1155. SysRemove(szRespFile);
  1156. return (iQueryResult);
  1157. }
  1158. }
  1159. fclose(pNSFile);
  1160. SysRemove(szRespFile);
  1161. ErrSetErrorCode(ERR_NO_DEFINED_MXS_FOR_DOMAIN);
  1162. return (ERR_NO_DEFINED_MXS_FOR_DOMAIN);
  1163. }
  1164. int DNS_GetDomainMXDirect(char const *pszDNSServer, char const *pszDomain,
  1165.   int iQuerySockType, char *&pszMXDomains, SYS_UINT32 * pTTL)
  1166. {
  1167. ///////////////////////////////////////////////////////////////////////////////
  1168. //  Setup DNS MX query with recursion requested
  1169. ///////////////////////////////////////////////////////////////////////////////
  1170. int iQueryLenght;
  1171. DNSQuery DNSQ;
  1172. if (DNS_RequestSetup(DNSQ, 0, QTYPE_MX, pszDomain, iQueryLenght, true) < 0)
  1173. return (ErrGetErrorCode());
  1174. SYS_UINT8 *pRespData = NULL;
  1175. switch (iQuerySockType) {
  1176. case (DNS_QUERY_TCP):
  1177. {
  1178. if ((pRespData =
  1179.      DNS_QuerySendStream(pszDNSServer, DNS_PORTNO, DNS_SOCKET_TIMEOUT,
  1180.  DNSQ, iQueryLenght)) == NULL)
  1181. return (ErrGetErrorCode());
  1182. }
  1183. break;
  1184. case (DNS_QUERY_UDP):
  1185. default:
  1186. {
  1187. ///////////////////////////////////////////////////////////////////////////////
  1188. //  Try needed UDP query first, if it's truncated switch to TCP query
  1189. ///////////////////////////////////////////////////////////////////////////////
  1190. bool bTruncated = false;
  1191. if (((pRespData =
  1192.       DNS_QuerySendDGram(pszDNSServer, DNS_PORTNO, DNS_SOCKET_TIMEOUT,
  1193.  DNSQ, iQueryLenght, bTruncated)) == NULL) &&
  1194.     bTruncated)
  1195. pRespData =
  1196.     DNS_QuerySendStream(pszDNSServer, DNS_PORTNO,
  1197. DNS_SOCKET_TIMEOUT, DNSQ, iQueryLenght);
  1198. if (pRespData == NULL)
  1199. return (ErrGetErrorCode());
  1200. }
  1201. break;
  1202. }
  1203. char szRespFile[SYS_MAX_PATH] = "";
  1204. SysGetTmpFile(szRespFile);
  1205. if (DNS_DecodeDirResponseMX(pRespData, szRespFile, pTTL) < 0) {
  1206. ErrorPush();
  1207. DNS_FreeRespData(pRespData);
  1208. CheckRemoveFile(szRespFile);
  1209. return (ErrorPop());
  1210. }
  1211. DNS_FreeRespData(pRespData);
  1212. FILE *pMXFile = fopen(szRespFile, "rb");
  1213. if (pMXFile == NULL) {
  1214. ErrorPush();
  1215. SysRemove(szRespFile);
  1216. return (ErrorPop());
  1217. }
  1218. fseek(pMXFile, 0, SEEK_END);
  1219. unsigned int uFileSize = (unsigned int) ftell(pMXFile);
  1220. if ((pszMXDomains = (char *) SysAlloc(uFileSize + 1)) == NULL) {
  1221. ErrorPush();
  1222. fclose(pMXFile);
  1223. SysRemove(szRespFile);
  1224. return (ErrorPop());
  1225. }
  1226. fseek(pMXFile, 0, SEEK_SET);
  1227. fread(pszMXDomains, uFileSize, 1, pMXFile);
  1228. pszMXDomains[uFileSize] = '';
  1229. fclose(pMXFile);
  1230. SysRemove(szRespFile);
  1231. return (0);
  1232. }