Skip to content

Commit 463dbe9

Browse files
fix(dns): validate resolver ports (#189)
1 parent 3d2e20c commit 463dbe9

2 files changed

Lines changed: 56 additions & 2 deletions

File tree

src/dns.mjs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ export const DEFAULT_PARKING_HOST = "moshcoding.com";
2222
export const DEFAULT_PORT = 5354;
2323
export const DEFAULT_HOST = "127.0.0.1";
2424

25+
export function parseDnsPort(input) {
26+
const raw = String(input ?? "").trim();
27+
if (!/^\d+$/.test(raw)) return null;
28+
const port = Number(raw);
29+
return Number.isSafeInteger(port) && port >= 1 && port <= 65535 ? port : null;
30+
}
31+
2532
// Short, because a name's target can change the moment its owner points it
2633
// somewhere. A stale A record is the one failure mode users cannot debug.
2734
export const DEFAULT_TTL = 30;
@@ -377,14 +384,21 @@ export async function dnsCommand(args = [], out = console.log) {
377384
const i = rest.indexOf(`--${name}`);
378385
return i >= 0 && rest[i + 1] ? rest[i + 1] : fallback;
379386
};
380-
const port = Number(flag("port", DEFAULT_PORT));
381387
const registryBase = flag("registry", DEFAULT_REGISTRY_BASE);
382388

383389
if (!sub || sub === "help" || sub === "--help") {
384390
out(USAGE);
385391
return 0;
386392
}
387393

394+
const portIndex = rest.indexOf("--port");
395+
const rawPort = portIndex >= 0 ? rest[portIndex + 1] : DEFAULT_PORT;
396+
const port = parseDnsPort(rawPort);
397+
if (port === null) {
398+
out(`--port needs a decimal integer from 1 to 65535, got ${JSON.stringify(rawPort)}`);
399+
return 1;
400+
}
401+
388402
if (sub === "tlds") {
389403
const tlds = await fetchTlds({ registryBase });
390404
out(tlds.length ? tlds.map((t) => `.${t}`).join("\n") : "no TLDs claimed yet");
@@ -428,7 +442,13 @@ export async function dnsCommand(args = [], out = console.log) {
428442
// by Host header and 404s a name it has never heard of, so pointing at
429443
// loopback — where the responder below is listening — is the difference
430444
// between `curl <name>` resolving and `curl <name>` working.
431-
const parkingHttpPort = Number(flag("parking-port", DEFAULT_PARKING_HTTP_PORT));
445+
const parkingPortIndex = rest.indexOf("--parking-port");
446+
const rawParkingHttpPort = parkingPortIndex >= 0 ? rest[parkingPortIndex + 1] : DEFAULT_PARKING_HTTP_PORT;
447+
const parkingHttpPort = parseDnsPort(rawParkingHttpPort);
448+
if (parkingHttpPort === null) {
449+
out(`--parking-port needs a decimal integer from 1 to 65535, got ${JSON.stringify(rawParkingHttpPort)}`);
450+
return 1;
451+
}
432452
let parking = null;
433453
if (!rest.includes("--no-parking-http")) {
434454
try {

test/dns-port-validation.test.mjs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import test from "node:test";
2+
import assert from "node:assert/strict";
3+
4+
import { dnsCommand, parseDnsPort } from "../src/dns.mjs";
5+
6+
test("DNS ports accept only decimal integers in the TCP range", () => {
7+
assert.equal(parseDnsPort("1"), 1);
8+
assert.equal(parseDnsPort(" 5354 "), 5354);
9+
assert.equal(parseDnsPort(65535), 65535);
10+
assert.equal(parseDnsPort("1e3"), null);
11+
assert.equal(parseDnsPort("65536"), null);
12+
});
13+
14+
test("dns install rejects invalid resolver ports before fetching TLDs", async () => {
15+
for (const value of [undefined, "", "abc", "0", "1.5", "1e3", "65536", "9007199254740992"]) {
16+
const args = ["install", "--port"];
17+
if (value !== undefined) args.push(value);
18+
const lines = [];
19+
20+
assert.equal(await dnsCommand(args, (line) => lines.push(String(line))), 1);
21+
assert.match(lines.join("\n"), /--port needs a decimal integer from 1 to 65535/);
22+
}
23+
});
24+
25+
test("dns start rejects invalid parking HTTP ports before opening sockets", async () => {
26+
for (const value of [undefined, "", "abc", "0", "1.5", "1e3", "65536", "Infinity"]) {
27+
const args = ["start", "--parking-port"];
28+
if (value !== undefined) args.push(value);
29+
const lines = [];
30+
31+
assert.equal(await dnsCommand(args, (line) => lines.push(String(line))), 1);
32+
assert.match(lines.join("\n"), /--parking-port needs a decimal integer from 1 to 65535/);
33+
}
34+
});

0 commit comments

Comments
 (0)