Skip to content

black-desk/cgtproxy

Repository files navigation

cgtproxy

checks commit activity contributors release date commits since release codecov go report card

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

Usage

  1. Install cgtproxy

  2. 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
  3. 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

Tips

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

How It Works

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 or app[-<launcher>]-<ApplicationID>-<random>.scope. For example:

...

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.

Advantages

Common methods for application-level proxy configuration on Linux have limitations:

  1. Environment variables:

    • No simple way to configure at the application level
    • Some applications ignore environment variables
  2. 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
  3. 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.

Differences from cgproxy

  1. cgproxy uses iptables, while cgtproxy uses nftables.

    You can check the differences between iptables and nftables.

  2. cgproxy predefines several [cgroups] and creates routing rules for them, while cgtproxy doesn't create [cgroups] but dynamically updates routing rules when [cgroups] appear.

  3. cgproxy uses eBPF to hook the execve system call, determining executable file paths when all applications execute and moving processes to predefined [cgroups], while cgtproxy keeps processes in their original [cgroups].

  4. cgproxy requires CAP_SYS_ADMIN, CAP_NETWORK_ADMIN, and CAP_BPF, while cgtproxy only requires CAP_NETWORK_ADMIN. For details, see the systemd service file.

Documentation

Project documentation:

Netfilter documentation:

Development Status

  • Optional cgroup monitoring implementation that listens to D-Bus instead of filesystem

    notify makes filesystem monitoring more stable. For my personal use, there's no need to implement another monitoring mechanism.

  • DNS hijacking for fake-ip:

    • IPv4

    • IPv6

      I don't have any IPv6-only devices, so I don't need and cannot validate this feature.

  • Built-in TPROXY server

    Clash Clash.Meta MetaCubeX/mihomo is good enough for me.

If you need any of the above features, pull requests are welcome.

License

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

Star History Chart

About

A transparent proxy RULE manager written in go inspired by cgproxy.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •