mirror of
https://github.com/springzfx/cgproxy.git
synced 2026-03-15 09:32:09 +08:00
cgproxy is work now
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
build
|
||||
.directory
|
||||
.vscode
|
||||
cgproxy2.sh
|
||||
14
CMakeLists.txt
Normal file
14
CMakeLists.txt
Normal file
@@ -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/)
|
||||
80
cgattach.cpp
Normal file
80
cgattach.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <regex>
|
||||
using namespace std;
|
||||
|
||||
void print_usage(){
|
||||
fprintf(stderr, "usage: cgattach <pid> <cgroup>\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<<pid_v<<" "<<cg_v<<endl;
|
||||
print_usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]){
|
||||
setuid(0);
|
||||
setgid(0);
|
||||
if (getuid()!=0||getgid()!=0){
|
||||
fprintf(stderr, "cgattach need setuid sticky bit\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc!=3){
|
||||
print_usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
string pid=string(argv[1]);
|
||||
string cgroup_target=string(argv[2]);
|
||||
validate(pid, cgroup_target);
|
||||
string cgroup_mount_point="/sys/fs/cgroup";
|
||||
string cgroup_target_path=cgroup_mount_point+cgroup_target;
|
||||
string cgroup_target_procs=cgroup_target_path+"/cgroup.procs"; // only support cgroup v2
|
||||
|
||||
// check if exist, we won't create it if not exist
|
||||
if (!exist(cgroup_target_path)){
|
||||
if (mkdir(cgroup_target_path.c_str(), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)==0){
|
||||
fprintf(stdout, "created cgroup %s success\n",cgroup_target.c_str());
|
||||
}else{
|
||||
fprintf(stderr, "created cgroup %s failed\n",cgroup_target.c_str());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// fprintf(stderr, "cgroup %s not exist\n",cgroup_target.c_str());
|
||||
// exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// put pid to target cgroup
|
||||
ofstream procs(cgroup_target_procs,ofstream::app);
|
||||
if (!procs.is_open()){
|
||||
fprintf(stderr, "open file %s failed\n",cgroup_target_procs.c_str());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
procs<<pid.c_str()<<endl;
|
||||
procs.close();
|
||||
|
||||
// maybe there some write error, for example process pid not exist
|
||||
if (!procs){
|
||||
fprintf(stderr, "write %s to %s failed, maybe process %s not exist\n",pid.c_str(),cgroup_target_procs.c_str(),pid.c_str());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
22
cgproxy.conf
Normal file
22
cgproxy.conf
Normal file
@@ -0,0 +1,22 @@
|
||||
## 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
|
||||
11
cgproxy.service
Normal file
11
cgproxy.service
Normal file
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=proxy cgroup
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=sh /usr/share/cgproxy/scripts/cgroup-tproxy.sh --config=/etc/cgproxy.conf
|
||||
ExecStop=sh /usr/share/cgproxy/scripts/cgroup-tproxy.sh stop
|
||||
RemainAfterExit=1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
12
cgproxy.sh
Normal file
12
cgproxy.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
config="/etc/cgproxy.conf"
|
||||
source $config
|
||||
|
||||
# test suid bit
|
||||
if [ -u "$(which cgattach)" ]; then
|
||||
cgattach $$ $proxy_cgroup
|
||||
else
|
||||
sudo cgattach $$ $proxy_cgroup
|
||||
fi
|
||||
$@
|
||||
141
cgroup-tproxy.sh
Normal file
141
cgroup-tproxy.sh
Normal file
@@ -0,0 +1,141 @@
|
||||
#!/bin/bash
|
||||
print_help(){
|
||||
cat << 'DOC'
|
||||
#############################################################################
|
||||
#
|
||||
# 1. For now, linux default using cgroup v1 for compatibility
|
||||
# this script need cgroup v2, you need enable cgroup v2 in your system.
|
||||
#
|
||||
# 2. Listening port is expected to accept iptables TPROXY, while REDIRECT
|
||||
# will not work in this script, because REDIRECT only support tcp/ipv4
|
||||
#
|
||||
# 3. 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
|
||||
#
|
||||
# 4. this script will proxy anything running in specific cgroup
|
||||
#
|
||||
# script usage:
|
||||
# cgroup-tproxy.sh [--help|--config|stop]
|
||||
# --config=FILE
|
||||
# load config from file
|
||||
# --help
|
||||
# show help info
|
||||
# stop
|
||||
# clean then stop
|
||||
#
|
||||
# proxy usage:
|
||||
# cgproxy <program>
|
||||
#
|
||||
#############################################################################
|
||||
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
|
||||
|
||||
83
readme.md
Normal file
83
readme.md
Normal file
@@ -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 <CMD>
|
||||
```
|
||||
|
||||
- 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.
|
||||
Reference in New Issue
Block a user