@@ -151,7 +151,9 @@ function combineSets<T>(...sets: ReadonlySet<T>[]): ReadonlySet<T> {
151
151
return new Set ( result ) ;
152
152
}
153
153
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
+ } {
155
157
const keys = _ . uniq ( _ . flatMap ( setMaps , ( mapping ) => Object . keys ( mapping ) ) ) ;
156
158
157
159
return _ . fromPairs (
@@ -163,6 +165,12 @@ function combineSetMaps<T>(...setMaps: Array<{ [key: string]: ReadonlySet<T> }>)
163
165
) ;
164
166
}
165
167
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
+
166
174
/**
167
175
* Network monitors tracks which networks the intercepted containers are connected to, and
168
176
* monitors the network aliases & IPs accessible on those networks.
@@ -192,7 +200,7 @@ class DockerNetworkMonitor {
192
200
193
201
private readonly networkTargets : {
194
202
[ networkId : string ] : {
195
- [ hostname : string ] : ReadonlySet < string >
203
+ [ hostname : string ] : ReadonlySet < string | HostGateway >
196
204
}
197
205
} = mobx . observable ( { } ) ;
198
206
@@ -206,20 +214,34 @@ class DockerNetworkMonitor {
206
214
return new Set ( [
207
215
..._ . flatten (
208
216
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
+ )
213
223
)
214
224
] ) ;
215
225
}
216
226
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.
218
230
get aliasIpMap ( ) : { [ host : string ] : ReadonlySet < string > } {
219
- return combineSetMaps ( ...Object . values ( this . networkTargets ) , {
231
+ const aliasMap = combineSetMaps ( ...Object . values ( this . networkTargets ) , {
220
232
// The Docker hostname always maps to the host's localhost, and it's not automatically included
221
233
// 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
+ }
223
245
} ) ;
224
246
}
225
247
@@ -281,7 +303,9 @@ class DockerNetworkMonitor {
281
303
return isInterceptedContainer ( container , this . proxyPort ) ;
282
304
}
283
305
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
+ > {
285
309
const networkDetails : Docker . NetworkInspectInfo = await this . docker . getNetwork ( networkId ) . inspect ( ) ;
286
310
const isDefaultBridge = networkDetails . Options ?. [ 'com.docker.network.bridge.default_bridge' ] === 'true' ;
287
311
@@ -304,7 +328,14 @@ class DockerNetworkMonitor {
304
328
return undefined ;
305
329
}
306
330
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
+
308
339
309
340
/*
310
341
* So, what names are resolveable on a network?
@@ -370,7 +401,7 @@ class DockerNetworkMonitor {
370
401
const alias = hostParts [ 0 ] ;
371
402
const target = hostParts . slice ( 1 ) . join ( ':' ) ;
372
403
const targetIp = target === 'host-gateway'
373
- ? '127.0.0.1'
404
+ ? HostGateway
374
405
: target ;
375
406
return [ alias , targetIp ] as const
376
407
} )
@@ -417,6 +448,6 @@ class DockerNetworkMonitor {
417
448
if ( ! aliasMap [ alias ] ) aliasMap [ alias ] = new Set ( ) ;
418
449
aliasMap [ alias ] . add ( target ) ;
419
450
return aliasMap ;
420
- } , { } as { [ alias : string ] : Set < string > } ) ;
451
+ } , { } as { [ alias : string ] : Set < string | HostGateway > } ) ;
421
452
}
422
453
}
0 commit comments