Skip to content

Commit 9614dea

Browse files
committed
Fix client error events with unknown protocol & direct conns
Without this, direct conns would go into the unknown protocol handler if they weren't HTTP, and would then get through to clientError if they couldn't be forwarded, but we didn't include the normal client error data so no useful debug info or context or error codes were provided. We now expose useful error codes for these cases, and include all the raw data required to typically provide a bit of a glimpse of the raw data that's being sent here. This shouldn't really come up - almost all unknown protocol handling should really use SOCKS or CONNECT tunnels to avoid this - but when it does it's good to get proper info.
1 parent 7c4319a commit 9614dea

File tree

1 file changed

+15
-7
lines changed

1 file changed

+15
-7
lines changed

src/server/http-combo-server.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as http2 from 'http2';
99
import * as semver from 'semver';
1010
import { makeDestroyable, DestroyableServer } from 'destroyable-server';
1111
import * as httpolyglot from '@httptoolkit/httpolyglot';
12-
import { delay, unreachableCheck } from '@httptoolkit/util';
12+
import { CustomError, delay, unreachableCheck } from '@httptoolkit/util';
1313
import {
1414
calculateJa3FromFingerprintData,
1515
calculateJa4FromHelloData,
@@ -263,18 +263,26 @@ export async function createComboServer(options: ComboServerOptions): Promise<De
263263
const tunnelAddress = socket[LastTunnelAddress];
264264

265265
try {
266+
let error: Error | undefined;
266267
if (!tunnelAddress) {
267-
server.emit('clientError', new Error('Unknown protocol without destination'), socket);
268-
return;
268+
error = new CustomError('Unknown protocol without destination', {
269+
code: 'UNKNOWN_PROTOCOL_NO_DESTINATION'
270+
});
271+
} else if (!tunnelAddress.includes(':')) {
272+
// Both CONNECT & SOCKS require a port, so this shouldn't happen
273+
error = new CustomError('Unknown protocol without destination port', {
274+
code: 'UNKNOWN_PROTOCOL_NO_DESTINATION_PORT'
275+
});
269276
}
270277

271-
if (!tunnelAddress.includes(':')) {
272-
// Both CONNECT & SOCKS require a port, so this shouldn't happen
273-
server.emit('clientError', new Error('Unknown protocol without destination port'), socket);
278+
if (error) {
279+
// Attach what data we have for debugging later:
280+
(error as any).rawPacket = socket.read();
281+
server.emit('clientError', error, socket);
274282
return;
275283
}
276284

277-
const { hostname, port } = getDestination('unknown', tunnelAddress); // Has port, so no protocol required
285+
const { hostname, port } = getDestination('unknown', tunnelAddress!); // Has port, so no protocol required
278286
options.rawPassthroughListener(socket, hostname, port);
279287
} catch (e) {
280288
console.error('Unknown protocol server error', e);

0 commit comments

Comments
 (0)