Skip to content

Commit

Permalink
Add relevant errors tags to passthrough-abort events
Browse files Browse the repository at this point in the history
  • Loading branch information
pimterry committed Feb 24, 2025
1 parent f264c37 commit efdd1e9
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 32 deletions.
35 changes: 35 additions & 0 deletions src/rules/passthrough-handling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
CADefinition,
PassThroughLookupOptions
} from './passthrough-handling-definitions';
import { ErrorLike } from '../util/error';

// TLS settings for proxied connections, intended to avoid TLS fingerprint blocking
// issues so far as possible, by closely emulating a Firefox Client Hello:
Expand Down Expand Up @@ -379,4 +380,38 @@ export async function getClientRelativeHostname(
} else {
return hostname;
}
}

export function buildUpstreamErrorTags(e: ErrorLike) {
const tags: string[] = [];

// OpenSSL can throw all sorts of weird & wonderful errors here, and rarely exposes a
// useful error code from them. To handle that, we try to detect the most common cases,
// notable including the useless but common 'unsupported' error that covers all
// OpenSSL-unsupported (e.g. legacy) configurations.
if (!e.code && e.stack?.split('\n')[1]?.includes('node:internal/tls/secure-context')) {
let tlsErrorTag: string;
if (e.message === 'unsupported') {
e.code = 'ERR_TLS_CONTEXT_UNSUPPORTED';
tlsErrorTag = 'context-unsupported';
e.message = 'Unsupported TLS configuration';
} else {
e.code = 'ERR_TLS_CONTEXT_UNKNOWN';
tlsErrorTag = 'context-unknown';
e.message = `TLS context error: ${e.message}`;
}

tags.push(`passthrough-tls-error:${tlsErrorTag}`);
}

// All raw error codes are included in the tags:
tags.push('passthrough-error:' + e.code);

// We build tags for by SSL alerts, for each recognition elsewhere:
const tlsAlertMatch = /SSL alert number (\d+)/.exec(e.message ?? '');
if (tlsAlertMatch) {
tags.push('passthrough-tls-error:ssl-alert-' + tlsAlertMatch[1]);
}

return tags;
}
36 changes: 4 additions & 32 deletions src/rules/requests/request-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ import {
shouldUseStrictHttps,
getClientRelativeHostname,
getDnsLookupFunction,
getTrustedCAs
getTrustedCAs,
buildUpstreamErrorTags
} from '../passthrough-handling';

import {
Expand Down Expand Up @@ -1123,6 +1124,7 @@ export class PassThroughHandler extends PassThroughHandlerDefinition {

options.emitEventCallback('passthrough-abort', {
downstreamAborted: !!(serverReq?.aborted),
tags: buildUpstreamErrorTags(e),
error: {
name: e.name,
code: e.code,
Expand Down Expand Up @@ -1180,37 +1182,7 @@ export class PassThroughHandler extends PassThroughHandlerDefinition {
}
})().catch(reject)
).catch((e: ErrorLike) => {
if (!e.code && e.stack?.split('\n')[1]?.includes('node:internal/tls/secure-context')) {
// OpenSSL can throw all sorts of weird & wonderful errors here, and rarely exposes a
// useful error code from them. To handle that, we try to detect the most common cases,
// notable including the useless but common 'unsupported' error that covers all
// OpenSSL-unsupported (e.g. legacy) configurations.

let tlsErrorTag: string;
if (e.message === 'unsupported') {
e.code = 'ERR_TLS_CONTEXT_UNSUPPORTED';
tlsErrorTag = 'context-unsupported';
e.message = 'Unsupported TLS configuration';
} else {
e.code = 'ERR_TLS_CONTEXT_UNKNOWN';
tlsErrorTag = 'context-unknown';
e.message = `TLS context error: ${e.message}`;
}

clientRes.tags.push(`passthrough-tls-error:${tlsErrorTag}`);
}

// All errors anywhere above (thrown or from explicit reject()) should end up here.

// We tag the response with the error code, for debugging from events:
clientRes.tags.push('passthrough-error:' + e.code);

// Tag responses, so programmatic examination can react to this
// event, without having to parse response data or similar.
const tlsAlertMatch = /SSL alert number (\d+)/.exec(e.message ?? '');
if (tlsAlertMatch) {
clientRes.tags.push('passthrough-tls-error:ssl-alert-' + tlsAlertMatch[1]);
}
clientRes.tags.push(...buildUpstreamErrorTags(e));

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

0 comments on commit efdd1e9

Please sign in to comment.