@@ -151,7 +151,9 @@ function combineSets<T>(...sets: ReadonlySet<T>[]): ReadonlySet<T> {
151151 return new Set ( result ) ;
152152}
153153
154- function combineSetMaps < T > ( ...setMaps : Array < { [ key : string ] : ReadonlySet < T > } > ) : { [ key : string ] : ReadonlySet < T > } {
154+ function combineSetMaps < T > ( ...setMaps : Array < { [ key : string ] : ReadonlySet < T > } > ) : {
155+ [ key : string ] : ReadonlySet < T >
156+ } {
155157 const keys = _ . uniq ( _ . flatMap ( setMaps , ( mapping ) => Object . keys ( mapping ) ) ) ;
156158
157159 return _ . fromPairs (
@@ -163,6 +165,12 @@ function combineSetMaps<T>(...setMaps: Array<{ [key: string]: ReadonlySet<T> }>)
163165 ) ;
164166}
165167
168+ // We treat host gateway routes totally separately to other routes. They resolve to 127.0.0.1,
169+ // but from the *host* POV (not the container/tunnel) so we have to handle them separately.
170+ const HostGateway = Symbol ( 'host-gateway' ) ;
171+ type HostGateway = typeof HostGateway ;
172+ const HostGatewaySet = new Set < HostGateway > ( [ HostGateway ] ) ;
173+
166174/**
167175 * Network monitors tracks which networks the intercepted containers are connected to, and
168176 * monitors the network aliases & IPs accessible on those networks.
@@ -192,7 +200,7 @@ class DockerNetworkMonitor {
192200
193201 private readonly networkTargets : {
194202 [ networkId : string ] : {
195- [ hostname : string ] : ReadonlySet < string >
203+ [ hostname : string ] : ReadonlySet < string | HostGateway >
196204 }
197205 } = mobx . observable ( { } ) ;
198206
@@ -206,20 +214,34 @@ class DockerNetworkMonitor {
206214 return new Set ( [
207215 ..._ . flatten (
208216 Object . values ( this . networkTargets )
209- . map ( ( networkMap ) => Object . keys ( networkMap ) )
210- ) . filter ( ( host ) =>
211- // We don't reroute the host hostname - the host is accessible from the host already
212- host !== DOCKER_HOST_HOSTNAME
217+ . map ( ( networkMap ) =>
218+ Object . entries ( networkMap )
219+ // Exclude any aliases that might map to the host itself:
220+ . filter ( ( [ _alias , targets ] ) => ! [ ...targets ] . some ( t => t === HostGateway ) )
221+ . map ( ( [ alias ] ) => alias )
222+ )
213223 )
214224 ] ) ;
215225 }
216226
217- // The list of mappings per-network, binding aliases to their (0+) target IPs
227+ // The list of mappings per-network, binding aliases to their (0+) target IPs.
228+ // For aliases returned by dockerRoutedAliases, this should be the tunnel-relative
229+ // IP. For other aliases, this should be host-relative.
218230 get aliasIpMap ( ) : { [ host : string ] : ReadonlySet < string > } {
219- return combineSetMaps ( ...Object . values ( this . networkTargets ) , {
231+ const aliasMap = combineSetMaps ( ...Object . values ( this . networkTargets ) , {
220232 // The Docker hostname always maps to the host's localhost, and it's not automatically included
221233 // on platforms (Windows & Mac) where Docker resolves it implicitly.
222- [ DOCKER_HOST_HOSTNAME ] : new Set ( [ '127.0.0.1' ] )
234+ 'host.docker.internal' : HostGatewaySet
235+ } ) ;
236+
237+ return _ . mapValues ( aliasMap , ( targets ) : ReadonlySet < string > => {
238+ if ( [ ...targets ] . some ( t => t === HostGateway ) ) {
239+ // For all host-gateway targets, we simplify to direct traffic
240+ // directly back to the host itself:
241+ return new Set ( [ '127.0.0.1' ] ) ;
242+ } else {
243+ return targets as ReadonlySet < string > ;
244+ }
223245 } ) ;
224246 }
225247
@@ -281,7 +303,9 @@ class DockerNetworkMonitor {
281303 return isInterceptedContainer ( container , this . proxyPort ) ;
282304 }
283305
284- private async getNetworkAliases ( networkId : string ) : Promise < { [ host : string ] : ReadonlySet < string > } | undefined > {
306+ private async getNetworkAliases ( networkId : string ) : Promise <
307+ { [ host : string ] : ReadonlySet < string | HostGateway > } | undefined
308+ > {
285309 const networkDetails : Docker . NetworkInspectInfo = await this . docker . getNetwork ( networkId ) . inspect ( ) ;
286310 const isDefaultBridge = networkDetails . Options ?. [ 'com.docker.network.bridge.default_bridge' ] === 'true' ;
287311
@@ -304,7 +328,14 @@ class DockerNetworkMonitor {
304328 return undefined ;
305329 }
306330
307- const aliases : Array < readonly [ alias : string , targetIp : string ] > = [ ] ;
331+ const aliases : Array < readonly [ alias : string , targetIp : string | HostGateway ] > = [ ] ;
332+
333+ aliases . push ( [ 'host.docker.internal' , HostGateway ] ) ;
334+ aliases . push ( [ 'gateway.docker.internal' , HostGateway ] ) ; // Seems equivalent? Very rarely used AFAICT.
335+ // Deprecated but still functional Docker Desktop aliases:
336+ if ( process . platform === 'darwin' ) aliases . push ( [ 'docker.for.mac.localhost' , HostGateway ] ) ;
337+ if ( process . platform === 'win32' ) aliases . push ( [ 'docker.for.win.localhost' , HostGateway ] ) ;
338+
308339
309340 /*
310341 * So, what names are resolveable on a network?
@@ -370,7 +401,7 @@ class DockerNetworkMonitor {
370401 const alias = hostParts [ 0 ] ;
371402 const target = hostParts . slice ( 1 ) . join ( ':' ) ;
372403 const targetIp = target === 'host-gateway'
373- ? '127.0.0.1'
404+ ? HostGateway
374405 : target ;
375406 return [ alias , targetIp ] as const
376407 } )
@@ -417,6 +448,6 @@ class DockerNetworkMonitor {
417448 if ( ! aliasMap [ alias ] ) aliasMap [ alias ] = new Set ( ) ;
418449 aliasMap [ alias ] . add ( target ) ;
419450 return aliasMap ;
420- } , { } as { [ alias : string ] : Set < string > } ) ;
451+ } , { } as { [ alias : string ] : Set < string | HostGateway > } ) ;
421452 }
422453}
0 commit comments