Skip to content

Commit

Permalink
fix: don't return NS or SOA authority records for error responses.
Browse files Browse the repository at this point in the history
  • Loading branch information
zicklag committed Nov 5, 2024
1 parent c5e2bc2 commit 7506614
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .env.local
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ REDIS_URL="redis://localhost:7634"
APP_IPS="127.0.0.1"
DNS_ALLOWED_DOMAINS="localhost:9523"
DNS_NAMESERVERS="localhost:9523"
DNS_SOA_MASTER="ns1.weird.one"
DNS_SOA_MASTER="localhost"
DNS_SOA_EMAIL="[email protected]"

PUBLIC_INSTANCE_NAME="Weird.One"
Expand Down
59 changes: 42 additions & 17 deletions src/lib/dns/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DefaultStore } from 'dinodns/plugins/storage';
import { dev } from '$app/environment';
import { AUTHORITATIVE_ANSWER, type SoaAnswer } from 'dns-packet';
import { z } from 'zod';
import { RCode } from 'dinodns/common/core/utils';

const REDIS_USER_PREFIX = 'weird:users:';
const REDIS_DNS_RECORD_PREFIX = 'weird:dns:records:';
Expand All @@ -31,6 +32,8 @@ const WEIRD_HOST_TXT_RECORD_REGEX = new RegExp(
const WEIRD_HOST_A_RECORD_REGEX = new RegExp(
`^([^\\.]*)\\.${escapeStringForEmbeddingInRegex(pubenv.PUBLIC_USER_DOMAIN_PARENT.split(':')[0])}$`
);
const VALID_DOMAIN_REGEX =
/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/;

const DNS_PORT = parseInt(env.DNS_PORT || '53');
const APP_IPS = env.APP_IPS.split(',');
Expand Down Expand Up @@ -109,6 +112,16 @@ export async function startDnsServer() {
staticRecords.set(appDomain, 'A', APP_IPS);
s.use(staticRecords.handler);

// Reject queries that are not valid domain names
s.use(async (req, res, next) => {
if (res.finished) return next();
const name = req.packet.questions[0].name;
if (!name.match(VALID_DOMAIN_REGEX)) {
res.errors.refused();
};
next();
});

// Reject queries for non-allowed domains ( when not in development )
s.use(async (req, res, next) => {
if (res.finished) return next();
Expand Down Expand Up @@ -177,8 +190,10 @@ export async function startDnsServer() {
(record) =>
new Promise((done) => {
dns.resolve(record.data, (err, addrs) => {
console.error('Error looking up A record for cname', record.data, err);
if (err) return done(null);
if (err) {
console.error('Error looking up A record for cname', record.data, err);
return done(null);
}
res.packet.answers = [
...req.packet.answers,
...addrs.map(
Expand Down Expand Up @@ -347,12 +362,15 @@ export async function startDnsServer() {
)) as (SupportedAnswer[] | null)[];

// Return answers
res.answer(
results
.filter((x) => !!x)
.map((x) => x as unknown as SupportedAnswer)
.flat()
);
const filtered = results
.filter((x) => !!x)
.map((x) => x as unknown as SupportedAnswer)
.flat();
if (filtered.length > 0) {
res.answer(filtered);
} else {
res.errors.nxDomain();
}

next();
});
Expand All @@ -362,18 +380,25 @@ export async function startDnsServer() {
//
// An earlier middleware will reject the record with an NXDOMAIN error if the domain doesn't match.
s.use(async (req, res, next) => {
if (res.finished) return next();

const question = req.packet.questions[0];
if (res.packet.answers.length == 0) {
// Comply with RFC 2308 Section 2.2 by returning an SOA record when there are no other
// answers.
res.packet.raw.authorities = [makeSoaAnswer(question.name)];
} else if (question.type != 'NS' && question.type != 'SOA') {
res.packet.raw.authorities = makeNsAnswers(question.name);
}

if (!res.finished) {
res.resolve();
// If the response is not an error
if (((res.packet.raw.flags || 0) & RCode.NO_ERROR) == RCode.NO_ERROR) {
// If there are no answers
if (res.packet.answers.length == 0) {
// Comply with RFC 2308 Section 2.2 by returning an SOA record when there are no other
// answers.
res.packet.raw.authorities = [makeSoaAnswer(question.name)];
// If the answer should be supplemented with the NS authority records
} else if (question.type != 'NS' && question.type != 'SOA') {
res.packet.raw.authorities = makeNsAnswers(question.name);
}
}

res.resolve();

next();
});

Expand Down

0 comments on commit 7506614

Please sign in to comment.