feat(dns): implement DKIM record serving and proactive key generation
- Add loadDkimRecords() method to read DKIM records from JSON files - Integrate DKIM records into DNS server during startup - Add initializeDkimForEmailDomains() for proactive DKIM key generation - Ensure DKIM records are available immediately after server startup - Update documentation with DKIM implementation status DKIM records are now automatically loaded from .nogit/data/dns/*.dkimrecord.json and served via DNS. Keys are generated for all configured email domains at startup.
This commit is contained in:
parent
c776dab2c0
commit
272973702e
@ -1,5 +1,29 @@
|
|||||||
# Implementation Hints and Learnings
|
# Implementation Hints and Learnings
|
||||||
|
|
||||||
|
## DKIM Implementation Status (2025-05-30)
|
||||||
|
|
||||||
|
### Current Implementation
|
||||||
|
1. **DKIM Key Generation**: Working - keys are generated when emails are sent
|
||||||
|
2. **DKIM Email Signing**: Working - emails are signed with DKIM
|
||||||
|
3. **DKIM DNS Record Serving**: Implemented - records are loaded from JSON files and served
|
||||||
|
4. **Proactive DKIM Generation**: Implemented - keys are generated for all email domains at startup
|
||||||
|
|
||||||
|
### Key Points
|
||||||
|
- DKIM selector is hardcoded as `mta` in DKIMCreator
|
||||||
|
- DKIM records are stored in `.nogit/data/dns/*.dkimrecord.json`
|
||||||
|
- DKIM keys are stored in `.nogit/data/keys/{domain}-private.pem` and `{domain}-public.pem`
|
||||||
|
- The server needs to be restarted for DKIM records to be loaded and served
|
||||||
|
- Proactive generation ensures DKIM records are available immediately after startup
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
After server restart, DKIM records can be queried:
|
||||||
|
```bash
|
||||||
|
dig @192.168.190.3 mta._domainkey.central.eu TXT +short
|
||||||
|
```
|
||||||
|
|
||||||
|
### Note
|
||||||
|
The existing dcrouter instance has test domain DKIM records but not for production domains like central.eu. A restart is required to trigger the proactive DKIM generation for configured email domains.
|
||||||
|
|
||||||
## SmartProxy Usage
|
## SmartProxy Usage
|
||||||
|
|
||||||
### New Route-Based Architecture (v18+)
|
### New Route-Based Architecture (v18+)
|
||||||
|
@ -814,8 +814,14 @@ export class DcRouter {
|
|||||||
// Generate email DNS records
|
// Generate email DNS records
|
||||||
const emailDnsRecords = await this.generateEmailDnsRecords();
|
const emailDnsRecords = await this.generateEmailDnsRecords();
|
||||||
|
|
||||||
// Combine all records: authoritative, email, and user-defined
|
// Initialize DKIM for all email domains
|
||||||
const allRecords = [...authoritativeRecords, ...emailDnsRecords];
|
await this.initializeDkimForEmailDomains();
|
||||||
|
|
||||||
|
// Load DKIM records from JSON files (they should now exist)
|
||||||
|
const dkimRecords = await this.loadDkimRecords();
|
||||||
|
|
||||||
|
// Combine all records: authoritative, email, DKIM, and user-defined
|
||||||
|
const allRecords = [...authoritativeRecords, ...emailDnsRecords, ...dkimRecords];
|
||||||
if (this.options.dnsRecords && this.options.dnsRecords.length > 0) {
|
if (this.options.dnsRecords && this.options.dnsRecords.length > 0) {
|
||||||
allRecords.push(...this.options.dnsRecords);
|
allRecords.push(...this.options.dnsRecords);
|
||||||
}
|
}
|
||||||
@ -826,7 +832,7 @@ export class DcRouter {
|
|||||||
// Register all DNS records
|
// Register all DNS records
|
||||||
if (allRecords.length > 0) {
|
if (allRecords.length > 0) {
|
||||||
this.registerDnsRecords(allRecords);
|
this.registerDnsRecords(allRecords);
|
||||||
logger.log('info', `Registered ${allRecords.length} DNS records (${authoritativeRecords.length} authoritative, ${emailDnsRecords.length} email, ${this.options.dnsRecords?.length || 0} user-defined)`);
|
logger.log('info', `Registered ${allRecords.length} DNS records (${authoritativeRecords.length} authoritative, ${emailDnsRecords.length} email, ${dkimRecords.length} DKIM, ${this.options.dnsRecords?.length || 0} user-defined)`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -944,6 +950,96 @@ export class DcRouter {
|
|||||||
return records;
|
return records;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load DKIM records from JSON files
|
||||||
|
* Reads all *.dkimrecord.json files from the DNS records directory
|
||||||
|
*/
|
||||||
|
private async loadDkimRecords(): Promise<Array<{name: string; type: string; value: string; ttl?: number}>> {
|
||||||
|
const records: Array<{name: string; type: string; value: string; ttl?: number}> = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Ensure paths are imported
|
||||||
|
const dnsDir = paths.dnsRecordsDir;
|
||||||
|
|
||||||
|
// Check if directory exists
|
||||||
|
if (!plugins.fs.existsSync(dnsDir)) {
|
||||||
|
logger.log('debug', 'No DNS records directory found, skipping DKIM record loading');
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read all files in the directory
|
||||||
|
const files = plugins.fs.readdirSync(dnsDir);
|
||||||
|
const dkimFiles = files.filter(f => f.endsWith('.dkimrecord.json'));
|
||||||
|
|
||||||
|
logger.log('info', `Found ${dkimFiles.length} DKIM record files`);
|
||||||
|
|
||||||
|
// Load each DKIM record
|
||||||
|
for (const file of dkimFiles) {
|
||||||
|
try {
|
||||||
|
const filePath = plugins.path.join(dnsDir, file);
|
||||||
|
const fileContent = plugins.fs.readFileSync(filePath, 'utf8');
|
||||||
|
const dkimRecord = JSON.parse(fileContent);
|
||||||
|
|
||||||
|
// Validate record structure
|
||||||
|
if (dkimRecord.name && dkimRecord.type === 'TXT' && dkimRecord.value) {
|
||||||
|
records.push({
|
||||||
|
name: dkimRecord.name,
|
||||||
|
type: 'TXT',
|
||||||
|
value: dkimRecord.value,
|
||||||
|
ttl: 3600 // Standard DKIM TTL
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.log('info', `Loaded DKIM record for ${dkimRecord.name}`);
|
||||||
|
} else {
|
||||||
|
logger.log('warn', `Invalid DKIM record structure in ${file}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.log('error', `Failed to load DKIM record from ${file}: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.log('error', `Failed to load DKIM records: ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize DKIM keys for all configured email domains
|
||||||
|
* This ensures DKIM records are available immediately at startup
|
||||||
|
*/
|
||||||
|
private async initializeDkimForEmailDomains(): Promise<void> {
|
||||||
|
if (!this.options.emailConfig?.domains || !this.emailServer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log('info', 'Initializing DKIM keys for email domains...');
|
||||||
|
|
||||||
|
// Get DKIMCreator instance from email server
|
||||||
|
const dkimCreator = (this.emailServer as any).dkimCreator;
|
||||||
|
if (!dkimCreator) {
|
||||||
|
logger.log('warn', 'DKIMCreator not available, skipping DKIM initialization');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure necessary directories exist
|
||||||
|
paths.ensureDirectories();
|
||||||
|
|
||||||
|
// Generate DKIM keys for each email domain
|
||||||
|
for (const domainConfig of this.options.emailConfig.domains) {
|
||||||
|
try {
|
||||||
|
// Generate DKIM keys for all domains, regardless of DNS mode
|
||||||
|
// This ensures keys are ready even if DNS mode changes later
|
||||||
|
await dkimCreator.handleDKIMKeysForDomain(domainConfig.domain);
|
||||||
|
logger.log('info', `DKIM keys initialized for ${domainConfig.domain}`);
|
||||||
|
} catch (error) {
|
||||||
|
logger.log('error', `Failed to initialize DKIM for ${domainConfig.domain}: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log('info', 'DKIM initialization complete');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate authoritative DNS records (NS only) for all domains in dnsScopes
|
* Generate authoritative DNS records (NS only) for all domains in dnsScopes
|
||||||
* SOA records are now automatically generated by smartdns with primaryNameserver setting
|
* SOA records are now automatically generated by smartdns with primaryNameserver setting
|
||||||
|
Loading…
x
Reference in New Issue
Block a user