🥚➡️🍏🍎
Usque is an open-source reimplementation of the Cloudflare WARP client's MASQUE mode. It leverages the Connect-IP (RFC 9484) protocol and comes with many operation modes including a native tunnel, SOCKS5 and HTTP proxies, and faster TCP-only L4 proxy variants.
You can download the latest release from the releases page. For now, Android (arm64), Linux (armv5, armv6, armv7, arm64, amd64), Windows (arm64, amd64, 386) and Darwin (arm64, amd64) binaries are provided. However only the Linux amd64 binary was tested. If you have a different platform, you can build from source.
Extract the archive and you will find a binary named usque in the root directory. You can move this binary to a directory in your PATH to make it accessible from anywhere.
Since the tool is written in Go, it should be rather trivial.
CGO_ENABLED=0 go build -ldflags="-s -w" .
And that will produce an usque binary in the current directory.
If you would rather cross compile, set the GOOS and GOARCH environment variables accordingly. For example, to build for Windows on a Linux system:
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" .
You can deploy the tool using Docker. Dockerfile is provided in the repository. To build the image, run:
docker build -t usque:latest .
Example usage (spawns a SOCKS proxy and exposes it on port 1080):
docker run -it --rm -p 1080:1080 usque:latest socks
$ ./usque --help
An unofficial Cloudflare Warp CLI that uses the MASQUE protocol and exposes the tunnel as various different services.
Usage:
usque [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
enroll Enrolls a MASQUE private key and switches mode
help Help about any command
http-proxy Expose Warp as an HTTP proxy with CONNECT support
l4-http-proxy Expose Warp as an L4 TCP-only HTTP proxy with CONNECT support
l4-socks Expose Warp as an L4 TCP-only SOCKS5 proxy
nativetun Expose Warp as a native TUN device
portfw Forward ports through a MASQUE tunnel
register Register a new client and enroll a device key
socks Expose Warp as a SOCKS5 proxy
version Print the version number of usque
Flags:
-c, --config string config file (default is config.json) (default "config.json")
-h, --help help for usque
Use "usque [command] --help" for more information about a command.
Before doing anything, you need to register.
There is a handy (though not too feature-rich) register subcommand that creates a fresh Warp account ready to use. It also takes care of device registration and MASQUE device enrollment. Call this once and it will create a working configuration for future use in modules.
A simple example would be:
$ ./usque register
[!TIP] If you want to specify a name for the device, you may do so by specifying
-n <device-name>.[!TIP] If you want to register with ZeroTrust, you need to obtain the team token and do so by specifying
--jwt <team-token>. 1. Visithttps://<team-domain>/warpand complete the authentication process. 2. Obtain the team token from the success page's source code, or execute the following command in the browser console:console.log(document.querySelector("meta[http-equiv='refresh']").content.split("=")[2]).
If you didn't get rate-limited or any other error, you should see a Successful registration message and a working config. In case of certain issues such as rate limiting, you may need to wait a bit and try again.
While the registration command also handles device enrollment, in some cases, you may want to re-enroll the old key found in the config. This is useful when migrating from one device to another while the server still has the old client key enrolled. Or if your account had WireGuard enabled and you want to switch to MASQUE.
[!NOTE] This command refreshes your config with data downloaded from Cloudflare servers, so make sure you have backups.
[!TIP] When using ZeroTrust this command can update the config with the newly assigned IPv4 and IPv6 addresses. This is useful, because IPv6 doesn't seem to work there if the IPv6 in config isn't up to date. Personal WARP doesn't seem to be affected by this.
$ ./usque enroll
The native tunnel is a good choice when you want a real network interface. It is also one of the faster modes of operation.
It requires the TUN device to be available on the system. This means your kernel must support loading the tun.ko module. iproute2 is also a requirement. While it is still userspace, traffic is directly injected into the kernel's network stack, therefore you will see a real network interface and you will be able to tunnel any IP (Layer 3) traffic that WARP supports. Since it creates a real network interface and also attempts to set IP addresses, it will most likely require root privileges.
It requires the wintun.dll file to be present in the same directory as the usque.exe binary. Then it will take care of bringing up the interface and setting the IP addresses. Normally this also requires administrative privileges.
To bring up a native tunnel, execute:
$ sudo ./usque nativetun
Unless otherwise specified, you should see a tun0 (or tun1, tun2, etc.) interface appear on Linux. On Windows, the interface is typically named usque. If you didn't disable IPv4 and IPv6 inside the tunnel using cli flags (on Linux), you should also see the IPv4 and IPv6 address pre-assigned to this interface. This should be enough for applications that can route traffic through a specific network interface to function. For example ping:
$ ping -I tun0 1.1
Or curl:
$ curl --interface tun0 https://cloudflare.com/cdn-cgi/trace
Should just work. However the tool doesn't set any routes. If you need that, you have to do that manually. For example, to route all traffic to the tunnel, you need to make sure that the address used for tunnel communication is routed to your regular network interface. For that, open the config.json and check the endpoint address. If you plan to connect to the Cloudflare endpoint using IPv4, you will most likely see this:
"endpoint_v4": "162.159.198.1"
Remember that for the next steps.
Assuming your regular network interface is eth0 and your gateway address is 192.168.1.1, you can add a route like this:
$ sudo ip route add 162.159.198.1/32 via 192.168.1.1 dev eth0
After that, you can add a default route to the tun0 interface for both IPv4 and IPv6:
$ sudo ip route add default dev tun0 && sudo ip -6 route add default dev tun0
First, determine the interface index for your regular network adapter by running:
route print
Look under the Interface List for the correct index number.
Before adding default routes, determine the gateway for your tunnel interface by running:
ipconfig
Look for the adapter named usque (or whatever name you have for your tunnel interface) and note its gateway address.
Assuming:
162.159.198.1192.168.1.112usque (replace with the actual name or index of your tunnel interface)Run the following commands in an elevated Command Prompt (Run as Administrator):
route add 162.159.198.1 mask 255.255.255.255 192.168.1.1 metric 1 if 12
Then add default routes to route all traffic through the tunnel:
route add 0.0.0.0 mask 0.0.0.0 [TUNNEL_GATEWAY] metric 1 if [TUN_INTERFACE_INDEX]
route add ::/0 [TUNNEL_GATEWAY] metric 1 if [TUN_INTERFACE_INDEX]
[!NOTE] Replace
[TUNNEL_GATEWAY]and[TUN_INTERFACE_INDEX]with the actual values for your tunnel adapter. You can get these by checkingipconfigandroute print.[!CAUTION] Always be careful with default routes, especially if you are running this on a headless machine. It is very easy to close yourself out of your current session. I suggest network namespaces on Linux as a safer playground for experiments or a spare VM with physical access or serial console. On Windows, you can set specific routes first such as
8.8.8.8/32to ensure the tunnel works before adding a default route.
[!TIP] If you are OK with using QUIC (UDP) to connect to WARP and don't need UDP support for your SOCKS proxy, L4 mode is more efficient.
If you just want to expose the tunnel as a quickly deployable proxy and your client supports SOCKS5, this mode is for you. It supports both IPv4 and IPv6. TCP and UDP even! It is also cross-platform and doesn't require any special kernel modules or root privileges. However it emulates an entire user-space network stack, so it can be resource hungry.
To start a SOCKS5 proxy, you can run:
$ ./usque socks
By default this will launch a SOCKS5 proxy on 0.0.0.0:1080 with no authentication. You can choose to bind to a specific address and port by specifying -b and -p respectively. You can also enable authentication by specifying -u and -w for username and password. For example:
$ ./usque socks -b 127.0.0.1 -p 8080 -u myuser -w mypass
Will start a SOCKS5 proxy accessible only on 127.0.0.1:8080 with username myuser and password mypass.
Test the proxy with curl:
curl -x socks5://myuser:mypass@localhost:8080 https://cloudflare.com/cdn-cgi/trace
[!NOTE] Since the proxy emulates its own networking stack, it's generally safe to say that users won't be able to access internal IPs and services the host has access to using the proxy. However the internal WARP network is available for them unfiltered. If you have ZeroTrust and Gateway on, users of your proxy may be able to reach each other as no manual filtering is applied. Inside the tunnel they will be able to connect to any TCP or UDP service.
[!CAUTION] Local SOCKS5 traffic is not encrypted since SOCKS5 does not support encryption. You probably shouldn't transport statewide secrets from one device to another on a public WiFi that has
usquerunning.[!NOTE] For now only one
user:passis supported.
[!TIP] If you are OK with using QUIC (UDP) to connect to WARP, L4 mode is more efficient.
Another easy to "get up and running" mode of operation is the HTTP proxy mode. Almost all clients support HTTP proxies. Regular HTTP unencrypted traffic sent to this proxy will simply be forwarded to the WARP network. For HTTPS and any other TCP traffic, the proxy exposes a HTTP CONNECT method. This mode is cross-platform and doesn't require any special kernel modules or root privileges. However it emulates an entire user-space network stack, so it can be resource hungry.
To start a HTTP proxy, you can run:
`shell
$ ./usque http-proxy
$ claude mcp add usque \
-- python -m otcore.mcp_server <graph>