@@ -17,9 +17,10 @@ import {
1717} from 'read-tls-client-hello' ;
1818import { URLPattern } from "urlpattern-polyfill" ;
1919
20- import { TlsHandshakeFailure } from '../types' ;
20+ import { Destination , TlsHandshakeFailure } from '../types' ;
2121import { getCA } from '../util/tls' ;
2222import { shouldPassThrough } from '../util/server-utils' ;
23+ import { getDestination } from '../util/url' ;
2324import {
2425 getParentSocket ,
2526 buildSocketTimingInfo ,
@@ -32,9 +33,8 @@ import {
3233 LastHopEncrypted ,
3334 TlsMetadata ,
3435 TlsSetupCompleted ,
35- getAddressAndPort ,
36- resetOrDestroy ,
37- SocketMetadata
36+ SocketMetadata ,
37+ resetOrDestroy
3838} from '../util/socket-util' ;
3939import { MockttpHttpsOptions } from '../mockttp' ;
4040import { buildSocksServer , SocksServerOptions , SocksTcpAddress } from './socks-server' ;
@@ -151,8 +151,8 @@ export interface ComboServerOptions {
151151
152152 requestListener : ( req : http . IncomingMessage , res : http . ServerResponse ) => void ;
153153 tlsClientErrorListener : ( socket : tls . TLSSocket , req : TlsHandshakeFailure ) => void ;
154- tlsPassthroughListener : ( socket : net . Socket , address : string , port ?: number ) => void ;
155- rawPassthroughListener : ( socket : net . Socket , address : string , port ?: number ) => void ;
154+ tlsPassthroughListener : ( socket : net . Socket , hostname : string , port ?: number ) => void ;
155+ rawPassthroughListener : ( socket : net . Socket , hostname : string , port ?: number ) => void ;
156156} ;
157157
158158// The low-level server that handles all the sockets & TLS. The server will correctly call the
@@ -249,19 +249,26 @@ export async function createComboServer(options: ComboServerOptions): Promise<De
249249
250250 if ( options . passthroughUnknownProtocols ) {
251251 unknownProtocolServer = net . createServer ( ( socket ) => {
252- const destination = socket [ LastTunnelAddress ] ;
253- if ( ! destination ) {
254- server . emit ( 'clientError' , new Error ( 'Unknown protocol without destination' ) , socket ) ;
255- return ;
256- }
252+ const tunnelAddress = socket [ LastTunnelAddress ] ;
257253
258- const [ host , port ] = getAddressAndPort ( destination ) ;
259- if ( ! port ) { // Both CONNECT & SOCKS require a port, so this shouldn't happen
260- server . emit ( 'clientError' , new Error ( 'Unknown protocol without destination port ' ) , socket ) ;
261- return ;
262- }
254+ try {
255+ if ( ! tunnelAddress ) {
256+ server . emit ( 'clientError' , new Error ( 'Unknown protocol without destination' ) , socket ) ;
257+ return ;
258+ }
263259
264- options . rawPassthroughListener ( socket , host , port ) ;
260+ if ( ! tunnelAddress . includes ( ':' ) ) {
261+ // Both CONNECT & SOCKS require a port, so this shouldn't happen
262+ server . emit ( 'clientError' , new Error ( 'Unknown protocol without destination port' ) , socket ) ;
263+ return ;
264+ }
265+
266+ const { hostname, port } = getDestination ( 'unknown' , tunnelAddress ) ; // Has port, so no protocol required
267+ options . rawPassthroughListener ( socket , hostname , port ) ;
268+ } catch ( e ) {
269+ console . error ( 'Unknown protocol server error' , e ) ;
270+ resetOrDestroy ( socket ) ;
271+ }
265272 } ) ;
266273 }
267274
@@ -432,7 +439,7 @@ function analyzeAndMaybePassThroughTls(
432439 server : tls . Server ,
433440 passthroughList : Required < MockttpHttpsOptions > [ 'tlsPassthrough' ] | undefined ,
434441 interceptOnlyList : Required < MockttpHttpsOptions > [ 'tlsInterceptOnly' ] | undefined ,
435- passthroughListener : ( socket : net . Socket , address : string , port ?: number ) => void
442+ passthroughListener : ( socket : net . Socket , hostname : string , port ?: number ) => void
436443) {
437444 if ( passthroughList && interceptOnlyList ) {
438445 throw new Error ( 'Cannot use both tlsPassthrough and tlsInterceptOnly options at the same time.' ) ;
@@ -450,23 +457,22 @@ function analyzeAndMaybePassThroughTls(
450457
451458 // SNI is a good clue for where the request is headed, but an explicit proxy address (via
452459 // CONNECT or SOCKS) is even better. Note that this may be a hostname or IPv4/6 address:
453- let upstreamHostname : string | undefined ;
454- let upstreamPort : number | undefined ;
460+ let upstreamDestination : Destination | undefined ;
455461 if ( socket [ LastTunnelAddress ] ) {
456- ( [ upstreamHostname , upstreamPort ] = getAddressAndPort ( socket [ LastTunnelAddress ] ) ) ;
462+ upstreamDestination = getDestination ( 'https' , socket [ LastTunnelAddress ] ) ;
457463 }
458464
459465 socket [ TlsMetadata ] = {
460466 sniHostname,
461- connectHostname : upstreamHostname ,
462- connectPort : upstreamPort ? .toString ( ) ,
467+ connectHostname : upstreamDestination ?. hostname ,
468+ connectPort : upstreamDestination ?. port . toString ( ) ,
463469 clientAlpn : helloData . alpnProtocols ,
464470 ja3Fingerprint : calculateJa3FromFingerprintData ( helloData . fingerprintData ) ,
465471 ja4Fingerprint : calculateJa4FromHelloData ( helloData )
466472 } ;
467473
468- if ( shouldPassThrough ( upstreamHostname , passThroughPatterns , interceptOnlyPatterns ) ) {
469- passthroughListener ( socket , upstreamHostname , upstreamPort ) ;
474+ if ( shouldPassThrough ( upstreamDestination ?. hostname , passThroughPatterns , interceptOnlyPatterns ) ) {
475+ passthroughListener ( socket , upstreamDestination . hostname , upstreamDestination . port ) ;
470476 return ; // Do not continue with TLS
471477 } else if ( shouldPassThrough ( sniHostname , passThroughPatterns , interceptOnlyPatterns ) ) {
472478 passthroughListener ( socket , sniHostname ! ) ; // Can't guess the port - not included in SNI
0 commit comments