Skip to content

Commit efdd1e9

Browse files
committed
Add relevant errors tags to passthrough-abort events
1 parent f264c37 commit efdd1e9

File tree

2 files changed

+39
-32
lines changed

2 files changed

+39
-32
lines changed

src/rules/passthrough-handling.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
CADefinition,
2323
PassThroughLookupOptions
2424
} from './passthrough-handling-definitions';
25+
import { ErrorLike } from '../util/error';
2526

2627
// TLS settings for proxied connections, intended to avoid TLS fingerprint blocking
2728
// issues so far as possible, by closely emulating a Firefox Client Hello:
@@ -379,4 +380,38 @@ export async function getClientRelativeHostname(
379380
} else {
380381
return hostname;
381382
}
383+
}
384+
385+
export function buildUpstreamErrorTags(e: ErrorLike) {
386+
const tags: string[] = [];
387+
388+
// OpenSSL can throw all sorts of weird & wonderful errors here, and rarely exposes a
389+
// useful error code from them. To handle that, we try to detect the most common cases,
390+
// notable including the useless but common 'unsupported' error that covers all
391+
// OpenSSL-unsupported (e.g. legacy) configurations.
392+
if (!e.code && e.stack?.split('\n')[1]?.includes('node:internal/tls/secure-context')) {
393+
let tlsErrorTag: string;
394+
if (e.message === 'unsupported') {
395+
e.code = 'ERR_TLS_CONTEXT_UNSUPPORTED';
396+
tlsErrorTag = 'context-unsupported';
397+
e.message = 'Unsupported TLS configuration';
398+
} else {
399+
e.code = 'ERR_TLS_CONTEXT_UNKNOWN';
400+
tlsErrorTag = 'context-unknown';
401+
e.message = `TLS context error: ${e.message}`;
402+
}
403+
404+
tags.push(`passthrough-tls-error:${tlsErrorTag}`);
405+
}
406+
407+
// All raw error codes are included in the tags:
408+
tags.push('passthrough-error:' + e.code);
409+
410+
// We build tags for by SSL alerts, for each recognition elsewhere:
411+
const tlsAlertMatch = /SSL alert number (\d+)/.exec(e.message ?? '');
412+
if (tlsAlertMatch) {
413+
tags.push('passthrough-tls-error:ssl-alert-' + tlsAlertMatch[1]);
414+
}
415+
416+
return tags;
382417
}

src/rules/requests/request-handlers.ts

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ import {
7979
shouldUseStrictHttps,
8080
getClientRelativeHostname,
8181
getDnsLookupFunction,
82-
getTrustedCAs
82+
getTrustedCAs,
83+
buildUpstreamErrorTags
8384
} from '../passthrough-handling';
8485

8586
import {
@@ -1123,6 +1124,7 @@ export class PassThroughHandler extends PassThroughHandlerDefinition {
11231124

11241125
options.emitEventCallback('passthrough-abort', {
11251126
downstreamAborted: !!(serverReq?.aborted),
1127+
tags: buildUpstreamErrorTags(e),
11261128
error: {
11271129
name: e.name,
11281130
code: e.code,
@@ -1180,37 +1182,7 @@ export class PassThroughHandler extends PassThroughHandlerDefinition {
11801182
}
11811183
})().catch(reject)
11821184
).catch((e: ErrorLike) => {
1183-
if (!e.code && e.stack?.split('\n')[1]?.includes('node:internal/tls/secure-context')) {
1184-
// OpenSSL can throw all sorts of weird & wonderful errors here, and rarely exposes a
1185-
// useful error code from them. To handle that, we try to detect the most common cases,
1186-
// notable including the useless but common 'unsupported' error that covers all
1187-
// OpenSSL-unsupported (e.g. legacy) configurations.
1188-
1189-
let tlsErrorTag: string;
1190-
if (e.message === 'unsupported') {
1191-
e.code = 'ERR_TLS_CONTEXT_UNSUPPORTED';
1192-
tlsErrorTag = 'context-unsupported';
1193-
e.message = 'Unsupported TLS configuration';
1194-
} else {
1195-
e.code = 'ERR_TLS_CONTEXT_UNKNOWN';
1196-
tlsErrorTag = 'context-unknown';
1197-
e.message = `TLS context error: ${e.message}`;
1198-
}
1199-
1200-
clientRes.tags.push(`passthrough-tls-error:${tlsErrorTag}`);
1201-
}
1202-
1203-
// All errors anywhere above (thrown or from explicit reject()) should end up here.
1204-
1205-
// We tag the response with the error code, for debugging from events:
1206-
clientRes.tags.push('passthrough-error:' + e.code);
1207-
1208-
// Tag responses, so programmatic examination can react to this
1209-
// event, without having to parse response data or similar.
1210-
const tlsAlertMatch = /SSL alert number (\d+)/.exec(e.message ?? '');
1211-
if (tlsAlertMatch) {
1212-
clientRes.tags.push('passthrough-tls-error:ssl-alert-' + tlsAlertMatch[1]);
1213-
}
1185+
clientRes.tags.push(...buildUpstreamErrorTags(e));
12141186

12151187
if ((e as any).causedByUpstreamError && !serverReq?.aborted) {
12161188
if (e.code === 'ECONNRESET' || e.code === 'ECONNREFUSED' || this.simulateConnectionErrors) {

0 commit comments

Comments
 (0)