mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:10:43 +07:00
PY-59608: Support `wslproxy` when routing is broken by VPN.
fixup! PY-59608: Support ``wslproxy`` when routing is broken by VPN. When user runs VPN with default gateway pointing to the VPN server and configures interface weight, we can't connect to WSL using its egress IP (traffic to ``172.0.0.0/8`` goes to VPN instead of WSL). With ``wsl.proxy.connect.localhost`` enabled in registry we bind ``wslproxy`` to ``127.0.0.1`` which could be used in latest WSL2 to connect from Windows to Linux. It is a little bit slow, but still works. fixup! PY-59608: Support ``wslproxy`` when routing is broken by VPN. PY-59608: Support ``wslproxy`` when routing is broken by VPN. When user runs VPN with default gateway pointing to the VPN server and configures interface weight, we can't connect to WSL using its egress IP (traffic to ``172.0.0.0/8`` goes to VPN instead of WSL). With ``wsl.proxy.connect.localhost`` enabled in registry we bind ``wslproxy`` to ``127.0.0.1`` which could be used in latest WSL2 to connect from Windows to Linux. It is a little bit slow, but still works. Co-authored-by: Vladimir Lagunov <vladimir.lagunov@jetbrains.com> Merge-request: IJ-MR-105285 Merged-by: Ilya Kazakevich <ilya.kazakevich@jetbrains.com> GitOrigin-RevId: 74b5ad4df9c5e95ca4ef53a465f07855a92aa324
This commit is contained in:
committed by
intellij-monorepo-bot
parent
394380290d
commit
eb7bca7328
Binary file not shown.
@@ -12,7 +12,8 @@
|
||||
|
||||
// See svg file and wslproxy_test_client.py
|
||||
|
||||
// When started, prints egress (eth0) IP addr as 4 bytes. Then, 2 bytes of ingress (loopback) port.
|
||||
// When started, prints egress (eth0) IP addr as 4 bytes (or it might use 127.0.0.1 which is possible for WSL2, see args)
|
||||
// Then, 2 bytes of ingress (loopback) port.
|
||||
// App running on WSL connects to this port.
|
||||
// Tool then opens egress (eth0) port and prints it as 2 bytes.
|
||||
// Windows client connects to it and talks to WSL app connected to the ingress port.
|
||||
@@ -20,6 +21,7 @@
|
||||
|
||||
// Threads are unbound, but it should not be a problem unless you create lots of connections
|
||||
|
||||
// To use 127.0.0.1 instead of eth0 address (for cases like VPN on Windows side) provide arg "--loopback"
|
||||
|
||||
// Will listen egress in this port
|
||||
#define JB_EGRESS_INTERFACE "eth0"
|
||||
@@ -186,9 +188,10 @@ _Noreturn static void *jb_listen_ingress(const int *p_ingress_srv_sock_fd) {
|
||||
|
||||
static int g_ingress_srv_sock_fd;
|
||||
|
||||
int main(void) {
|
||||
g_egress_ip = jb_get_wsl_public_ip();
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// '--loopback' means use 127.0.0.1 as egress IP
|
||||
g_egress_ip = (argc > 1 && strcmp(&argv[1][0], "--loopback") == 0) ? htonl(INADDR_LOOPBACK)
|
||||
: jb_get_wsl_public_ip();
|
||||
// IP address
|
||||
write(STDOUT_FILENO, &g_egress_ip, sizeof g_egress_ip);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ def read_stderr(stderr):
|
||||
print(f"STDERR: {text}")
|
||||
|
||||
|
||||
process = subprocess.Popen("./wslproxy", shell=False,
|
||||
process = subprocess.Popen(["./wslproxy", "--loopback"], shell=False,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
@@ -153,6 +153,9 @@
|
||||
<registryKey key="wsl.obtain.windows.host.ip.alternatively" os="windows" defaultValue="true" restartRequired="true"
|
||||
description="Obtain Windows host machine IP alternatively (not using the recommended 'cat /etc/resolv.conf | grep nameserver')."/>
|
||||
|
||||
<registryKey key="wsl.proxy.connect.localhost" os="windows" defaultValue="false" restartRequired="false"
|
||||
description="Connect to 127.0.0.1 on WSLProxy instead of public WSL IP which might be inaccessible due to routing issues"/>
|
||||
|
||||
<virtualFileSystem implementationClass="com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl" key="file" physical="true"/>
|
||||
<virtualFileSystem implementationClass="com.intellij.openapi.vfs.impl.jar.JarFileSystemImpl" key="jar" physical="true"/>
|
||||
<virtualFileSystem implementationClass="com.intellij.openapi.vfs.ex.temp.TempFileSystem" key="temp" physical="true"/>
|
||||
|
||||
@@ -3,10 +3,10 @@ package com.intellij.execution.wsl
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import io.ktor.network.selector.ActorSelectorManager
|
||||
import io.ktor.network.sockets.aSocket
|
||||
import io.ktor.network.sockets.openReadChannel
|
||||
import io.ktor.network.sockets.openWriteChannel
|
||||
import io.ktor.network.sockets.*
|
||||
import io.ktor.utils.io.ByteReadChannel
|
||||
import io.ktor.utils.io.ByteWriteChannel
|
||||
import io.ktor.utils.io.close
|
||||
@@ -36,6 +36,22 @@ import kotlin.coroutines.coroutineContext
|
||||
*/
|
||||
class WslProxy(distro: AbstractWslDistribution, private val applicationPort: Int) : Disposable {
|
||||
private companion object {
|
||||
/**
|
||||
* Server might not be opened yet. Since non-blocking Ktor API doesn't wait for it but throws exception instead, we retry
|
||||
*/
|
||||
private tailrec suspend fun TcpSocketBuilder.tryConnect(host: String, port: Int, attemptRemains: Int = 10): Socket {
|
||||
try {
|
||||
return connect(host, port)
|
||||
}
|
||||
catch (e: IOException) {
|
||||
if (attemptRemains <= 0) throw e
|
||||
thisLogger().warn("Can't connect to $host $port , will retry", e)
|
||||
delay(100)
|
||||
}
|
||||
return tryConnect(host, port, attemptRemains - 1)
|
||||
}
|
||||
|
||||
|
||||
suspend fun connectChannels(source: ByteReadChannel, dest: ByteWriteChannel) {
|
||||
val buffer = ByteBuffer.allocate(4096)
|
||||
while (coroutineContext.isActive) {
|
||||
@@ -97,7 +113,8 @@ class WslProxy(distro: AbstractWslDistribution, private val applicationPort: Int
|
||||
private suspend fun readPortFromChannel(channel: ByteReadChannel): Int = readToBuffer(channel, 2).short.toUShort().toInt()
|
||||
|
||||
init {
|
||||
val wslCommandLine = runBlocking { distro.getTool("wslproxy") }
|
||||
val args = if (Registry.`is`("wsl.proxy.connect.localhost")) arrayOf("--loopback") else emptyArray()
|
||||
val wslCommandLine = runBlocking { distro.getTool("wslproxy", *args) }
|
||||
val process = Runtime.getRuntime().exec(wslCommandLine.commandLineString)
|
||||
val log = Logger.getInstance(WslProxy::class.java)
|
||||
|
||||
@@ -136,10 +153,16 @@ class WslProxy(distro: AbstractWslDistribution, private val applicationPort: Int
|
||||
|
||||
private suspend fun clientConnected(linuxEgressPort: Int) {
|
||||
val winToLin = scope.async {
|
||||
aSocket(ActorSelectorManager(scope.coroutineContext)).tcp().connect(wslLinuxIp, linuxEgressPort)
|
||||
thisLogger().info("Connecting to WSL: $wslLinuxIp:$linuxEgressPort")
|
||||
val socket = aSocket(ActorSelectorManager(scope.coroutineContext)).tcp().tryConnect(wslLinuxIp, linuxEgressPort)
|
||||
thisLogger().info("Connected to WSL")
|
||||
socket
|
||||
}
|
||||
val winToWin = scope.async {
|
||||
aSocket(ActorSelectorManager(scope.coroutineContext)).tcp().connect("127.0.0.1", applicationPort)
|
||||
thisLogger().info("Connecting to app: $127.0.0.1:$applicationPort")
|
||||
val socket = aSocket(ActorSelectorManager(scope.coroutineContext)).tcp().tryConnect("127.0.0.1", applicationPort)
|
||||
thisLogger().info("Connected to app")
|
||||
socket
|
||||
}
|
||||
scope.launch {
|
||||
val winToLinSocket = winToLin.await()
|
||||
|
||||
Reference in New Issue
Block a user