const dns = require('dns').promises; const logger = require('./logger'); const IP_CONNECTION_COUNTS = new Map(); const BANNED_IPS = new Set(); const IP_RATE_LIMIT = 20; // 每个IP(服务器)每分钟最多20次连接 const IP_TIME_WINDOW = 60 * 1000; // 1分钟 const IP_BAN_DURATION = 5 * 60 * 1000; // 5分钟 /** * 检查IP地址是否因为连接频率过高而被限制。 * @param {string} remoteAddress 客户端IP地址。 * @returns {boolean} 如果被限制则返回true,否则返回false。 */ function isIpRateLimited(remoteAddress) { if (BANNED_IPS.has(remoteAddress)) { logger.warn(`Connection from banned IP ${remoteAddress} rejected.`); return true; } const now = Date.now(); const requests = IP_CONNECTION_COUNTS.get(remoteAddress) || []; const recentRequests = requests.filter(timestamp => now - timestamp < IP_TIME_WINDOW); if (recentRequests.length >= IP_RATE_LIMIT) { logger.warn(`IP ${remoteAddress} has exceeded the connection rate limit. Banning for ${IP_BAN_DURATION / 1000} seconds.`); BANNED_IPS.add(remoteAddress); setTimeout(() => { BANNED_IPS.delete(remoteAddress); logger.info(`IP ${remoteAddress} has been unbanned.`); }, IP_BAN_DURATION); IP_CONNECTION_COUNTS.delete(remoteAddress); return true; } recentRequests.push(now); IP_CONNECTION_COUNTS.set(remoteAddress, recentRequests); return false; } /** * 检查IP地址是否有有效的反向DNS(PTR)记录。 * 正规的邮件服务器通常都有PTR记录。 * @param {string} remoteAddress 客户端IP地址。 * @returns {Promise} 如果验证通过则返回true,否则返回false。 */ async function hasValidPtrRecord(remoteAddress) { // 对于本地和私有地址,我们跳过检查,因为它们通常没有公共PTR记录 if (remoteAddress.startsWith('127.') || remoteAddress.startsWith('192.168.') || remoteAddress.startsWith('10.') || remoteAddress.startsWith('::1')) { return true; } try { const hostnames = await dns.reverse(remoteAddress); if (hostnames && hostnames.length > 0) { logger.info(`PTR record for ${remoteAddress} found: ${hostnames.join(', ')}`); return true; } logger.warn(`No PTR record found for ${remoteAddress}.`); return false; } catch (error) { // 'ENOTFOUND' 是最常见的错误,意味着没有找到PTR记录。 if (error.code === 'ENOTFOUND') { logger.warn(`No PTR record found for ${remoteAddress}.`); } else { logger.error(`Error during PTR lookup for ${remoteAddress}:`, error); } return false; } } /** * 在连接建立时验证客户端。 * @param {object} session SMTP会话对象。 * @param {function} callback 回调函数。 */ async function validateConnection(session, callback) { const { remoteAddress } = session; // 1. IP频率限制检查 if (isIpRateLimited(remoteAddress)) { const err = new Error('Connection rejected due to high frequency. Please try again later.'); err.responseCode = 421; return callback(err); } // 2. 反向DNS检查 const hasPtr = await hasValidPtrRecord(remoteAddress); if (!hasPtr) { const err = new Error('Connection rejected: The IP address has no PTR record.'); err.responseCode = 550; // 550表示请求的操作未执行,邮箱不可用(在这里引申为连接源不可信) return callback(err); } // 所有检查通过 callback(); } module.exports = { validateConnection };