en | zh_CN
Warning
This English README is translated from the Chinese version using AI and may contain errors.
cgtproxy
is a transparent proxy rule manager written in Go, inspired by
the cgproxy project.
This project automatically updates nft rules based on configuration files to redirect network traffic from each cgroup to specific targets, enabling dynamic transparent proxy rules at the application level.
Currently supported targets include:
DIRECT
(direct connection)DROP
(drop packets)TPROXY
-
Install
cgtproxy
-
Enable and start the systemd service:
systemctl daemon-reload systemctl enable --now cgtproxy.service
Check the generated nft rules with the default configuration:
sudo nft list ruleset
-
Create your own configuration:
-
Write configuration according to the configuration guide
-
Place the configuration file at
/etc/cgtproxy/config.yaml
-
Restart the service:
systemctl restart cgtproxy.service
-
You can create a bash function to easily manage processes:
function cgtproxy-exec() {
local slice="cgtproxy-$1.slice"
shift 1
systemd-run --user --slice "$slice" -P "$@"
}
When you use this function like:
# Run without proxy
cgtproxy-exec direct /some/command
# Run with network disabled
cgtproxy-exec drop /some/command
# Run with proxy
cgtproxy-exec proxy /some/command
The function uses systemd-run
to run commands in the cgtproxy-direct
,
cgtproxy-drop
, and cgtproxy-proxy
slices.
In the example configuration, we:
- Leave traffic from cgroup
cgtproxy-direct.slice
unmodified - Drop traffic from cgroup
cgtproxy-drop.slice
- Transparently proxy traffic from cgroup
cgtproxy-proxy.slice
Netfilter can filter network traffic by cgroup and redirect traffic to TPROXY servers.
The systemd desktop environment documentation suggests that desktop environments and other launchers should start applications in systemd-managed units:
...
To ensure cross-desktop compatibility and encourage sharing of good practices, desktop environments should adhere to the following conventions:
- Application unit names should be in the form
app[-<launcher>]-<ApplicationID>[@<random>].service
orapp[-<launcher>]-<ApplicationID>-<random>.scope
. For example:
[email protected]
[email protected]
[email protected]
app-org.kde.amarok.service
app-org.gnome.Evince-12345.scope
...
While this documentation doesn't directly specify what "Application ID" should be, currently all Linux desktop environments use "desktop file ID" when launching applications.
For example, Telegram from Flatpak launched by a desktop environment will run in a cgroup similar to:
/user.slice/user-1000.slice/[email protected]/app.slice/[email protected]
This means each application instance's cgroup path follows a pattern that can be matched with regular expressions.
Based on this, cgtproxy
monitors cgroupfs changes through inotify,
and uses regex-based configuration files to update nft rules according to
configuration when new cgroup hierarchies are created.
Common methods for application-level proxy configuration on Linux have limitations:
-
Environment variables:
- No simple way to configure at the application level
- Some applications ignore environment variables
-
Filtering traffic by binary path (like Clash):
Clash scans procfs when applications create new sockets to determine which binary actually initiated the connection, then decides how to route it.
This approach has the following issues:
- Performance issues when there are many processes
- Programs written with scripts (like applications written with pyqt) cannot be correctly identified
- Cannot correctly identify when applications connect to the network by running command-line tools
-
Using cgproxy:
This approach has serious security issues:
- cgproxy moves processes out of their original cgroups
- Unauthorized user-level processes can escape to system-level cgroups
Additionally, this approach breaks systemd's single-writer rule.
cgtproxy
does not have these problems.
-
cgproxy
uses iptables, whilecgtproxy
uses nftables.You can check the differences between iptables and nftables.
-
cgproxy
predefines several [cgroups] and creates routing rules for them, whilecgtproxy
doesn't create [cgroups] but dynamically updates routing rules when [cgroups] appear. -
cgproxy
uses eBPF to hook the execve system call, determining executable file paths when all applications execute and moving processes to predefined [cgroups], whilecgtproxy
keeps processes in their original [cgroups]. -
cgproxy
requiresCAP_SYS_ADMIN
,CAP_NETWORK_ADMIN
, andCAP_BPF
, whilecgtproxy
only requiresCAP_NETWORK_ADMIN
. For details, see the systemd service file.
Project documentation:
Netfilter documentation:
-
Optional cgroup monitoring implementation that listens to D-Bus instead of filesystemnotify makes filesystem monitoring more stable. For my personal use, there's no need to implement another monitoring mechanism.
-
DNS hijacking for fake-ip:
-
IPv4
-
IPv6I don't have any IPv6-only devices, so I don't need and cannot validate this feature.
-
-
Built-in TPROXY serverClashClash.MetaMetaCubeX/mihomo is good enough for me.
If you need any of the above features, pull requests are welcome.
Unless otherwise stated, the code in this project is open source under the GNU General Public License version 3 or any later version, while documentation, configuration files, and scripts used in the development and maintenance process are open source under the MIT License.
This project complies with the REUSE Specification.
You can use reuse-tool to generate an SPDX list for this project:
reuse spdx