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

Major update: port mapping, vless outbound, and more #190

Open
wants to merge 44 commits into
base: main
Choose a base branch
from

Conversation

rikkagcp1
Copy link

@rikkagcp1 rikkagcp1 commented Jul 4, 2023

Add a port map to allow the use of non-standard proxy ports:

{
  "80":8080,
  "443":8443
}

For example, the above setup will redirect requests originally targeting port 443 to 8443. Similar redirection works for port 80 as well (redirect to proxyIP:8080).

Note: the keys in a JSON must be strings. "443":8443 is valid but 443:8443 is not.

To use it, you need to set "PORTMAP" environmental to a JSON like the above example, it will only be valid if "PROXYIP" is set.

Add VLESS outbound

To use it, you need to set "VLESS" environmental to a standard Vless sharing link.
Cloudflare Worker runtime has imposed outbound port restrictions where a TLS (WebSocket secured) outbound request must be made on port 443, and a non-TLS (plain WebSocket) outbound request must be made on port 80. Due to these restrictions, chaining to a VLESS server not running on port 80 (ws) or 443 (wss) won't work.

See: https://community.cloudflare.com/t/port-forwarding-with-worker/528002

Support UDP outbound

  1. Direct outbound if run on NodeJS
  2. Forward UDP requests to a remote Vless server if run on CF Worker
  3. Otherwise reject the UDP outbound

Fallback mechanism

When handling outbound, the program goes through outbounds defined in globalConfig.outbounds sequencially. If one fails, the next outbound (if any) will be tried, until it reaches the end of the outbound chain.
globalConfig.outbounds is similar to the outbounds object in a standard ?ray config file, but with some limitations:

  1. protocol: forward: our addon, used to forward the outbound TCP traffic directly to a proxy server.
  2. socks and vless only support one user-pass per server.
  3. socks outbound does not support UDP.

If run on a CF Worker, the resultant outbound sequence will be Direct (via worker), Forward (via PROXYIP, PORTMAP applies), VLESS, SOCKS, see setConfigFromEnv(). If a certain environmental variable is not set, the corresponding outbound will be skipped. Note that Direct outbound will always exist and will be attempted first.

Abstract worker-vless.js, allow it to be used as a module elsewhere or deploy it locally, see "node/index.js".

It exposes a number of functions and interfaces to be used in an external launcher:

  1. platformAPI: defines how to create TCP/Websocket/UDP connection in each platform, required to set if not run on CF Workers.
  2. globalConfig: all configurations, such as UUID, outbound methods.
  3. setConfigFromEnv: a simplifer way of setting outbound, the caller should pass a JSON which may contain PROXYIP, PORTMAP, VLESS, and SOCKS string fields.
  4. vlessOverWSHandler(webSocket, earlyDataHeader): Process an accepted "webSocket" connection, should be called when a new Websocket connection is established. "webSocket" is a Nodejs WS-compatible object, it must be an accepted one before calling this function. "earlyDataHeader" is a base64 string for ws 0rtt, its value comes from an optional field "sec-websocket-protocol" in the request header.
  5. getVLESSConfig(hostName): Return a human-readable webpage, describing the client config. "getVLESSConfig" now uses the latest active UUID.
  6. redirectConsoleLog(logServer, instanceId): Call this function to mirror console.log and POST it to a HTTP(s) server, set LOGPOST environmental variable in CF Worker to use this function. logServer is the URL, instanceId can be an UUID or a random number.

Using the provided wrapper to run in NodeJS only requires the ws library (see "node/setup.sh"), no need to install wrangler or other dependencies.

@ihategfw
Copy link
Collaborator

ihategfw commented Jul 12, 2023

Your verison lost an important logic compared with original version.

In order to resolve the worker issue that socket is not allowed to connect to Cloudflare IPs, the original version make a judgement in L201. Only if the destination website is proxied by Cloudflare, the worker will try to redirect by proxyIP/socks5.

In your version, firstly, if I only set the global config as forward outbound protocol and ENV is empty, the code setConfigFromEnv(env); in fetch function will override the global config. I have to comment out the code to let global config affect.

Secondly, after the code was commented out and outbound protocol was set as forward, all tcp outbound will be redirect to address, which leads to the fact that only the Cloudflare websites can be opened and other websites cannot be connected. Because normally proxyIP only forwards data to IP like Cloudflare anycast IP. I am guessing that if the outbound protocol is socks or vless, all websites can be opened but all data will be transmitted by the other server set in the global config.

@rikkagcp1
Copy link
Author

In order to resolve the worker issue that socket is not allowed to connect to Cloudflare IPs, the original version make a judgement in L201. Only if the destination website is proxied by Cloudflare, the worker will try to redirect by proxyIP/socks5.

This feature was inherented. The rule of thumb here is that, it will only move on to the next outbound if the previous one fails.

the code setConfigFromEnv(env); in fetch function will override the global config.

You are right, that is the intended behavior. setConfigFromEnv(env); can be called from anywhere, and it will always set to the same configuration (put into a known state), regardless of the value of the current globalConfig. On workers, you are not supposed to set the globalConfig json directly by modifying the code, you should always use environmental variables.

Secondly, after the code was commented out and outbound protocol was set as forward, all tcp outbound will be redirect to address

If you are an advanced user, of course you can customize the code and comment out the call to setConfigFromEnv. However, it seems that you removed the "freedom" outbound and only leave the "forward" outbound there, which is still a valid config, but it will not follow your intention. In your case, you need to keep both freedom and forward in your outbound. Furthermore, the sequence matters.

@ihategfw
Copy link
Collaborator

On workers, you are not supposed to set the globalConfig json directly by modifying the code, you should always use environmental variables.

Yes, you are right.

Another issue is that the format of PORTMAP should be {"443":8443}, because the "key" of json must be string.

After doing this, everything works perfectly.

@smounives
Copy link

Hi, I set the value of VLEES in the Workers environment variable to vless://[email protected]:port?type=tcp&security=tls
But I still can't access any Cloudflare website, the vless server uses the latest version 1.8.4 of xray-core, and I can connect to this vless in other clients normally.

@smounives
Copy link

I have tried SOCKS5 and it works, but VLESS can't work properly.

@rikkagcp1
Copy link
Author

Hi, I set the value of VLEES in the Workers environment variable to vless://[email protected]:port?type=tcp&security=tls But I still can't access any Cloudflare website, the vless server uses the latest version 1.8.4 of xray-core, and I can connect to this vless in other clients normally.

I suspect your VLESS server is not running on port 443 or port 80.

Cloudflare Worker runtime has imposed outbound port restrictions where a TLS (WebSocket secured) outbound request must be made on port 443, and a non-TLS (plain WebSocket) outbound request must be made on port 80. Due to these restrictions, chaining to a VLESS server not running on port 80 (ws) or 443 (wss) won't work.

See: https://community.cloudflare.com/t/port-forwarding-with-worker/528002

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

Successfully merging this pull request may close these issues.

4 participants