fix(dns): Fixed Soa records
This commit is contained in:
parent
71183b35c0
commit
74692c4aa5
@ -20,7 +20,7 @@
|
||||
"@git.zone/tsrun": "^1.3.3",
|
||||
"@git.zone/tstest": "^2.3.1",
|
||||
"@git.zone/tswatch": "^2.0.1",
|
||||
"@types/node": "^22.15.24",
|
||||
"@types/node": "^22.15.29",
|
||||
"node-forge": "^1.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -32,7 +32,7 @@
|
||||
"@push.rocks/qenv": "^6.1.0",
|
||||
"@push.rocks/smartacme": "^8.0.0",
|
||||
"@push.rocks/smartdata": "^5.15.1",
|
||||
"@push.rocks/smartdns": "^7.4.0",
|
||||
"@push.rocks/smartdns": "^7.4.7",
|
||||
"@push.rocks/smartfile": "^11.2.5",
|
||||
"@push.rocks/smartlog": "^3.1.8",
|
||||
"@push.rocks/smartmail": "^2.1.0",
|
||||
|
82
pnpm-lock.yaml
generated
82
pnpm-lock.yaml
generated
@ -33,8 +33,8 @@ importers:
|
||||
specifier: ^5.15.1
|
||||
version: 5.15.1(@aws-sdk/credential-providers@3.817.0)(socks@2.8.4)
|
||||
'@push.rocks/smartdns':
|
||||
specifier: ^7.4.0
|
||||
version: 7.4.0
|
||||
specifier: ^7.4.7
|
||||
version: 7.4.7
|
||||
'@push.rocks/smartfile':
|
||||
specifier: ^11.2.5
|
||||
version: 11.2.5
|
||||
@ -103,8 +103,8 @@ importers:
|
||||
specifier: ^2.0.1
|
||||
version: 2.1.0
|
||||
'@types/node':
|
||||
specifier: ^22.15.24
|
||||
version: 22.15.24
|
||||
specifier: ^22.15.29
|
||||
version: 22.15.29
|
||||
node-forge:
|
||||
specifier: ^1.3.1
|
||||
version: 1.3.1
|
||||
@ -833,8 +833,8 @@ packages:
|
||||
'@push.rocks/smartdns@6.2.2':
|
||||
resolution: {integrity: sha512-MhJcHujbyIuwIIFdnXb2OScGtRjNsliLUS8GoAurFsKtcCOaA0ytfP+PNzkukyBufjb1nMiJF3rjhswXdHakAQ==}
|
||||
|
||||
'@push.rocks/smartdns@7.4.0':
|
||||
resolution: {integrity: sha512-dedSy946AUOeT2EzgbcEC1IVeT+3wNDzw/28anQXL3juMdA05T1aP7TkSOee3uU8AUjVx2ZASz/2D/TpdBDWsw==}
|
||||
'@push.rocks/smartdns@7.4.7':
|
||||
resolution: {integrity: sha512-sgOUqtGJstRvt8+aoAR13L9g/m3sZNY5ai9qpczhDnxGW9uP7+JnthMtQHrhnMiNbZxxq1cBCuRN4YVz6R4V5Q==}
|
||||
|
||||
'@push.rocks/smartenv@5.0.12':
|
||||
resolution: {integrity: sha512-tDEFwywzq0FNzRYc9qY2dRl2pgQuZG0G2/yml2RLWZWSW+Fn1EHshnKOGHz8o77W7zvu4hTgQQX42r/JY5XHTg==}
|
||||
@ -1500,11 +1500,11 @@ packages:
|
||||
'@types/node-forge@1.3.11':
|
||||
resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==}
|
||||
|
||||
'@types/node@18.19.105':
|
||||
resolution: {integrity: sha512-a+DrwD2VyzqQR2W0EVF8EaCh6Em4ilQAYLEPZnMNkQHXR7ziWW7RUhZMWZAgRpkDDAdUIcJOXSPJT/zBEwz3sA==}
|
||||
'@types/node@18.19.110':
|
||||
resolution: {integrity: sha512-WW2o4gTmREtSnqKty9nhqF/vA0GKd0V/rbC0OyjSk9Bz6bzlsXKT+i7WDdS/a0z74rfT2PO4dArVCSnapNLA5Q==}
|
||||
|
||||
'@types/node@22.15.24':
|
||||
resolution: {integrity: sha512-w9CZGm9RDjzTh/D+hFwlBJ3ziUaVw7oufKA3vOFSOZlzmW9AkZnfjPb+DLnrV6qtgL/LNmP0/2zBNCFHL3F0ng==}
|
||||
'@types/node@22.15.29':
|
||||
resolution: {integrity: sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==}
|
||||
|
||||
'@types/ping@0.4.4':
|
||||
resolution: {integrity: sha512-ifvo6w2f5eJYlXm+HiVx67iJe8WZp87sfa683nlqED5Vnt9Z93onkokNoWqOG21EaE8fMxyKPobE+mkPEyxsdw==}
|
||||
@ -5131,10 +5131,8 @@ snapshots:
|
||||
'@push.rocks/taskbuffer': 3.1.7
|
||||
transitivePeerDependencies:
|
||||
- '@nuxt/kit'
|
||||
- bufferutil
|
||||
- react
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
- vue
|
||||
|
||||
'@hapi/hoek@9.3.0': {}
|
||||
@ -5571,7 +5569,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@push.rocks/smartdns@7.4.0':
|
||||
'@push.rocks/smartdns@7.4.7':
|
||||
dependencies:
|
||||
'@push.rocks/smartdelay': 3.0.5
|
||||
'@push.rocks/smartenv': 5.0.12
|
||||
@ -6651,27 +6649,27 @@ snapshots:
|
||||
|
||||
'@types/bn.js@5.1.6':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/body-parser@1.19.5':
|
||||
dependencies:
|
||||
'@types/connect': 3.4.38
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/buffer-json@2.0.3': {}
|
||||
|
||||
'@types/clean-css@4.2.11':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
source-map: 0.6.1
|
||||
|
||||
'@types/connect@3.4.38':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/cors@2.8.18':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/debug@4.1.12':
|
||||
dependencies:
|
||||
@ -6683,7 +6681,7 @@ snapshots:
|
||||
|
||||
'@types/dns-packet@5.6.5':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/elliptic@6.4.18':
|
||||
dependencies:
|
||||
@ -6691,7 +6689,7 @@ snapshots:
|
||||
|
||||
'@types/express-serve-static-core@5.0.6':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
'@types/qs': 6.14.0
|
||||
'@types/range-parser': 1.2.7
|
||||
'@types/send': 0.17.4
|
||||
@ -6708,30 +6706,30 @@ snapshots:
|
||||
|
||||
'@types/from2@2.3.5':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/fs-extra@11.0.4':
|
||||
dependencies:
|
||||
'@types/jsonfile': 6.1.4
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/fs-extra@9.0.13':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/glob@7.2.0':
|
||||
dependencies:
|
||||
'@types/minimatch': 5.1.2
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/glob@8.1.0':
|
||||
dependencies:
|
||||
'@types/minimatch': 5.1.2
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/gunzip-maybe@1.4.2':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/hast@3.0.4':
|
||||
dependencies:
|
||||
@ -6753,11 +6751,11 @@ snapshots:
|
||||
|
||||
'@types/jsonfile@6.1.4':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/mailparser@3.4.6':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
iconv-lite: 0.6.3
|
||||
|
||||
'@types/mdast@4.0.4':
|
||||
@ -6776,18 +6774,18 @@ snapshots:
|
||||
|
||||
'@types/node-fetch@2.6.12':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
form-data: 4.0.2
|
||||
|
||||
'@types/node-forge@1.3.11':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/node@18.19.105':
|
||||
'@types/node@18.19.110':
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
|
||||
'@types/node@22.15.24':
|
||||
'@types/node@22.15.29':
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
|
||||
@ -6803,30 +6801,30 @@ snapshots:
|
||||
|
||||
'@types/s3rver@3.7.4':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/semver@7.7.0': {}
|
||||
|
||||
'@types/send@0.17.4':
|
||||
dependencies:
|
||||
'@types/mime': 1.3.5
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/serve-static@1.15.7':
|
||||
dependencies:
|
||||
'@types/http-errors': 2.0.4
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
'@types/send': 0.17.4
|
||||
|
||||
'@types/symbol-tree@3.2.5': {}
|
||||
|
||||
'@types/tar-stream@2.2.3':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/through2@2.0.41':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/triple-beam@1.3.5': {}
|
||||
|
||||
@ -6850,18 +6848,18 @@ snapshots:
|
||||
|
||||
'@types/whatwg-url@8.2.2':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
'@types/webidl-conversions': 7.0.3
|
||||
|
||||
'@types/which@3.0.4': {}
|
||||
|
||||
'@types/ws@8.18.1':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
|
||||
'@types/yauzl@2.10.3':
|
||||
dependencies:
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
optional: true
|
||||
|
||||
'@ungap/structured-clone@1.3.0': {}
|
||||
@ -7141,7 +7139,7 @@ snapshots:
|
||||
|
||||
cloudflare@4.2.0:
|
||||
dependencies:
|
||||
'@types/node': 18.19.105
|
||||
'@types/node': 18.19.110
|
||||
'@types/node-fetch': 2.6.12
|
||||
abort-controller: 3.0.0
|
||||
agentkeepalive: 4.6.0
|
||||
@ -7412,7 +7410,7 @@ snapshots:
|
||||
engine.io@6.6.4:
|
||||
dependencies:
|
||||
'@types/cors': 2.8.18
|
||||
'@types/node': 22.15.24
|
||||
'@types/node': 22.15.29
|
||||
accepts: 1.3.8
|
||||
base64id: 2.0.0
|
||||
cookie: 0.7.2
|
||||
|
@ -1,126 +0,0 @@
|
||||
# SmartDNS DnsServer Issues and Required Changes
|
||||
|
||||
## Current Limitation: Cannot Serve Multiple Records of Same Type
|
||||
|
||||
### Problem Description
|
||||
The current implementation of `@push.rocks/smartdns` DnsServer has a critical limitation that prevents it from serving multiple DNS records of the same type for a domain. This is particularly problematic for:
|
||||
- **NS records** - Most domains need 2+ nameservers for redundancy
|
||||
- **A/AAAA records** - Round-robin DNS requires multiple IPs
|
||||
- **MX records** - Multiple mail servers with different priorities
|
||||
- **TXT records** - Multiple TXT records for SPF, DKIM, domain verification, etc.
|
||||
|
||||
### Root Cause
|
||||
In the `processDnsRequest` method of DnsServer, when processing DNS queries:
|
||||
|
||||
```javascript
|
||||
for (const handlerEntry of this.handlers) {
|
||||
if (plugins.minimatch.minimatch(question.name, handlerEntry.domainPattern) &&
|
||||
handlerEntry.recordTypes.includes(question.type)) {
|
||||
const answer = handlerEntry.handler(question);
|
||||
if (answer) {
|
||||
response.answers.push(dnsAnswer);
|
||||
answered = true;
|
||||
break; // <-- PROBLEM: Exits after first matching handler!
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `break` statement causes the loop to exit after the first matching handler returns an answer, preventing subsequent handlers from being called.
|
||||
|
||||
### Impact
|
||||
- **NS Records**: Only one nameserver is returned instead of multiple
|
||||
- **Domain Registration Failures**: Registrars like GoDaddy reject domains with only one NS record
|
||||
- **No Round-Robin**: Cannot implement round-robin DNS with multiple A records
|
||||
- **Limited TXT Records**: Cannot serve multiple TXT records (SPF + DKIM + others)
|
||||
|
||||
### Required Changes
|
||||
|
||||
#### Option 1: Continue Processing All Handlers (Recommended)
|
||||
Remove the `break` statement to allow all matching handlers to contribute answers:
|
||||
|
||||
```javascript
|
||||
for (const handlerEntry of this.handlers) {
|
||||
if (plugins.minimatch.minimatch(question.name, handlerEntry.domainPattern) &&
|
||||
handlerEntry.recordTypes.includes(question.type)) {
|
||||
const answer = handlerEntry.handler(question);
|
||||
if (answer) {
|
||||
response.answers.push(dnsAnswer);
|
||||
if (dnssecRequested) {
|
||||
const rrsig = this.generateRRSIG(question.type, [dnsAnswer], question.name);
|
||||
response.answers.push(rrsig);
|
||||
}
|
||||
answered = true;
|
||||
// Don't break - continue checking other handlers
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Option 2: Handler Returns Array
|
||||
Modify the handler interface to allow returning multiple answers:
|
||||
|
||||
```typescript
|
||||
export interface IDnsHandler {
|
||||
domainPattern: string;
|
||||
recordTypes: string[];
|
||||
handler: (question: dnsPacket.Question) => DnsAnswer | DnsAnswer[] | null;
|
||||
}
|
||||
```
|
||||
|
||||
Then update processDnsRequest to handle arrays:
|
||||
|
||||
```javascript
|
||||
const answer = handlerEntry.handler(question);
|
||||
if (answer) {
|
||||
const answers = Array.isArray(answer) ? answer : [answer];
|
||||
for (const ans of answers) {
|
||||
response.answers.push({...ans, ttl: ans.ttl || 300, class: ans.class || 'IN'});
|
||||
}
|
||||
answered = true;
|
||||
break; // Can break here since handler returns all records
|
||||
}
|
||||
```
|
||||
|
||||
### Workaround (Current Implementation)
|
||||
Currently working around this by registering separate handlers for each record. This is inefficient but functional:
|
||||
|
||||
```typescript
|
||||
// Instead of one handler for multiple NS records
|
||||
// We register separate handlers for each NS record
|
||||
for (const record of records) {
|
||||
this.dnsServer.registerHandler(record.name, [record.type], (question) => {
|
||||
if (question.name === record.name && question.type === record.type) {
|
||||
return { /* single record */ };
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Other Issues Found
|
||||
|
||||
#### 1. SOA Record Timeout
|
||||
SOA queries sometimes timeout or return incorrect data. This may be related to the DNSSEC implementation or SOA record generation.
|
||||
|
||||
#### 2. DNSSEC Zone Prefix
|
||||
The DnsServer automatically prefixes 'ns1.' to the dnssecZone:
|
||||
```javascript
|
||||
mname: `ns1.${this.options.dnssecZone}`
|
||||
```
|
||||
This can cause mismatches when the actual nameserver doesn't have the 'ns1.' prefix.
|
||||
|
||||
### Testing the Fix
|
||||
After implementing Option 1 or 2, test with:
|
||||
|
||||
```bash
|
||||
# Should return BOTH nameservers
|
||||
dig @nameserver.example.com domain.com NS
|
||||
|
||||
# Should show multiple NS records in answer section
|
||||
domain.com. 3600 IN NS ns1.example.com.
|
||||
domain.com. 3600 IN NS ns2.example.com.
|
||||
```
|
||||
|
||||
### Priority
|
||||
**HIGH** - This issue prevents proper DNS server operation and blocks domain registration at many registrars.
|
@ -79,7 +79,7 @@ export interface IDcRouterOptions {
|
||||
/**
|
||||
* DNS records to register
|
||||
* Must be within the defined dnsScopes (or receive warning)
|
||||
* Only need A, CNAME, TXT, MX records (NS and SOA are auto-generated)
|
||||
* Only need A, CNAME, TXT, MX records (NS records auto-generated, SOA handled by smartdns)
|
||||
* Can use `useIngressProxy: false` to expose real server IP (defaults to true)
|
||||
*/
|
||||
dnsRecords?: Array<{
|
||||
@ -788,6 +788,7 @@ export class DcRouter {
|
||||
httpsPort: 443, // Required but won't bind due to manual mode
|
||||
manualHttpsMode: true, // Enable manual HTTPS socket handling
|
||||
dnssecZone: primaryNameserver,
|
||||
primaryNameserver: primaryNameserver, // Automatically generates correct SOA records
|
||||
// For now, use self-signed cert until we integrate with Let's Encrypt
|
||||
httpsKey: '',
|
||||
httpsCert: ''
|
||||
@ -937,7 +938,8 @@ export class DcRouter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate authoritative DNS records (NS and SOA) 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
|
||||
*/
|
||||
private async generateAuthoritativeRecords(): Promise<Array<{name: string; type: string; value: string; ttl?: number}>> {
|
||||
const records: Array<{name: string; type: string; value: string; ttl?: number}> = [];
|
||||
@ -946,9 +948,7 @@ export class DcRouter {
|
||||
return records;
|
||||
}
|
||||
|
||||
const primaryNameserver = this.options.dnsNsDomains[0];
|
||||
|
||||
// Generate NS and SOA records for each domain in scopes
|
||||
// Generate NS records for each domain in scopes
|
||||
for (const domain of this.options.dnsScopes) {
|
||||
// Add NS records for all nameservers
|
||||
for (const nsDomain of this.options.dnsNsDomains) {
|
||||
@ -960,17 +960,11 @@ export class DcRouter {
|
||||
});
|
||||
}
|
||||
|
||||
// Add SOA record with first nameserver as primary
|
||||
const soaValue = `${primaryNameserver} hostmaster.${domain} ${Date.now()} 7200 3600 1209600 3600`;
|
||||
records.push({
|
||||
name: domain,
|
||||
type: 'SOA',
|
||||
value: soaValue,
|
||||
ttl: 3600
|
||||
});
|
||||
// SOA records are now automatically generated by smartdns DnsServer
|
||||
// with the primaryNameserver configuration option
|
||||
}
|
||||
|
||||
logger.log('info', `Generated ${records.length} authoritative records for ${this.options.dnsScopes.length} domains`);
|
||||
logger.log('info', `Generated ${records.length} NS records for ${this.options.dnsScopes.length} domains`);
|
||||
return records;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user