mirror of
https://github.com/minescope/mineping.git
synced 2025-07-14 08:04:35 +03:00
feat: skip SRV lookup for IP addresses and localhost
Performing DNS SRV lookups for hosts that are already direct IP addresses or special-case hostnames like 'localhost' is unnecessary. In addition, several related test suite improvements have been included: - A bug in the Bedrock mock packet creation was fixed where the magic GUID was being written to an incorrect buffer offset. - The DNS mocking strategy in the Java tests has been refactored for better accuracy by mocking the `dns.promises.Resolver` class. - An error test for the Bedrock pinger was corrected to properly handle a promise rejection instead of a synchronous throw.
This commit is contained in:
75
lib/java.js
75
lib/java.js
@ -5,7 +5,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
import net from "node:net";
|
||||
import { createConnection, isIP } from "node:net";
|
||||
import { Resolver } from "node:dns/promises";
|
||||
import createDebug from "debug";
|
||||
import * as varint from "./varint.js";
|
||||
@ -147,39 +147,60 @@ export async function pingJava(host, options = {}) {
|
||||
let targetHost = host;
|
||||
let targetPort = fallbackPort;
|
||||
|
||||
try {
|
||||
// A list of hostnames that should never have an SRV lookup.
|
||||
const nonSrvLookableHostnames = ["localhost"];
|
||||
|
||||
// Check if the host is a valid IP address (v4 or v6).
|
||||
// net.isIP() returns 0 for invalid IPs, 4 for IPv4, and 6 for IPv6.
|
||||
const isDirectIp = isIP(host) !== 0;
|
||||
const isNonLookableHostname = nonSrvLookableHostnames.includes(
|
||||
host.toLowerCase()
|
||||
);
|
||||
|
||||
if (isDirectIp || isNonLookableHostname) {
|
||||
debug(
|
||||
"attempting SRV lookup for _minecraft._tcp.%s with %dms timeout",
|
||||
host,
|
||||
timeout
|
||||
"host '%s' is a direct IP or a non-lookable hostname, skipping SRV lookup.",
|
||||
host
|
||||
);
|
||||
const resolver = new Resolver({ timeout, tries: 3 });
|
||||
const srvRecords = await resolver.resolveSrv(`_minecraft._tcp.${host}`);
|
||||
if (srvRecords.length > 0) {
|
||||
targetHost = srvRecords[0].name;
|
||||
targetPort = srvRecords[0].port;
|
||||
debug("SRV lookup successful, new target: %s:%d", targetHost, targetPort);
|
||||
}
|
||||
} catch (err) {
|
||||
// Common errors like ENODATA, ENOTFOUND, or a DNS timeout (ETIMEOUT) are expected
|
||||
// when a server does not have an SRV record, so we ignore them and proceed.
|
||||
const nonFatalDnsCodes = ["ENODATA", "ENOTFOUND", "ETIMEOUT"];
|
||||
if (
|
||||
err instanceof Error &&
|
||||
"code" in err &&
|
||||
nonFatalDnsCodes.includes(err.code)
|
||||
) {
|
||||
debug("SRV lookup for %s failed (%s), using fallback.", host, err.code);
|
||||
} else {
|
||||
// Re-throw anything else to fail the operation
|
||||
debug("SRV lookup for %s failed unexpectedly, re-throwing.", host, err);
|
||||
throw err;
|
||||
} else {
|
||||
try {
|
||||
debug(
|
||||
"attempting SRV lookup for _minecraft._tcp.%s with %dms timeout",
|
||||
host,
|
||||
timeout
|
||||
);
|
||||
const resolver = new Resolver({ timeout, tries: 3 });
|
||||
const srvRecords = await resolver.resolveSrv(`_minecraft._tcp.${host}`);
|
||||
if (srvRecords.length > 0) {
|
||||
targetHost = srvRecords[0].name;
|
||||
targetPort = srvRecords[0].port;
|
||||
debug(
|
||||
"SRV lookup successful, new target: %s:%d",
|
||||
targetHost,
|
||||
targetPort
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
// Common errors like ENODATA, ENOTFOUND, or a DNS timeout (ETIMEOUT) are expected
|
||||
// when a server does not have an SRV record, so we ignore them and proceed.
|
||||
const nonFatalDnsCodes = ["ENODATA", "ENOTFOUND", "ETIMEOUT"];
|
||||
if (
|
||||
err instanceof Error &&
|
||||
"code" in err &&
|
||||
nonFatalDnsCodes.includes(err.code)
|
||||
) {
|
||||
debug("SRV lookup for %s failed (%s), using fallback.", host, err.code);
|
||||
} else {
|
||||
// Re-throw anything else to fail the operation
|
||||
debug("SRV lookup for %s failed unexpectedly, re-throwing.", host, err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
debug("creating TCP connection to %s:%d", targetHost, targetPort);
|
||||
const socket = net.createConnection({ host: targetHost, port: targetPort });
|
||||
const socket = createConnection({ host: targetHost, port: targetPort });
|
||||
|
||||
// Prevent cleanup tasks from running more than once
|
||||
// in case of multiple error callbacks
|
||||
|
Reference in New Issue
Block a user