Как подключиться к приложению, установленному на хосте, из WSL2?
Как из WSL2 с установленной Ubuntu 18 подключиться к Windows-приложению, установленому хосте?
Когда из командной строки Windows я выполняю следующую команду:
telnet 127.0.0.1 9876
я получаю запись в логе, что установлено соединение.
Когда я делаю то же самое из терминала WSL Ubuntu, соединение не устанавливается.
Пробовал IP 127.0.1.1, но он тоже не работает.
Как соединиться из WSL c хостом?
Ответы (1 шт):
Может кому-то будет полезно.
UPDATE
По-умолчанию WSL2 поднимает сеть в режиме NAT, в этом режиме WSL2 функционирует в изолированной виртуальной машине, доступ в сеть через виртуальный vEthernet интерфейс.
Начиная с Windows 11 22H2 в WSL2 есть поддержка сетевого режима mirrored. В этом режиме все интерфейсы Windows транслированы внутрь WSL2, в том числе Localhost, а маршрут по-умолчанию строится через шлюз Windows.
Для этого создайте файл C:\Users\<user>\.wslconfig
[wsl2]
networkingMode = mirrored
и перезагрузите WSL2
wsl --shutdown
В режиме mirrored WSL2 loopback тождественнен Windows loopback.
- Я запустил echo server в Windows 127.0.0.1, из WSL2 делаю netcat. Лог сервера
Serving on ('127.0.0.1', 9876)
Connection from ('127.0.0.1', 45906)
Received: hello
Connection closed: ('127.0.0.1', 45906)
Видно, что соединение открывается с loopback интерфейса Windows.
- В обратную сторону тоже работает. В WSL2
python3 echo-server.py
В Windows
PS> Test-NetConnection -ComputerName 127.0.0.1 -Port 9876
ComputerName : 127.0.0.1
RemoteAddress : 127.0.0.1
RemotePort : 9876
InterfaceAlias : Loopback Pseudo-Interface 1
SourceAddress : 127.0.0.1
TcpTestSucceeded : True
Лог сервера
Serving on ('127.0.0.1', 9876)
Connection from ('127.0.0.1', 51736)
Connection closed: ('127.0.0.1', 51736)
ИТОГО. В режиме mirrored сетевые соединения между WSL2 и Windows работают в обе стороны.
Первый ответ
WSL2 выполняет Linux в виртуальной машине. Ядро, выполняемое в этой виртуалке, создает свой набор сетевых интерфейсов, не связанный с сетевыми интерфейсами в хосте Windows.
Ядро WSL2 подпилено таким образом, что серверные порты, которые открыты в WSL2 localhost, автоматически форвардятся в Windows [1]. То есть, если вы в WSL2 запустите какой-то сервер на порту 9876, то к нему можно будет подключиться в Windows на
localhost:9876НО! в обратную сторону это не работает. Серверные порты, открытые в Windows, не видны в WSL2.
Вам нужно каким-то образом транслировать искомый сервис 9876 на сетевой интерфейс WSL2, который виден в WSL2 по адресу
ip route show default | awk '{print $3}'
Вариант 1
Если это ваш сервис, измените его так, чтобы он был открыт на 0.0.0.0. Тогда он будет привязан ко всем интерфейсам в системе, в том числе к виртуальному интерфейсу WSL.
Вариант 2
Сразу признаюсь, у меня не заработало
$wslIp = (Get-NetIPAddress -InterfaceAlias "vEthernet (WSL (Hyper-V firewall))" -AddressFamily IPv4).IPAddress
netsh interface portproxy add v4tov4 listenaddress=$wslIp listenport=9876 connectaddress=127.0.0.1 connectport=9876
интернеты уверяют, что сервис iphlpsvc откроет прокси на $wslIp:9876 для 127.0.0.1:9876, но, повторюсь, у меня не заработало, и я не стал разбираться.
Вариант 3
Поднимите прокси, который будет обмениваться трафиком между $wslIp:9876 и 127.0.0.1:9876
Например, вот скрипт на Python
import psutil
import asyncio
import sys
def get_wsl_address():
"""
Returns IPv4 address of the WSL interface
"""
for iface_name, addrs in psutil.net_if_addrs().items():
if "WSL" in iface_name:
for addr in addrs:
if addr.family == 2: # AF_INET
return addr.address
return None
async def handle_proxy(client_reader, client_writer, port):
"""
Handles a proxy connection between the client (WSL) and the server (localhost).
Exchanges traffic between WSL endpoint and `localhost:<port>`
Parameters:
- client_reader: The reader for the client connection (from WSL).
- client_writer: The writer for the client connection (to WSL).
- port: The port to connect to on localhost.
"""
peer_name = client_writer.get_extra_info('peername')
print(f"New connection from {peer_name}")
try:
# Connect to localhost
server_reader, server_writer = await asyncio.open_connection('127.0.0.1', port)
async def forward(reader, writer):
try:
while True:
data = await reader.read(4096)
if not data:
break
writer.write(data)
await writer.drain()
except Exception:
pass
finally:
writer.close()
await writer.wait_closed()
# Bidirectional forwarding
await asyncio.gather(
forward(client_reader, server_writer),
forward(server_reader, client_writer)
)
except Exception:
pass
finally:
print(f"Closing connection from {peer_name}")
server_writer.close()
await server_writer.wait_closed()
client_writer.close()
await client_writer.wait_closed()
async def start_proxy(port):
"""
Starts Windows-localhost-to-WSL proxying.
Opens a server socket at WSL vEthernet interface and forwards traffic to `localhost:<port>`.
The same port is used at WSL vEthernet interface.
Parameter:
- port: The port to connect to on localhost.
"""
wsl_addr = get_wsl_address()
if not wsl_addr:
print("WSL address not found")
return
server = await asyncio.start_server(
lambda r, w: handle_proxy(r, w, port),
wsl_addr, port
)
async with server:
await server.serve_forever()
if __name__ == "__main__":
port = int(sys.argv[1]) if len(sys.argv) > 1 else None
if port is not None:
asyncio.run(start_proxy(port))
else:
print("Usage: python proxy.py <port>")
sys.exit(1)
Пример
В Windows я запустил простой echo server
import asyncio
async def handle_client(reader, writer):
addr = writer.get_extra_info('peername')
print(f'Client connected: {addr}')
try:
while True:
data = await reader.readline()
if not data:
break
message = data.decode().rstrip()
print(f'Message from client {addr}: {message}')
writer.write(data)
await writer.drain()
except Exception as e:
print(f'Error with client {addr}: {e}')
finally:
print(f'Client disconnected: {addr}')
writer.close()
await writer.wait_closed()
async def main():
server = await asyncio.start_server(handle_client, '127.0.0.1', 9876)
addr = server.sockets[0].getsockname()
print(f'Server started on {addr}')
async with server:
await server.serve_forever()
if __name__ == '__main__':
asyncio.run(main())
python .\echo-server.py
Затем запустил прокси
python .\proxy.py 9876
В WSL запустил netcat
echo "Hello!" | nc -N $(ip route show default | awk '{print $3}') 9876
Логи:
netcat-- ничего (опция -N сразу завершает, не печатает ответ сервера)proxy
АдресNew connection from ('172.27.157.123', 47952) Closing connection from ('172.27.157.123', 47952)172.27.157.123- это адрес моей убунты в WSL- эхо-сервер
здесь порт - это клиентский порт прокси, а сообщениеServer started on ('127.0.0.1', 9876) Client connected: ('127.0.0.1', 59614) Message from client ('127.0.0.1', 59614): Hello! Client disconnected: ('127.0.0.1', 59614)Hello!переслано от WSL.
Работает.
[1]: при условии, что в .wslconfig установлена опция localhostForwarding (по-умолчанию установлена)