import { tap, expect } from '@git.zone/tstest/tapbundle'; import * as plugins from '../../../ts/plugins.js'; import * as net from 'net'; import { startTestServer, stopTestServer } from '../../helpers/server.loader.js' import type { ITestServer } from '../../helpers/server.loader.js'; const TEST_PORT = 2525; let testServer: ITestServer; tap.test('setup - start test server', async (toolsArg) => { testServer = await startTestServer({ port: TEST_PORT }); await toolsArg.delayFor(1000); }); tap.test('RFC 7489 DMARC - Server handles DMARC policies', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; const dmarcResults: any[] = []; // Test domains simulating different DMARC policies const dmarcTestScenarios = [ { domain: 'dmarc-reject.example.com', policy: 'reject', alignment: 'strict' }, { domain: 'dmarc-quarantine.example.com', policy: 'quarantine', alignment: 'relaxed' }, { domain: 'dmarc-none.example.com', policy: 'none', alignment: 'relaxed' } ]; let currentScenarioIndex = 0; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { // Check if server advertises DMARC support const advertisesDmarc = dataBuffer.toLowerCase().includes('dmarc'); console.log('Server advertises DMARC:', advertisesDmarc); step = 'test_scenarios'; testNextScenario(); } else if (step === 'test_scenarios') { handleScenarioResponse(); } }); function testNextScenario() { if (currentScenarioIndex >= dmarcTestScenarios.length) { // All tests complete console.log('DMARC test results:', dmarcResults); // Check that server handled all scenarios const allScenariosHandled = dmarcResults.every(result => result.mailFromResponse !== undefined ); expect(allScenariosHandled).toEqual(true); socket.write('QUIT\r\n'); socket.end(); done.resolve(); return; } const scenario = dmarcTestScenarios[currentScenarioIndex]; const testFromAddress = `dmarc-test@${scenario.domain}`; dmarcResults[currentScenarioIndex] = { domain: scenario.domain, policy: scenario.policy, mailFromAccepted: false, rcptAccepted: false }; console.log(`Testing DMARC policy: ${scenario.policy} for domain: ${scenario.domain}`); socket.write(`MAIL FROM:<${testFromAddress}>\r\n`); dataBuffer = ''; } function handleScenarioResponse() { const currentResult = dmarcResults[currentScenarioIndex]; if (dataBuffer.includes('250') && dataBuffer.includes('sender accepted')) { currentResult.mailFromAccepted = true; currentResult.mailFromResponse = dataBuffer.trim(); socket.write(`RCPT TO:\r\n`); dataBuffer = ''; } else if (dataBuffer.includes('250') && dataBuffer.includes('recipient accepted')) { currentResult.rcptAccepted = true; socket.write('DATA\r\n'); dataBuffer = ''; } else if (dataBuffer.includes('354')) { // Send email with DMARC-relevant headers const scenario = dmarcTestScenarios[currentScenarioIndex]; const email = [ `From: dmarc-test@${scenario.domain}`, `To: recipient@example.com`, `Subject: DMARC RFC 7489 Compliance Test - ${scenario.policy}`, `Date: ${new Date().toUTCString()}`, `Message-ID: `, `DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=${scenario.domain}; s=default;`, ` h=from:to:subject:date; bh=testbodyhash; b=testsignature`, `Authentication-Results: example.org; spf=pass smtp.mailfrom=${scenario.domain}`, '', `This email tests DMARC ${scenario.policy} policy compliance.`, 'The server should handle DMARC policies according to RFC 7489.', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') && dataBuffer.includes('Message accepted')) { currentResult.emailAccepted = true; console.log(`DMARC ${currentResult.policy} policy email accepted`); // Reset and test next scenario socket.write('RSET\r\n'); dataBuffer = ''; } else if (dataBuffer.includes('250') && dataBuffer.includes('Reset')) { currentScenarioIndex++; testNextScenario(); } else if (dataBuffer.includes('550') || dataBuffer.includes('553')) { // DMARC policy rejection (expected for some scenarios) currentResult.dmarcRejected = true; currentResult.rejectionResponse = dataBuffer.trim(); console.log(`DMARC ${currentResult.policy} policy rejected as expected`); // Reset and test next scenario socket.write('RSET\r\n'); dataBuffer = ''; } } socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('RFC 7489 DMARC - Alignment testing', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; // Test misaligned domain (envelope vs header) socket.write('MAIL FROM:\r\n'); dataBuffer = ''; } else if (step === 'mail' && dataBuffer.includes('250')) { step = 'rcpt'; socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else if (step === 'rcpt' && dataBuffer.includes('250')) { step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } else if (step === 'data' && dataBuffer.includes('354')) { // Email with different header From domain (testing alignment) const email = [ `From: sender@header-domain.com`, `To: recipient@example.com`, `Subject: DMARC Alignment Test`, `Date: ${new Date().toUTCString()}`, `Message-ID: `, `DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=header-domain.com; s=default;`, ` h=from:to:subject:date; bh=alignmenthash; b=alignmentsig`, '', 'Testing DMARC domain alignment (envelope vs header From).', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') || dataBuffer.includes('550 ')) { const accepted = dataBuffer.includes('250'); console.log(`Alignment test ${accepted ? 'accepted' : 'rejected due to alignment failure'}`); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('RFC 7489 DMARC - Subdomain policy', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; // Test subdomain policy inheritance socket.write('MAIL FROM:\r\n'); dataBuffer = ''; } else if (step === 'mail' && dataBuffer.includes('250')) { step = 'rcpt'; socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else if (step === 'rcpt' && dataBuffer.includes('250')) { step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } else if (step === 'data' && dataBuffer.includes('354')) { // Email from subdomain to test policy inheritance const email = [ `From: sender@subdomain.dmarc-policy.com`, `To: recipient@example.com`, `Subject: DMARC Subdomain Policy Test`, `Date: ${new Date().toUTCString()}`, `Message-ID: `, `DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=subdomain.dmarc-policy.com; s=default;`, ` h=from:to:subject:date; bh=subdomainhash; b=subdomainsig`, '', 'Testing DMARC subdomain policy inheritance.', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') || dataBuffer.includes('550 ')) { const accepted = dataBuffer.includes('250'); console.log(`Subdomain policy test ${accepted ? 'accepted' : 'rejected'}`); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('RFC 7489 DMARC - Report generation hint', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; socket.write('MAIL FROM:\r\n'); dataBuffer = ''; } else if (step === 'mail' && dataBuffer.includes('250')) { step = 'rcpt'; socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else if (step === 'rcpt' && dataBuffer.includes('250')) { step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } else if (step === 'data' && dataBuffer.includes('354')) { // Email with DMARC report request headers const email = [ `From: dmarc-report@example.com`, `To: recipient@example.com`, `Subject: DMARC Report Generation Test`, `Date: ${new Date().toUTCString()}`, `Message-ID: `, `DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=default;`, ` h=from:to:subject:date; bh=reporthash; b=reportsig`, `Authentication-Results: mta.example.com;`, ` dmarc=pass (p=none dis=none) header.from=example.com`, '', 'Testing DMARC report generation capabilities.', 'Server should log DMARC results for reporting.', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') && dataBuffer.includes('Message accepted')) { console.log('DMARC report test email accepted'); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('cleanup - stop test server', async () => { await stopTestServer(testServer); }); tap.start();