fix: address review feedback for gRPC insecure TLS and DNS-over-TLS

This commit is contained in:
phatlet
2026-06-29 15:07:32 +07:00
parent 29fcd22e20
commit 4470346e23
7 changed files with 57 additions and 22 deletions
+11 -3
View File
@@ -153,11 +153,19 @@ function IsValidNameServer(nameServer: string): boolean {
return regex.test(nameServer);
}
function IsValidDnsResolver(resolver: string): boolean {
const ipType = ValidateIpAddress(resolver);
if (ipType === "IP4" || ipType === "IP6") {
const normalizedResolver = resolver.trim();
const ipv4Parts = normalizedResolver.split(".");
if (
ipv4Parts.length === 4 &&
ipv4Parts.every((part) => /^\d+$/.test(part) && Number(part) >= 0 && Number(part) <= 255)
) {
return true;
}
return IsValidHost(resolver);
const ipType = ValidateIpAddress(normalizedResolver);
if (ipType === "IP6") {
return true;
}
return IsValidHost(normalizedResolver);
}
const IsValidURL = function (url: string): boolean {
return /^(http|https):\/\/[^ "]+$/.test(url);
+21 -7
View File
@@ -90,13 +90,22 @@ class DNSResolver {
const onMessage = (message: Buffer) => {
clearTimeout(timeoutId);
// @ts-expect-error dns2 types are incomplete
const response = dns2.Packet.parse(message) as DNSResponse;
resolve(response);
socket.removeListener("message", onMessage);
try {
// @ts-expect-error dns2 types are incomplete
const response = dns2.Packet.parse(message) as DNSResponse;
resolve(response);
} catch (error) {
reject(error instanceof Error ? error : new Error(String(error)));
}
};
const timeoutId = setTimeout(() => {
socket.removeListener("message", onMessage);
socket.close();
if (this.socket === socket) {
this.socket = null;
}
reject(new Error(`DNS query timed out for ${domain} (${recordType}) via ${targetNameserver}`));
}, timeoutMs);
@@ -164,10 +173,15 @@ class DNSResolver {
if (expectedLength !== null && responseBuffer.length >= expectedLength + 2) {
cleanup();
const responseData = responseBuffer.subarray(2, 2 + expectedLength);
// @ts-expect-error dns2 types are incomplete
const response = dns2.Packet.parse(responseData) as DNSResponse;
socket.end();
resolve(response);
try {
// @ts-expect-error dns2 types are incomplete
const response = dns2.Packet.parse(responseData) as DNSResponse;
socket.destroy();
resolve(response);
} catch (error) {
socket.destroy();
reject(error instanceof Error ? error : new Error(String(error)));
}
}
});
+2 -3
View File
@@ -33,6 +33,7 @@ class DnsCall {
let values = this.monitor.type_data.values;
const configuredNameServer = this.monitor.type_data.nameServer?.trim() || undefined;
const transport = this.monitor.type_data.transport ?? "UDP";
const transportLabel = transport === "TLS" ? "DNS-over-TLS" : "DNS";
const queryStartTime = performance.now();
try {
@@ -44,7 +45,6 @@ class DnsCall {
allowSelfSignedCert: this.monitor.type_data.allowSelfSignedCert,
});
let latency = Math.round(performance.now() - queryStartTime);
const transportLabel = transport === "TLS" ? "DNS-over-TLS" : "DNS";
if (dnsRes[recordType] === undefined) {
return {
@@ -102,7 +102,6 @@ class DnsCall {
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const latency = Math.round(performance.now() - queryStartTime);
const transportLabel = transport === "TLS" ? "DNS-over-TLS" : "DNS";
return {
status: GC.DOWN,
latency,
@@ -114,7 +113,7 @@ class DnsCall {
status: GC.DOWN,
latency: Math.round(performance.now() - queryStartTime),
type: GC.REALTIME,
error_message: `DNS ${recordType} check did not return a definitive result for ${host}`,
error_message: `${transportLabel} ${recordType} check did not return a definitive result for ${host}`,
};
}
}
+4 -8
View File
@@ -74,18 +74,14 @@ class GrpcCall {
const credentials =
tls && insecure
? grpc.credentials.createSsl(null, null, null, { rejectUnauthorized: false })
? grpc.credentials.createSsl(null, null, null, {
checkServerIdentity: () => undefined,
})
: tls
? grpc.credentials.createSsl()
: grpc.credentials.createInsecure();
const clientOptions: grpc.ChannelOptions = {};
// Keep channel-level insecure knob for grpc-js compatibility.
if (tls && insecure) {
clientOptions["grpc-node.tls_reject_unauthorized"] = 0;
}
const client = new healthService(target, credentials, clientOptions);
const client = new healthService(target, credentials);
const deadline = new Date(Date.now() + timeoutMs);
const result = await new Promise<{ status: string }>((resolve, reject) => {
@@ -14,7 +14,7 @@ Configure:
- `matchType` (`ANY` or `ALL`, default `ANY`)
- at least one expected value in `values`
For UDP transport, `nameServer` is optional (leave blank for resolver defaults).
For UDP transport, `nameServer` is optional (leave blank to walk authoritative nameservers, then fall back to `8.8.8.8`).
For DNS-over-TLS (`transport: "TLS"`), `nameServer` is required.
@@ -45,6 +45,20 @@ Connection errors and timeouts return **DOWN**.
"port": 50051,
"service": "my.package.MyService",
"tls": true,
"timeout": 5000
}
}
```
### Self-signed TLS example {#self-signed-example}
```json
{
"type": "GRPC",
"type_data": {
"host": "grpc.example.com",
"port": 50051,
"tls": true,
"insecure": true,
"timeout": 5000
}
@@ -13,6 +13,10 @@
if (!data.timeout) data.timeout = 10000;
if (data.tls === undefined) data.tls = false;
if (data.insecure === undefined) data.insecure = false;
$effect(() => {
if (!data.tls) data.insecure = false;
});
</script>
<div class="space-y-4">