genotrance / px

An HTTP proxy server to automatically authenticate through an NTLM proxy
MIT License
950 stars 98 forks source link

hostonly and WSL2 #173

Open audetto opened 1 year ago

audetto commented 1 year ago

I am trying to find the simplest setup to use this on WSL2.

I have read https://github.com/genotrance/px/issues/149 but I think it could be even easier.

Basically --hostonly is not enough to cover WSL2.

I get

Client not allowed 172.18.88.214

even if the log has

proxy:hostonly = 1

On Windows I can see a WSL Ethernet adapter

image

So,

I wonder if px could not scan all these Virtual adapters and add them to the "local" adapters directly.

genotrance commented 1 year ago

The virtual adapter on the Px side is x.80. whereas the connection is coming from x.88. which is why Px rejects it.

audetto commented 1 year ago

the subnet mask is .240 not .255 172.18.88.* is in the networks defined by the IP+mask

audetto commented 1 year ago

https://github.com/genotrance/px/blob/faaa57c2e7bd06f1bc502e8a1d63b6911a667c27/px/main.py#L412-L417

this function will return the hostname which is 172.18.80.1, but it knows nothing about the local network behind it.

is there a python way to extract the subnet mask?

genotrance commented 1 year ago

The goal of --hostonly is to allow all apps running on that same host OS to access Px even if via different interfaces. It does not equate to VMs running on the host which will have a different IP, they are a different host. WSL2 uses a VM so you will need to specify the IP or a range via --allow like in #149 to make it work.

We want to be super careful who can authenticate via Px. --hostonly is a shortcut to simplify that specific case. There's no way to correctly guess that the subnet is a virtual network and even if we did, the admin might not want those apps in VMs to inherit access. It has to be explicit. We could come up with another shortcut but --gateway + --allow enable this already and can be very prescriptive.

audetto commented 1 year ago

The difference between "apps" and "VMs" is probably a bit blurred, especially when the doc says

This allows local apps as well as VM or container apps to use Px when in a NAT config.

but I totally understand that what I ask requires a deeper knowledge of the type of adapters each network uses and this might not be easy to extract.

dfillingham commented 1 year ago

The hostonly feature is fantastic at protecting security. The problem with WSL2 is that at every reboot it will grab a new random subnet to run it's virtual network on. If I was to open up allow to eg 172.17.0.0/16, then I'm opening myself up to potentially other people using my proxy if I happen to connect to a physical network that falls into the same range.

I'd like to see a configuration option added that allows me to specify the names of the WSL2 distros I want included as part of hostonly and the command to execute in that distro to return it's IP address on stdout.

Then, when determining host IPs we could run wsl -l --running on the windows side, read it's stdout and see if the distro I asked for is running.

We would need to implement a refresh of host IPs every x seconds, similar to how proxyreload works.

For example, a config that might look something like:

hostonly = 0
hostonlywsl2distros = [ { "distro": "Ubuntu", "command": "/home/david/get-ip.sh" } ]

This would mean at startup (and then every x seconds on a timer afterwards) we would:

We can execute commands in a running distro with wsl on the windows side:

wsl -d Ubuntu /home/david/get-ip.sh

Some examples of outputs:

No distros running

PS C:\Users\david> wsl -l --running
There are no running distributions.

Multiple distros running

PS C:\Users\david> wsl -l --running
Windows Subsystem for Linux Distributions:
Ubuntu (Default)
kali-linux

Getting the IP address by the command given

PS C:\Users\david> wsl -d Ubuntu /home/david/get-ip.sh
172.17.245.154
genotrance commented 1 year ago

I'm open to PRs that can do this cleanly, agree randomizing the WSL2 IP will be a pain to deal with. That being said, I'm not a WSL2 user so hard to implement at this time.

DBS-ST-VIT commented 1 month ago

In WSL2 under Windows 11, i got it working by setting the networkingMode to mirrored. I ran px with --hostonly and connected in the WSL to http://localhost:3128 and it worked without any problems.

Just make sure to restart WSL (wsl --shutdown and wsl) after changing the networkingMode in the .wslconfig.

Roemer commented 1 month ago

Mirrored mode does not work really well with VPN adapters currently. What you can try is to fix the ip address range of the hyper-v adapter for WSL by adjusting some registry keys:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss]
"NatGatewayIpAddress"="10.20.30.1"
"NatNetwork"="10.20.30.0/24"

With this, any WSL will get an ip from the range 10.20.30.0/24. You can of course adjust this to your liking. After this, configuring px with:

allow = 10.20.30.*
gateway = 1
hostonly = 1

seems to allow access from a local WSL.

genotrance commented 1 month ago

I've been doing basically the opposite - I run Px in a docker image on WSL2 and have my Windows, WSL2 and Docker apps connect to it. My WSL2 gets an internal IP (172.x) IP in a different range from Docker. In my case, I am not admin on Windows and the firewall is configured to block all inbound connections so Px is inaccessible to WSL2 and Docker. This might be affecting others as well.

I can set network_mode: host or expose port 3128 in Docker. For Px, I simply set PX_GATEWAY=1. I can access Px using localhost:3128 on Windows or WSL2. On Docker, I can specify the container name or use the WSL2 IP.

This setup is more secure since there's no way to access WSL2 from outside the physical machine. If WSL2 is configured with an external IP (assuming that's possible), Px might need to be configured more carefully.

Roemer commented 1 month ago

The problem there is, that there is no SSPI in WSL2, so you need another way to securely store the username/password to access the proxy (keyring?) to not have the Windows domain password somewhere in plain text. In Windows, it can just use the Windows domain credentials which is fairly nice. Small edit: What we use from Docker in WSL2 to access WSL itself is to start all containers with --add-host=host.docker.internal:host-gateway and then you can use http://host.docker.internal:3128 from the containers to get to the port 3128 in WSL2.

genotrance commented 1 month ago

Agree - forgot the primary reason Px came to be! I use env vars to configure Px (username, server, etc) and keyring for saving the password. I also mount -v ./keyrings:/root/.local/share/keyrings to store the password outside the container.