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
|
||||
|
||||
## 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
|
||||
|
||||
### New Route-Based Architecture (v18+)
|
||||
|
@ -814,8 +814,14 @@ export class DcRouter {
|
||||
// Generate email DNS records
|
||||
const emailDnsRecords = await this.generateEmailDnsRecords();
|
||||
|
||||
// Combine all records: authoritative, email, and user-defined
|
||||
const allRecords = [...authoritativeRecords, ...emailDnsRecords];
|
||||
// Initialize DKIM for all email domains
|
||||
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) {
|
||||
allRecords.push(...this.options.dnsRecords);
|
||||
}
|
||||
@ -826,7 +832,7 @@ export class DcRouter {
|
||||
// Register all DNS records
|
||||
if (allRecords.length > 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* SOA records are now automatically generated by smartdns with primaryNameserver setting
|
||||
|
Loading…
x
Reference in New Issue
Block a user