commit 267aac32de1891a18dc6172654d7e92a9b3517fa Author: fancy Date: Wed Apr 22 03:04:15 2020 +0800 cgproxy is work now diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6282f46 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +build +.directory +.vscode +cgproxy2.sh diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..cb13add --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.10) + +project(cgproxy VERSION 1.0) +add_executable(cgattach cgattach.cpp) + +install(TARGETS cgattach DESTINATION /usr/bin + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE SETUID) +install(FILES cgproxy.sh DESTINATION /usr/bin RENAME cgproxy + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +#install(FILES cgproxy2.sh DESTINATION /usr/bin RENAME cgproxy2 +# PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +install(FILES cgproxy.service DESTINATION /usr/lib/systemd/system/) +install(FILES cgproxy.conf DESTINATION /etc/) +install(FILES cgroup-tproxy.sh DESTINATION /usr/share/cgproxy/scripts/) diff --git a/cgattach.cpp b/cgattach.cpp new file mode 100644 index 0000000..ff087b9 --- /dev/null +++ b/cgattach.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +void print_usage(){ + fprintf(stderr, "usage: cgattach \n"); +} + +bool exist(string path){ + struct stat st; + if (stat(path.c_str(),&st)!=-1){ + return S_ISDIR(st.st_mode); + } + return false; +} + +bool validate(string pid, string cgroup){ + bool pid_v=regex_match(pid,regex("^[0-9]+$")); + bool cg_v=regex_match(cgroup,regex("^\\/[a-zA-Z0-9\\-_./@]+$")); + if (pid_v && cg_v) return true; + // cout< +# +############################################################################# +DOC +} + +## any process in this cgroup will be proxied +proxy_cgroup="/user.slice/user-1000.slice/proxy.slice" + +## some variables +port=12345 +enable_tcp=true +enable_udp=true +enable_ipv4=true +enable_ipv6=true + +## do not modify this if you don't known what you are doing +mark=2333 +table=100 +v2ray_so_mark=255 + +## cgroup things +# cgroup_mount_point=$(findmnt -t cgroup,cgroup2 -n -J|jq '.filesystems[0].target') +# cgroup_type=$(findmnt -t cgroup,cgroup2 -n -J|jq '.filesystems[0].fstype') +cgroup_mount_point="/sys/fs/cgroup" +cgroup_type="cgroup2" +cgroup_procs_file="cgroup.procs" + +## parse parameter +for i in "$@" +do +case $i in + stop) + iptables -t mangle -F + iptables -t mangle -X TPROXY_PRE + iptables -t mangle -X TPROXY_OUT + ip6tables -t mangle -F + ip6tables -t mangle -X TPROXY_PRE + ip6tables -t mangle -X TPROXY_OUT + ip rule delete fwmark $mark lookup $table + ip route flush table $table + ip -6 rule delete fwmark $mark lookup $table + ip -6 route flush table $table + exit 0 + ;; + --config=*) + config=${i#*=} + source $config + shift + ;; + --help) + print_help + exit 0 + ;; +esac +done + +## TODO cgroup need to exists before using in iptables since 5.6.5, maybe it's bug +test -d $cgroup_mount_point$proxy_cgroup || mkdir $cgroup_mount_point$proxy_cgroup || exit -1; + +## use TPROXY +#ipv4# +ip rule add fwmark $mark table $table +ip route add local default dev lo table $table +iptables -t mangle -N TPROXY_PRE +iptables -t mangle -A TPROXY_PRE -p udp -m mark --mark $mark -j TPROXY --on-ip 127.0.0.1 --on-port $port --tproxy-mark $mark +iptables -t mangle -A TPROXY_PRE -p tcp -m mark --mark $mark -j TPROXY --on-ip 127.0.0.1 --on-port $port --tproxy-mark $mark +iptables -t mangle -A PREROUTING -j TPROXY_PRE + +iptables -t mangle -N TPROXY_OUT +iptables -t mangle -A TPROXY_OUT -p udp -o lo -j RETURN +iptables -t mangle -A TPROXY_OUT -p udp -m cgroup --path $proxy_cgroup -j MARK --set-mark $mark +iptables -t mangle -A TPROXY_OUT -p tcp -o lo -j RETURN +iptables -t mangle -A TPROXY_OUT -p tcp -m cgroup --path $proxy_cgroup -j MARK --set-mark $mark +iptables -t mangle -A OUTPUT -m mark ! --mark $v2ray_so_mark -j TPROXY_OUT + +#ipv6# +ip -6 rule add fwmark $mark table $table +ip -6 route add local default dev lo table $table +ip6tables -t mangle -N TPROXY_PRE +ip6tables -t mangle -A TPROXY_PRE -p udp -m mark --mark $mark -j TPROXY --on-ip ::1 --on-port $port --tproxy-mark $mark +ip6tables -t mangle -A TPROXY_PRE -p tcp -m mark --mark $mark -j TPROXY --on-ip ::1 --on-port $port --tproxy-mark $mark +ip6tables -t mangle -A PREROUTING -j TPROXY_PRE + +ip6tables -t mangle -N TPROXY_OUT +ip6tables -t mangle -A TPROXY_OUT -p udp -o lo -j RETURN +ip6tables -t mangle -A TPROXY_OUT -p udp -m cgroup --path $proxy_cgroup -j MARK --set-mark $mark +ip6tables -t mangle -A TPROXY_OUT -p tcp -o lo -j RETURN +ip6tables -t mangle -A TPROXY_OUT -p tcp -m cgroup --path $proxy_cgroup -j MARK --set-mark $mark +ip6tables -t mangle -A OUTPUT -m mark ! --mark $v2ray_so_mark -j TPROXY_OUT + +## allow to disable, order is important +$enable_udp || iptables -t mangle -I TPROXY_OUT -p udp -j RETURN +$enable_udp || ip6tables -t mangle -I TPROXY_OUT -p udp -j RETURN +$enable_tcp || iptables -t mangle -I TPROXY_OUT -p tcp -j RETURN +$enable_tcp || ip6tables -t mangle -I TPROXY_OUT -p tcp -j RETURN +$enable_ipv4 || iptables -t mangle -I TPROXY_OUT -j RETURN +$enable_ipv6 || ip6tables -t mangle -I TPROXY_OUT -j RETURN + + +## create proxy prefix command for easy use +# cat << 'DOC' > /usr/bin/cgproxy +# !/usr/bin/bash +# systemd-run -q --slice proxy.slice --scope --user $@ +# DOC +# chmod a+x /usr/bin/cgproxy + +## message for user +cat << DOC +proxied cgroup: $proxy_cgroup +DOC + +## tproxy need Root or cap_net_admin capability +# setcap cap_net_admin+ep /usr/lib/v2ray/v2ray + diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..6a0be45 --- /dev/null +++ b/readme.md @@ -0,0 +1,83 @@ +# Transparent Proxy with cgroup v2 + +## Introduction + +cgproxy will **transparent** proxy anything running in specific cgroup. It resembles with *proxychains* and *tsock*, but without their disadvantages. + +## Prerequest + +- cgroup2 + + For now, linux default using cgroup v1 for compatibility, this project need cgroup v2, you need disable cgroup v1 and enable cgroup v2 in your system. + +- TPROXY + + A process listening on port (e.g. 12345) to accept iptables TPROXY, for example v2ray's dokodemo-door in tproxy mode. + +## How to install + +```bash +mkdir build && cd build && cmake .. && make && make install +``` + +It is alreay in archlinux AUR. + +## How to use + +- First enable service + + ```bash + sudo systemctl enable --now cgproxy.service + sudo systemctl status cgproxy.service + ``` + +- Then prefix with cgproxy with you command, just like proxychains + + ``` + cgproxy + ``` + +- For example, test proxy + + ```bash + cgproxy curl -vIs https://www.google.com + ``` + +More config in `/etc/cgproxy.conf`: + +```bash +## any process in this cgroup will be proxied +## must start with slash '/' +proxy_cgroup="/proxy.slice" + +## listening port of another proxy process, for example v2ray +port=12345 + +## if you set to false, it's traffic won't go through proxy, but still can go direct to internet +enable_tcp=true +enable_udp=true +enable_ipv4=true +enable_ipv6=true + +## v2ray outbound mark +## only useful if v2ray process is also in proxy_cgroup, for example, you want to proxy whole userspace, +## and v2ray is also running in userspace +## otherwise ignore this +v2ray_so_mark=255 + +## do not modify this if you don't known what you are doing +mark=2333 +table=100 +``` + + + +## NOTES + +- `cgattach` attach pid to specific cgroup, and has *suid* bit set by default, be careful to use on multi-user server for securiry. To avoid this situation, you can remove the *suid* bit , then it will fallback to use *sudo*, with *visudo* you can restrict permission or set NOPASSWD for youself. +- TPROXY need root or cap_net_admin capability whatever process is listening on port, + v2ray as example: sudo setcap cap_net_admin+ep /usr/lib/v2ray/v2ray + +## TIPS + +- `systemd-cgls` to see the cgroup hierarchical tree. \ No newline at end of file