Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Host name based access control on the server #387

Closed
chase-qi opened this issue Dec 17, 2024 · 5 comments
Closed

Host name based access control on the server #387

chase-qi opened this issue Dec 17, 2024 · 5 comments

Comments

@chase-qi
Copy link

chase-qi commented Dec 17, 2024

Thank you for working on the great project. It is handy and easy to use for me. I have got most of the setup working as I needed. Host name based access control is the last bit. Any comments would be greatly appreciated. Details added below.

Describe the goal

A clear and concise description of what you try to achieve.

I want to control access on the server side by domain/host name.

Describe if you are behind a proxy, if you use some kind relay, what protocol/app you want to forward

wstunnel server is behind nginx proxy. nginx config:

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name wstunnel.***.***;

    if ($allowed_country = no) {
        return 444;
    }

    ssl_certificate /var/lib/dehydrated/certs/wstunnel.***.***/fullchain.pem;
    ssl_certificate_key /var/lib/dehydrated/certs/wstunnel.***.***/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {

        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;

        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
    }
}

TCP and UDP taffic is forward from iptables to redsocks to wstunnel client socks5 proxy. redsocks config

base {
    log_debug = off;
    log_info = on;
    log = "file:/var/log/redsocks.log";
    daemon = on;
    redirector = iptables;
}

redsocks {
    local_ip = 198.18.0.1;
    local_port = 12345;
    ip = 127.0.0.1;
    port = 1082;
    type = socks5;
}

redudp {
    local_ip = 198.18.0.1;
    local_port = 10053;
    ip = 127.0.0.1;
    port = 1080;
    dest_ip = 8.8.8.8;
    dest_port = 53;
    udp_timeout = 10;
    udp_timeout_stream = 10;
}

Describe what does not work

A clear and concise description of why you can't reach your goal.

Host-based access only works for server side DNS resolution, but doesn't work for client side DNS resolution. IP-based access control works for client side DNS resolution, but a domain's IP may change which makes it hard to maintain. In this case, I wonder if it is possible at all to see host/domain name on the server side for host based access control.

For my setup, traffic is forwarded from iptables to readsocks, then to wstunnel. I cannot really control how the clients(curl/wget/etc) handles DNS resolution. In my case, Nginx can only see its own domain/host name, not the destination domain/host name. wstunnel server can only see the DNS server IP and destination IP. I think this is mainly because DNS resolution is done on the client side. When using curl -x socks5h ***, wstunnel can see destination host name.

Describe your wstunnel setup

Paste your logs of wstunnel, started with --log-lvl=DEBUG, and with the command line used

Server side logs when the client side not using server side DNS resolution.

Dec 17 03:36:38 wstunnel wstunnel[3855]: 2024-12-17T03:36:38.959849Z  INFO cnx{peer="127.0.0.1:36526"}: wstunnel::tunnel::server::server: Accepting connection
Dec 17 03:36:38 wstunnel wstunnel[3855]: 2024-12-17T03:36:38.960087Z  INFO cnx{peer="127.0.0.1:36526"}:tunnel{id="0193d2b0-6cee-7e21-806f-ab09a958c302" remote="34.117.59.81:80"}: wstunnel::tunnel::server::server: Tunnel accepted due to matched restriction: 01
Dec 17 03:36:38 wstunnel wstunnel[3855]: 2024-12-17T03:36:38.960104Z  INFO cnx{peer="127.0.0.1:36526"}:tunnel{id="0193d2b0-6cee-7e21-806f-ab09a958c302" remote="34.117.59.81:80"}: wstunnel::protocols::tcp::server: Opening TCP connection to 34.117.59.81:80
Dec 17 03:36:38 wstunnel wstunnel[3855]: 2024-12-17T03:36:38.962926Z  INFO cnx{peer="127.0.0.1:36526"}:tunnel{id="0193d2b0-6cee-7e21-806f-ab09a958c302" remote="34.117.59.81:80"}: wstunnel::tunnel::server::server: connected to Tcp { proxy_protocol: false } 34.117.59.81:80
Dec 17 03:36:39 wstunnel wstunnel[3855]: 2024-12-17T03:36:39.080195Z ERROR cnx{peer="127.0.0.1:36526"}:tunnel{id="0193d2b0-6cee-7e21-806f-ab09a958c302" remote="34.117.59.81:80"}: wstunnel::tunnel::transport::io: error while reading from tunnel rx websocket close
Dec 17 03:36:39 wstunnel wstunnel[3855]: 2024-12-17T03:36:39.080237Z  INFO cnx{peer="127.0.0.1:36526"}:tunnel{id="0193d2b0-6cee-7e21-806f-ab09a958c302" remote="34.117.59.81:80"}: wstunnel::tunnel::transport::io: Closing local <= remote tunnel
Dec 17 03:36:39 wstunnel wstunnel[3855]: 2024-12-17T03:36:39.080333Z  INFO cnx{peer="127.0.0.1:36526"}:tunnel{id="0193d2b0-6cee-7e21-806f-ab09a958c302" remote="34.117.59.81:80"}: wstunnel::tunnel::transport::io: Closing local => remote tunnel
  • client

/wstunnel client -L socks5://127.0.0.1:1080 -P ******** wss://wstunnel.***.***

  • server

/usr/local/bin/wstunnel server ws://127.0.0.1:8080 --restrict-config /etc/wstunnel/restrictions.yaml

$ cat /etc/wstunnel/restrictions.yaml
allow_list: &allow_list
- !Tunnel
  cidr:
  # dns.google.com
  - 8.8.8.8/32
  # ipinfo.io
  - 34.117.59.81/32
  host: ^.*$

restrictions:
- name: 01
  match:
  - !PathPrefix '^******$'
  allow: *allow_list

Desktop (please complete the following information):

  • OS: [e.g. iOS]

Linux

  • Version [e.g. 22]

Debian 12

@erebe
Copy link
Owner

erebe commented Dec 21, 2024

Hello,

I am not sure to understand your request.
When you are talking about host, you mean the hostname of wstunnel server ? i.e: if the server is reachable at wss://foobar.com, you mean foobar.com ?

or are you talking about the hostname in the requested tunnel. I.e: -L tcp://8080:foobar.com:80

Regarding DNS resolution, it is the server that does it if you specify a tunnel with a hostname. For example, for the socks5 tunnel, the client forward the host to server, and it is the server that does the DNS resolution.

@chase-qi
Copy link
Author

Hi @erebe Thank you for the reply, and sorry for the confusion.

I meant the hostname of the destination. For example, the ipinfo.io in the curl -x socks5h://127.0.0.1:1080 ipinfo.io. I have the below tunnel defined in my restrictions.yaml.

- !Tunnel
  # REGEX.
  host: "^(ipinfo.io)$"
  # Logical OR.
  cidr:
  # ipinfo.io
  - 34.117.59.81/32
  # dns.google.com
  - 8.8.8.8/32

When using socks5h, the DNS resolution is done on the server side, and it is done on the client side when using socks5. In the later case, can the wstunnel server see the destination hostname, the ipinfo.io? From the log, wstunnel server only print the IP address of the hostname, and from my test, it only match cidr for the access control. Once 34.117.59.81/32 is removed from the cidr list, curl -x socks5://127.0.0.1:1080 ipinfo.io fails with empty reply as it is rejected by the server, although ipinfo.io is defined in the host regex.

I know I can achive host base access control if I configure client like curl to always use socks5h. However, in my case, both TCP and UDP traffic is forwared from redsocks to the socks5. redsocks doesn't support socks5h. Per the comment here semigodking/redsocks#206 (comment), it cannot be supported in that layer.

In my setup, I configure redsocks to forward traffic on a private interface to the socks5 proxy. DHCP sever is running on the private interface. So it is like a gateway/router. My goal is to let client PCs connected to the private interface to access internet via the socks5 proxy transparently.

The client PCs cannot see the socks5 proxy that runs on the gateway/router. For a request like curl ipinfo.io on the client PC, I see the below logs on the wstunnel server, it can only see the IP of DNS server and destination server. And it uses the IP of destination server for the access control.

8.8.8:53"}: wstunnel::protocols::udp::server: Opening UDP connection to 8.8.8.8:53
Dec 22 08:09:26 x13 wstunnel[21964]: 2024-12-22T00:09:26.246827Z  INFO cnx{peer="127.0.0.1:47094"}:tunnel{id="0193ebb2-87de-7563-b891-f67f48d30e78" remote="8.8.8.8:53"}: wstunnel::tunnel::server::server: connected to Udp { timeout: Some(30s) } 8.8.8.8:53
...
...
Dec 22 08:18:21 x13 wstunnel[21964]: 2024-12-22T00:18:21.796715Z  INFO cnx{peer="127.0.0.1:46370"}: wstunnel::tunnel::server::server: Accepting connection
Dec 22 08:18:21 x13 wstunnel[21964]: 2024-12-22T00:18:21.796886Z  INFO cnx{peer="127.0.0.1:46370"}:tunnel{id="0193ebba-b3e2-7950-b137-7bb7c8d0cf45" remote="34.117.59.81:80"}: wstunnel::tunnel::server::server: Tunnel accepted due to matched restriction: rpi4b1
Dec 22 08:18:21 x13 wstunnel[21964]: 2024-12-22T00:18:21.796921Z  INFO cnx{peer="127.0.0.1:46370"}:tunnel{id="0193ebba-b3e2-7950-b137-7bb7c8d0cf45" remote="34.117.59.81:80"}: wstunnel::protocols::tcp::server: Opening TCP connection to 34.117.59.81:80
Dec 22 08:18:21 x13 wstunnel[21964]: 2024-12-22T00:18:21.797184Z  INFO cnx{peer="127.0.0.1:46370"}:tunnel{id="0193ebba-b3e2-7950-b137-7bb7c8d0cf45" remote="34.117.59.81:80"}: wstunnel::tunnel::server::server: connected to Tcp { proxy_protocol: false } 34.117.59.81:80

On the wstunnel server that run command like wstunnel server wss://[::]:443 --restrict-config restrictions.yaml, I want to control which domain names the clients can access. I wonder if it is possible to maintain a list of hosts or a host regex pattern instead of a list of IPs.

@totchi-lagawi
Copy link

You mean doing reverse IP lookup on the server side to check wether a specific IP belongs to one of the authorised domains?

@erebe
Copy link
Owner

erebe commented Dec 22, 2024

Hello @chase-qi,

If you are using in curl socks5 instead of socks5h, it is not possible to know the domain. Even wstunnel client does not know the targeted domain, as it is curl doing the DNS resolution and communicate to the client only the ip address.

In general, If you are using socks5, the protocol allows requesting to forward IP address or domain. There is no way for the socks5 server to tell the client to not request forwarding ip address but only domain. The client is free to chose what either suits it best.

@chase-qi
Copy link
Author

@totchi-lagawi I assumed that the wstunnel client may know domain name for every request that even using socks5 and the client can encapsulate the domain name somehow, then the serve side can extract the info and use domain name for access control. Per @erebe's comment, when DNS resolution is done separately, even the client doesn't know the domain name, then my assumption is wrong.

@erebe Thanks for you comments. At least I know domain name is not always visible on the server side now. I am closing the ticket.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants