36 Commits
v0.03 ... v0.0x

Author SHA1 Message Date
fancy
da0c925efc add licence in aur 2020-05-16 17:26:38 +08:00
fancy
b2b3168463 update readme 2020-05-14 16:16:45 +08:00
fancy
2838ffbb70 bump version 2020-05-14 14:28:08 +08:00
fancy
749fe38ca8 add local aur build 2020-05-14 14:21:40 +08:00
fancy
c0668fd8d2 use macro 2020-05-14 13:57:39 +08:00
fancy
06ae0b9fc5 update readme 2020-05-14 12:07:12 +08:00
fancy
4e04dcf84a update readme 2020-05-14 04:53:23 +08:00
fancy
c0e9ea24c1 allow array input for cgroup_proxy and cgroup_noproxy 2020-05-14 04:47:29 +08:00
fancy
f8e0abbb55 check root, and check iptables before clean 2020-05-13 23:42:05 +08:00
fancy
6c24c68831 only masquerade ipv6 private address 2020-05-08 11:47:51 +08:00
fancy
d3b2dc0465 small fix 2020-05-07 00:22:08 +08:00
fancy
4be7be2083 example: rename to keep order 2020-05-06 02:42:44 +08:00
fancy
25f94968ae install readme.md to doc 2020-05-05 20:14:26 +08:00
fancy
3b4b67df33 small change 2020-05-05 19:30:35 +08:00
fancy
31ae519193 v2ray.service without root 2020-05-05 00:32:09 +08:00
fancy
7f0ebe9d35 remove mark_noproxy, and other small change 2020-05-04 20:41:50 +08:00
fancy
236c08172b example: update readme 2020-05-03 18:29:08 +08:00
fancy
c07ae13030 example: add aliyun doh 2020-05-03 17:00:34 +08:00
fancy
d5ea832b4f change timeout, and dns no need to proxy 2020-05-03 15:05:56 +08:00
fancy
aa5ca6f204 update example, limit to localhost 2020-05-02 08:01:19 +08:00
fancy
a80187f947 optimize function get_cgroup2_mount_point 2020-05-02 04:15:54 +08:00
fancy
dca895c7cc readme update 2020-05-02 03:45:36 +08:00
fancy
08097a54d7 readme update 2020-05-02 03:42:22 +08:00
fancy
bce568d802 readme update 2020-05-02 03:40:32 +08:00
fancy
98c07a31af readme update 2020-05-02 03:37:58 +08:00
fancy
916c11d280 update config example 2020-05-01 17:51:53 +08:00
fancy
72579bc84a typo fix 2020-05-01 13:55:06 +08:00
fancy
5c16fdfb9f add v2ray config example 2020-05-01 11:55:57 +08:00
fancy
f55b09ec12 imporved gateway nat, and bypass broadcast things 2020-05-01 11:26:46 +08:00
fancy
6ae12bf5c4 optimize 2020-04-30 16:32:07 +08:00
fancy
31627dd956 update readme 2020-04-30 02:05:03 +08:00
fancy
9f8d540c78 important optimize 2020-04-30 02:02:11 +08:00
fancy
b8204126c5 maintain update 2020-04-28 20:25:44 +08:00
fancy
daa68f20ea package deb rpm 2020-04-28 19:58:40 +08:00
fancy
836a34cdc8 also handle gateway dns 2020-04-28 13:49:26 +08:00
fancy
3c21882b88 more compact 2020-04-28 12:17:25 +08:00
30 changed files with 589 additions and 129 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
build
.directory
.vscode
v2ray_config/proxy
v2ray_config/06_outbounds_proxy.json

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.10)
project(cgproxy VERSION 1.0)
project(cgproxy VERSION 3.8)
add_executable(cgattach cgattach.cpp)
install(TARGETS cgattach DESTINATION /usr/bin
@@ -21,3 +21,34 @@ install(FILES cgproxy.conf
DESTINATION /etc/)
install(FILES cgroup-tproxy.sh
DESTINATION /usr/share/cgproxy/scripts/)
install(FILES readme.md
DESTINATION /share/doc/cgproxy/)
## package for deb and rpm
set(CPACK_GENERATOR "DEB;RPM")
set(CPACK_PACKAGE_NAME "cgproxy")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "cgproxy will transparent proxy anything running in specific cgroup.It aslo supports global transparent proxy and gateway proxy")
## deb pack
set(CPACK_DEBIAN_PACKAGE_NAME "cgproxy")
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "x86_64")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "systemd")
set(CPACK_DEBIAN_PACKAGE_SECTION "network")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "Optional")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/springzfx/cgproxy")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "springzfx@gmail.com")
set(CONTROL_DIR ${CMAKE_SOURCE_DIR}/control)
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CONTROL_DIR}/postinst;${CONTROL_DIR}/prerm")
## rpm pack
set(CPACK_RPM_PACKAGE_ARCHITECTURE, "x86_64")
set(CPACK_RPM_PACKAGE_REQUIRES "systemd")
set(CPACK_RPM_PACKAGE_GROUP "network")
set(CPACK_RPM_PACKAGE_URL "https://github.com/springzfx/cgproxy")
set(CONTROL_DIR ${CMAKE_SOURCE_DIR}/control)
set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CONTROL_DIR}/postinst")
set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE "${CONTROL_DIR}/prerm")
include(CPack)

View File

@@ -0,0 +1,40 @@
# Maintainer: Fancy Zhang <springzfx@gmail.com>
pkgname=cgproxy-git
pkgver=v3.8.r1.gc0668fd
pkgrel=1
pkgdesc="A transparent proxy program with cgroup2, like proxychains"
arch=('x86_64')
url="https://github.com/springzfx/cgproxy"
license=('GPL')
groups=('')
makedepends=('cmake')
depends=('systemd')
provides=('cgproxy')
conflicts=('cgproxy')
curr_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source=("${pkgname}::git+file://${curr_dir}/../.git")
# source=("${pkgname}::git+file:///home/fancy/workspace/cgproxy/.git")
md5sums=('SKIP')
pkgver() {
cd "$pkgname"
( set -o pipefail
git describe --long --tags 2>/dev/null | sed 's/\([^-]*-g\)/r\1/;s/-/./g' ||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
)
}
backup=('etc/cgproxy.conf')
install="cgproxy.install"
build(){
cd "$pkgname"
mkdir -p build && cd build && cmake .. && make
}
package_cgproxy-git(){
cd "$pkgname"/build
make DESTDIR=$pkgdir install
}

View File

@@ -0,0 +1,8 @@
#!/bin/sh
post_install(){
cat <<'DOC'
to start service:
systemctl enable --now cgproxy.service
DOC
}

View File

@@ -10,6 +10,10 @@
#include <unistd.h>
using namespace std;
#define error(...) {fprintf(stderr, __VA_ARGS__);fprintf(stderr, "\n");}
#define debug(...) {fprintf(stdout, __VA_ARGS__);fprintf(stdout, "\n");}
void print_usage() { fprintf(stdout, "usage: cgattach <pid> <cgroup>\n"); }
bool exist(string path) {
@@ -26,29 +30,32 @@ bool validate(string pid, string cgroup) {
if (pid_v && cg_v)
return true;
fprintf(stderr, "paramater validate error\n");
error("paramater validate error");
print_usage();
exit(EXIT_FAILURE);
}
string get_cgroup2_mount_point(){
char cgroup2_mount_point[100];
FILE* fp = popen("findmnt -t cgroup2 -n |cut -d' ' -f 1", "r");
fscanf(fp,"%s",&cgroup2_mount_point);
char cgroup2_mount_point[100]="";
FILE* fp = popen("findmnt -t cgroup2 -n -o TARGET", "r");
int count=fscanf(fp,"%s",&cgroup2_mount_point);
fclose(fp);
if (count=0){
error("cgroup2 not supported");
exit(EXIT_FAILURE);
}
return cgroup2_mount_point;
}
int main(int argc, char *argv[]) {
setuid(0);
setgid(0);
if (getuid() != 0 || getgid() != 0) {
fprintf(stderr, "cgattach need suid sticky bit or run with root\n");
int flag=setuid(0);
if (flag!=0) {
perror("cgattach setuid");
exit(EXIT_FAILURE);
}
if (argc != 3) {
fprintf(stderr, "only need 2 paramaters\n");
error("only need 2 paramaters");
print_usage();
exit(EXIT_FAILURE);
}
@@ -65,20 +72,19 @@ int main(int argc, char *argv[]) {
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());
debug("created cgroup %s success", cgroup_target.c_str());
} else {
fprintf(stderr, "created cgroup %s failed, errno %d\n",
cgroup_target.c_str(), errno);
error("created cgroup %s failed, errno %d", cgroup_target.c_str(), errno);
exit(EXIT_FAILURE);
}
// fprintf(stderr, "cgroup %s not exist\n",cgroup_target.c_str());
// error("cgroup %s not exist",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());
error("open file %s failed", cgroup_target_procs.c_str());
exit(EXIT_FAILURE);
}
procs << pid.c_str() << endl;
@@ -86,7 +92,7 @@ int main(int argc, char *argv[]) {
// maybe there some write error, for example process pid may not exist
if (!procs) {
fprintf(stderr, "write %s to %s failed, maybe process %s not exist\n",
error("write %s to %s failed, maybe process %s not exist",
pid.c_str(), cgroup_target_procs.c_str(), pid.c_str());
exit(EXIT_FAILURE);
}

View File

@@ -1,33 +1,48 @@
# see how to configure
# https://github.com/springzfx/cgproxy
########################################################################
## cgroup transparent proxy
## see how to configure, https://github.com/springzfx/cgproxy
###################################################################################
## any process in cgroup_proxy will be proxied, and cgroup_noproxy the opposite
## cgroup must start with slash '/'
# cgroup_proxy="/"
cgroup_proxy="/proxy.slice"
## note, cgroup must start with slash '/'
## the value can be string or bash array
## for array, only the first element will be created if not exist
## and the rest elements will not, so won't be applied if not exist
### global proxy with v2ray service
# cgroup_proxy="/"
# cgroup_noproxy=("/noproxy.slice" "/system.slice/v2ray.service")
### global proxy with manual `cgnoporxy qv2ray`
# cgroup_proxy="/"
# cgroup_noproxy="/noproxy.slice"
### default
cgroup_proxy="/proxy.slice"
cgroup_noproxy="/noproxy.slice"
########################################################################
###################################################################################
## allow as gateway for local network
enable_gateway=false
########################################################################
###################################################################################
## 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
###################################################################################
## if you set to false, it's traffic won't go through proxy,
## but still can go direct to internet
enable_dns=true
enable_tcp=true
enable_udp=true
enable_ipv4=true
enable_ipv6=true
enable_dns=true
########################################################################
###################################################################################
## do not modify this if you don't known what you are doing
table=100
mark_proxy=0x01
mark_noproxy=0xff
mark_newin=0x02
fwmark=0x01
mark_newin=0x02

View File

@@ -30,6 +30,13 @@ cat << 'DOC'
DOC
}
check_root(){
uid=$(id -u)
[ ! $uid -eq 0 ] && { >&2 echo "permission denied, need root";exit 0; }
}
check_root
## any process in this cgroup will be proxied
cgroup_proxy="/proxy.slice"
cgroup_noproxy="/noproxy.slice"
@@ -39,22 +46,21 @@ enable_gateway=false
## some variables
port=12345
## some options
enable_dns=true
enable_tcp=true
enable_udp=true
enable_ipv4=true
enable_ipv6=true
enable_dns=true
## do not modify this if you don't known what you are doing
table=100
mark_proxy=0x01
mark_noproxy=0xff
fwmark=0x01
make_newin=0x02
## 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=$(findmnt -t cgroup2 -n |cut -d' ' -f 1)
cgroup_mount_point=$(findmnt -t cgroup2 -n -o TARGET)
cgroup_type="cgroup2"
cgroup_procs_file="cgroup.procs"
@@ -63,31 +69,35 @@ for i in "$@"
do
case $i in
stop)
echo "stopping tproxy iptables"
iptables -t mangle -D PREROUTING -j TPROXY_PRE
iptables -t mangle -D OUTPUT -j TPROXY_OUT
iptables -t mangle -F TPROXY_PRE
iptables -t mangle -F TPROXY_OUT
iptables -t mangle -F TPROXY_ENT
iptables -t mangle -X TPROXY_PRE
iptables -t mangle -X TPROXY_OUT
iptables -t mangle -X TPROXY_ENT
ip6tables -t mangle -D PREROUTING -j TPROXY_PRE
ip6tables -t mangle -D OUTPUT -j TPROXY_OUT
ip6tables -t mangle -F TPROXY_PRE
ip6tables -t mangle -F TPROXY_OUT
ip6tables -t mangle -F TPROXY_ENT
ip6tables -t mangle -X TPROXY_PRE
ip6tables -t mangle -X TPROXY_OUT
ip rule delete fwmark $mark_proxy lookup $table
ip6tables -t mangle -X TPROXY_ENT
ip rule delete fwmark $fwmark lookup $table
ip route flush table $table
ip -6 rule delete fwmark $mark_proxy lookup $table
ip -6 rule delete fwmark $fwmark lookup $table
ip -6 route flush table $table
## may not exist, just ignore, and tracking their existence is reliable
iptables -t nat -D POSTROUTING -m addrtype ! --src-type LOCAL -j MASQUERADE &> /dev/null
ip6tables -t nat -D POSTROUTING -m addrtype ! --src-type LOCAL -j MASQUERADE &> /dev/null
## may not exist, just ignore, and tracking their existence is not reliable
iptables -t nat -D POSTROUTING -m owner ! --socket-exists -j MASQUERADE &> /dev/null
ip6tables -t nat -D POSTROUTING -m owner ! --socket-exists -s fc00::/7 -j MASQUERADE &> /dev/null
exit 0
;;
--config=*)
config=${i#*=}
source $config
shift
;;
--help)
print_help
@@ -97,92 +107,113 @@ esac
done
## TODO cgroup need to exists before using in iptables since 5.6.5, maybe it's bug
## only create the first one in arrary
test -d $cgroup_mount_point$cgroup_proxy || mkdir $cgroup_mount_point$cgroup_proxy || exit -1;
test -d $cgroup_mount_point$cgroup_noproxy || mkdir $cgroup_mount_point$cgroup_noproxy || exit -1;
## use TPROXY
#ipv4#
ip rule add fwmark $mark_proxy table $table
ip rule add fwmark $fwmark table $table
ip route add local default dev lo table $table
iptables -t mangle -N TPROXY_ENT
iptables -t mangle -A TPROXY_ENT -p tcp -j TPROXY --on-ip localhost --on-port $port --tproxy-mark $fwmark
iptables -t mangle -A TPROXY_ENT -p udp -j TPROXY --on-ip localhost --on-port $port --tproxy-mark $fwmark
iptables -t mangle -N TPROXY_PRE
iptables -t mangle -A TPROXY_PRE -m socket --transparent -j MARK --set-mark $fwmark
iptables -t mangle -A TPROXY_PRE -m socket --transparent -j RETURN
iptables -t mangle -A TPROXY_PRE -p icmp -j RETURN
iptables -t mangle -A TPROXY_PRE -p udp --dport 53 -j TPROXY_ENT
iptables -t mangle -A TPROXY_PRE -p tcp --dport 53 -j TPROXY_ENT
iptables -t mangle -A TPROXY_PRE -m addrtype --dst-type LOCAL -j RETURN
iptables -t mangle -A TPROXY_PRE -m pkttype --pkt-type broadcast -j RETURN
iptables -t mangle -A TPROXY_PRE -m pkttype --pkt-type multicast -j RETURN
iptables -t mangle -A TPROXY_PRE -p tcp -j TPROXY --on-ip 127.0.0.1 --on-port $port --tproxy-mark $mark_proxy
iptables -t mangle -A TPROXY_PRE -p udp -j TPROXY --on-ip 127.0.0.1 --on-port $port --tproxy-mark $mark_proxy
iptables -t mangle -A TPROXY_PRE -m addrtype ! --dst-type UNICAST -j RETURN
iptables -t mangle -A TPROXY_PRE -j TPROXY_ENT
iptables -t mangle -A PREROUTING -j TPROXY_PRE
iptables -t mangle -N TPROXY_OUT
iptables -t mangle -A TPROXY_OUT -o lo -j RETURN
iptables -t mangle -A TPROXY_OUT -p icmp -j RETURN
iptables -t mangle -A TPROXY_OUT -m connmark --mark $make_newin -j RETURN # return incoming connection directly
iptables -t mangle -A TPROXY_OUT -m mark --mark $mark_noproxy -j RETURN
iptables -t mangle -A TPROXY_OUT -m cgroup --path $cgroup_noproxy -j RETURN
iptables -t mangle -A TPROXY_OUT -m cgroup --path $cgroup_proxy -j MARK --set-mark $mark_proxy
iptables -t mangle -A TPROXY_OUT -m connmark --mark $make_newin -j RETURN
iptables -t mangle -A TPROXY_OUT -m addrtype --dst-type LOCAL -j RETURN
iptables -t mangle -A TPROXY_OUT -m addrtype ! --dst-type UNICAST -j RETURN
for cg in ${cgroup_noproxy[@]}; do
iptables -t mangle -A TPROXY_OUT -m cgroup --path $cg -j RETURN
done
for cg in ${cgroup_proxy[@]}; do
iptables -t mangle -A TPROXY_OUT -m cgroup --path $cg -j MARK --set-mark $fwmark
done
iptables -t mangle -A OUTPUT -j TPROXY_OUT
#ipv6#
ip -6 rule add fwmark $mark_proxy table $table
ip -6 rule add fwmark $fwmark table $table
ip -6 route add local default dev lo table $table
ip6tables -t mangle -N TPROXY_ENT
ip6tables -t mangle -A TPROXY_ENT -p tcp -j TPROXY --on-ip localhost --on-port $port --tproxy-mark $fwmark
ip6tables -t mangle -A TPROXY_ENT -p udp -j TPROXY --on-ip localhost --on-port $port --tproxy-mark $fwmark
ip6tables -t mangle -N TPROXY_PRE
ip6tables -t mangle -A TPROXY_PRE -m socket --transparent -j MARK --set-mark $fwmark
ip6tables -t mangle -A TPROXY_PRE -m socket --transparent -j RETURN
ip6tables -t mangle -A TPROXY_PRE -p icmpv6 -j RETURN
ip6tables -t mangle -A TPROXY_PRE -p udp --dport 53 -j TPROXY_ENT
ip6tables -t mangle -A TPROXY_PRE -p tcp --dport 53 -j TPROXY_ENT
ip6tables -t mangle -A TPROXY_PRE -m addrtype --dst-type LOCAL -j RETURN
ip6tables -t mangle -A TPROXY_PRE -m pkttype --pkt-type broadcast -j RETURN
ip6tables -t mangle -A TPROXY_PRE -m pkttype --pkt-type multicast -j RETURN
ip6tables -t mangle -A TPROXY_PRE -p tcp -j TPROXY --on-ip ::1 --on-port $port --tproxy-mark $mark_proxy
ip6tables -t mangle -A TPROXY_PRE -p udp -j TPROXY --on-ip ::1 --on-port $port --tproxy-mark $mark_proxy
ip6tables -t mangle -A TPROXY_PRE -m addrtype ! --dst-type UNICAST -j RETURN
ip6tables -t mangle -A TPROXY_PRE -j TPROXY_ENT
ip6tables -t mangle -A PREROUTING -j TPROXY_PRE
ip6tables -t mangle -N TPROXY_OUT
ip6tables -t mangle -A TPROXY_OUT -o lo -j RETURN
ip6tables -t mangle -A TPROXY_OUT -p icmp -j RETURN
ip6tables -t mangle -A TPROXY_OUT -m connmark --mark $make_newin -j RETURN # return incoming connection directly
ip6tables -t mangle -A TPROXY_OUT -m mark --mark $mark_noproxy -j RETURN
ip6tables -t mangle -A TPROXY_OUT -m cgroup --path $cgroup_noproxy -j RETURN
ip6tables -t mangle -A TPROXY_OUT -m cgroup --path $cgroup_proxy -j MARK --set-mark $mark_proxy
ip6tables -t mangle -A TPROXY_OUT -p icmpv6 -j RETURN
ip6tables -t mangle -A TPROXY_OUT -m connmark --mark $make_newin -j RETURN
ip6tables -t mangle -A TPROXY_OUT -m addrtype --dst-type LOCAL -j RETURN
ip6tables -t mangle -A TPROXY_OUT -m addrtype ! --dst-type UNICAST -j RETURN
for cg in ${cgroup_noproxy[@]}; do
ip6tables -t mangle -A TPROXY_OUT -m cgroup --path $cg -j RETURN
done
for cg in ${cgroup_proxy[@]}; do
ip6tables -t mangle -A TPROXY_OUT -m cgroup --path $cg -j MARK --set-mark $fwmark
done
ip6tables -t mangle -A OUTPUT -j TPROXY_OUT
## allow to disable, order is important
$enable_dns || iptables -t mangle -I TPROXY_OUT -p udp --dport 53 -j RETURN
$enable_dns || ip6tables -t mangle -I TPROXY_OUT -p udp --dport 53 -j RETURN
$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
$enable_dns || iptables -t mangle -I TPROXY_OUT -p udp --dport 53 -j RETURN
$enable_dns || ip6tables -t mangle -I TPROXY_OUT -p udp --dport 53 -j RETURN
$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
if $enable_gateway; then
$enable_dns || iptables -t mangle -I TPROXY_PRE -p udp --dport 53 -j RETURN
$enable_dns || ip6tables -t mangle -I TPROXY_PRE -p udp --dport 53 -j RETURN
$enable_udp || iptables -t mangle -I TPROXY_PRE -p udp -j RETURN
$enable_udp || ip6tables -t mangle -I TPROXY_PRE -p udp -j RETURN
$enable_tcp || iptables -t mangle -I TPROXY_PRE -p tcp -j RETURN
$enable_tcp || ip6tables -t mangle -I TPROXY_PRE -p tcp -j RETURN
$enable_ipv4 || iptables -t mangle -I TPROXY_PRE -j RETURN
$enable_ipv6 || ip6tables -t mangle -I TPROXY_PRE -j RETURN
$enable_dns || iptables -t mangle -I TPROXY_PRE -p udp --dport 53 -j RETURN
$enable_dns || ip6tables -t mangle -I TPROXY_PRE -p udp --dport 53 -j RETURN
$enable_udp || iptables -t mangle -I TPROXY_PRE -p udp -j RETURN
$enable_udp || ip6tables -t mangle -I TPROXY_PRE -p udp -j RETURN
$enable_tcp || iptables -t mangle -I TPROXY_PRE -p tcp -j RETURN
$enable_tcp || ip6tables -t mangle -I TPROXY_PRE -p tcp -j RETURN
$enable_ipv4 || iptables -t mangle -I TPROXY_PRE -j RETURN
$enable_ipv6 || ip6tables -t mangle -I TPROXY_PRE -j RETURN
fi
## do not handle local device connection through tproxy if gateway is not enabled
$enable_gateway || iptables -t mangle -I TPROXY_PRE -m addrtype ! --src-type LOCAL -m addrtype ! --dst-type LOCAL -j RETURN
$enable_gateway || ip6tables -t mangle -I TPROXY_PRE -m addrtype ! --src-type LOCAL -m addrtype ! --dst-type LOCAL -j RETURN
## allow back to local device if gateway enabled, and avoid through tproxy again
$enable_gateway && iptables -t mangle -I TPROXY_OUT -m addrtype ! --src-type LOCAL -m addrtype ! --dst-type LOCAL -j RETURN
$enable_gateway && ip6tables -t mangle -I TPROXY_OUT -m addrtype ! --src-type LOCAL -m addrtype ! --dst-type LOCAL -j RETURN
$enable_gateway || iptables -t mangle -I TPROXY_PRE -m addrtype ! --src-type LOCAL -j RETURN
$enable_gateway || ip6tables -t mangle -I TPROXY_PRE -m addrtype ! --src-type LOCAL -j RETURN
## make sure following rules are the first in chain TPROXY_PRE to mark new incoming connection
## make sure following rules are the first in chain TPROXY_PRE to mark new incoming connection or gateway proxy connection
## so must put at last to insert first
iptables -t mangle -I TPROXY_PRE -m addrtype --dst-type LOCAL -m conntrack --ctstate NEW -j CONNMARK --set-mark $make_newin
ip6tables -t mangle -I TPROXY_PRE -m addrtype --dst-type LOCAL -m conntrack --ctstate NEW -j CONNMARK --set-mark $make_newin
iptables -t mangle -I TPROXY_PRE -m addrtype ! --src-type LOCAL -m conntrack --ctstate NEW -j CONNMARK --set-mark $make_newin
ip6tables -t mangle -I TPROXY_PRE -m addrtype ! --src-type LOCAL -m conntrack --ctstate NEW -j CONNMARK --set-mark $make_newin
## message for user
cat << DOC
proxied cgroup: $cgroup_proxy
noproxy cgroup: ${cgroup_noproxy[@]}
proxied cgroup: ${cgroup_proxy[@]}
DOC
if $enable_gateway; then
iptables -t nat -A POSTROUTING -m addrtype ! --src-type LOCAL -j MASQUERADE
ip6tables -t nat -A POSTROUTING -m addrtype ! --src-type LOCAL -j MASQUERADE
iptables -t nat -A POSTROUTING -m owner ! --socket-exists -j MASQUERADE
ip6tables -t nat -A POSTROUTING -m owner ! --socket-exists -s fc00::/7 -j MASQUERADE # only masquerade ipv6 private address
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1
echo "gateway enabled"

2
control/postinst Normal file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
systemctl enable --now cgproxy.service

2
control/prerm Normal file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
systemctl disable --now cgproxy.service

109
readme.md
View File

@@ -1,3 +1,5 @@
# Transparent Proxy with cgroup v2
@@ -6,7 +8,7 @@
cgproxy will transparent proxy anything running in specific cgroup. It resembles with *proxychains* and *tsock*, but without their disadvantages, and more powerfull.
It aslo supports global transparent proxy and gateway proxy. See [Global transparent proxy](#global-transparent-proxy) and [Gateway proxy](#gateway-proxy)
It aslo supports global transparent proxy and gateway proxy. See [Global transparent proxy](#global-transparent-proxy) and [Gateway proxy](#gateway-proxy).
<!--ts-->
@@ -36,25 +38,26 @@ It aslo supports global transparent proxy and gateway proxy. See [Global transpa
- TPROXY
A process listening on port (e.g. 12345) to accept iptables TPROXY, for example v2ray's dokodemo-door in tproxy mode.
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
mkdir build && cd build && cmake .. && make && sudo make install
```
It is alreay in [archlinux AUR](https://aur.archlinux.org/packages/cgproxy/).
- It is alreay in [archlinux AUR](https://aur.archlinux.org/packages/?K=cgproxy).
- DEB and RPM are packaged in [release page](https://github.com/springzfx/cgproxy/releases).
## How to use
- First enable service
- First enable and start service
```bash
sudo systemctl enable --now cgproxy.service
sudo systemctl status cgproxy.service
```
- Then prefix with cgproxy with your command, just like proxychains
```
@@ -67,41 +70,59 @@ It is alreay in [archlinux AUR](https://aur.archlinux.org/packages/cgproxy/).
cgproxy curl -vIs https://www.google.com
```
- To completely stop
```
sudo systemctl disable --now cgproxy.service
```
----
<details>
<summary>More config in `/etc/cgproxy.conf` (click to expand)</summary>
<summary>More config in <i>/etc/cgproxy.conf</i> (click to expand)</summary>
```bash
# see how to configure
# https://github.com/springzfx/cgproxy
########################################################################
## cgroup transparent proxy
###################################################################################
## any process in cgroup_proxy will be proxied, and cgroup_noproxy the opposite
## cgroup must start with slash '/'
# cgroup_proxy="/"
cgroup_proxy="/proxy.slice"
## note, cgroup must start with slash '/'
## the value can be string or bash array
## for array, only the first element will be created if not exist
## and the rest elements will not, so won't be applied if not exist
### global proxy with v2ray service
# cgroup_proxy="/"
# cgroup_noproxy=("/noproxy.slice" "/system.slice/v2ray.service")
### global proxy with manual `cgnoporxy qv2ray`
# cgroup_proxy="/"
# cgroup_noproxy="/noproxy.slice"
### default
cgroup_proxy="/proxy.slice"
cgroup_noproxy="/noproxy.slice"
########################################################################
###################################################################################
## allow as gateway for local network
enable_gateway=false
########################################################################
###################################################################################
## 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
###################################################################################
## if you set to false, it's traffic won't go through proxy,
## but still can go direct to internet
enable_dns=true
enable_tcp=true
enable_udp=true
enable_ipv4=true
enable_ipv6=true
enable_dns=true
########################################################################
###################################################################################
## do not modify this if you don't known what you are doing
table=100
mark_proxy=0x01
mark_noproxy=0xff
fwmark=0x01
mark_newin=0x02
```
</details>
@@ -113,24 +134,30 @@ sudo systemctl restart cgproxy.service
## Global transparent proxy
- First, set **cgroup_proxy="/"** in `/etc/cgproxy.conf`, this will proxy all connection
- Set `cgroup_proxy="/"` in */etc/cgproxy.conf*, this will proxy all connection
- Then, run your proxy software in cgroup_noproxy to allow direct to internet
- And allow your proxy program (v2ray) direct to internet, two ways:
- active way
```bash
cgnoproxy <PROXY PROGRAM>
# qv2ray as example
cgnoproxy qv2ray
# v2ray as example
cgnoproxy sudo v2ray --config config_file
```
- Finally, restart service `sudo systemctl restart cgproxy.service`, that's all
run `cgnoproxy <PROXY PROGRAM>`
example: `cgnoproxy sudo v2ray -config config_file`
example: `cgnoproxy qv2ray`
- passive way, useful if you run v2ray as service
set `cgroup_noproxy="<PROXY PROGRAM's CGROUP>"`
example: `cgroup_noproxy=("/noproxy.slice" "/system.slice/v2ray.service")`
- Finally, restart cgproxy service, that's all
## Gateway proxy
- set **enable_gateway=true** in `/etc/cgproxy.conf` and restart service
- other device set this host as gateway, and set public dns if necessary
- Set `enable_gateway=true` in */etc/cgproxy.conf*
- And allow your proxy software (v2ray) direct to internet, described above
- Other device set this host as gateway, and set public dns if necessary
## Other useful tools provided in this project
@@ -158,7 +185,7 @@ sudo systemctl restart cgproxy.service
## 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.
- `cgattach` 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 *sudoer* you can restrict permission or set NOPASSWD for youself.
- v2ray TPROXY need root or special permission
@@ -166,9 +193,17 @@ sudo systemctl restart cgproxy.service
sudo setcap "cap_net_admin,cap_net_bind_service=ep" /usr/lib/v2ray/v2ray
```
- Why not outbound mark solution, because in v2ray [when `"localhost"` is used, out-going DNS traffic is not controlled by V2Ray](https://www.v2fly.org/en/configuration/dns.html), so no mark at all, that's pity.
## TIPS
- `systemd-cgls` to see the cgroup hierarchical tree.
- Check cgroup2 support `findmnt -t cgroup2`
- Offer you v2ray service and full config exmaple in [v2ray_config](https://github.com/springzfx/cgproxy/tree/master/v2ray_config)
- Offer you qv2ray config example
![Qv2ray config example](https://i.loli.net/2020/04/28/bdQBzUD37FOgfvt.png)
## Licences

5
v2ray_config/00_log.json Normal file
View File

@@ -0,0 +1,5 @@
{
"log": {
"loglevel": "none"
}
}

10
v2ray_config/01_api.json Normal file
View File

@@ -0,0 +1,10 @@
{
"api": {
"services": [
"HandlerService",
"LoggerService",
"StatsService"
],
"tag": "API"
}
}

22
v2ray_config/02_dns.json Normal file
View File

@@ -0,0 +1,22 @@
{
"dns": {
"hosts": {
"geosite:category-ads": "127.0.0.1"
},
"servers": [
"https+local://223.5.5.5/dns-query",
"https://1.1.1.1/dns-query",
{
"address": "localhost",
"port": 53,
"domains": [
"geosite:cn"
],
"expectIPs": [
"geoip:cn"
]
}
],
"tag": "dns_inbound"
}
}

View File

@@ -0,0 +1,8 @@
{
"policy": {
"system": {
"statsInboundDownlink": true,
"statsInboundUplink": true
}
}
}

View File

@@ -0,0 +1,54 @@
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"domain": [
"geosite:category-ads-all"
],
"outboundTag": "outBound_BLACKHOLE",
"type": "field"
},
{
"inboundTag": [
"inbound_API"
],
"outboundTag": "API",
"type": "field"
},
{
"outboundTag": "dns-out",
"port": "53",
"type": "field"
},
{
"domain": [
"geosite:google",
"geosite:github",
"geosite:netflix",
"geosite:steam",
"geosite:telegram",
"geosite:tumblr",
"geosite:bbc"
],
"outboundTag": "outBound_PROXY",
"type": "field"
},
{
"domain": [
"geosite:cn"
],
"outboundTag": "outBound_DIRECT",
"type": "field"
},
{
"ip": [
"geoip:cn",
"geoip:private"
],
"outboundTag": "outBound_DIRECT",
"type": "field"
}
]
}
}

View File

@@ -0,0 +1,14 @@
{
"inbounds": [
{
"listen": "127.0.0.1",
"port": 15490,
"protocol": "dokodemo-door",
"settings": {
"address": "127.0.0.1"
},
"sniffing": {},
"tag": "inbound_API"
}
]
}

View File

@@ -0,0 +1,30 @@
{
"inbounds": [
{
"listen": "127.0.0.1",
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"address": "",
"followRedirect": true,
"network": "tcp,udp",
"port": 0,
"timeout": 300,
"userLevel": 0
},
"sniffing": {
"destOverride": [
"http",
"tls"
],
"enabled": true
},
"streamSettings": {
"sockopt": {
"tproxy": "tproxy"
}
},
"tag": "tproxy_IN_ipv4lo"
}
]
}

View File

@@ -0,0 +1,30 @@
{
"inbounds": [
{
"listen": "::1",
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"address": "",
"followRedirect": true,
"network": "tcp,udp",
"port": 0,
"timeout": 300,
"userLevel": 0
},
"sniffing": {
"destOverride": [
"http",
"tls"
],
"enabled": true
},
"streamSettings": {
"sockopt": {
"tproxy": "tproxy"
}
},
"tag": "tproxy_IN_ipv6lo"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"inbounds": [
{
"listen": "127.0.0.1",
"port": 8888,
"protocol": "http",
"sniffing": {
"enabled": false
},
"tag": "http_IN"
}
]
}

View File

@@ -0,0 +1,17 @@
{
"inbounds": [
{
"listen": "127.0.0.1",
"port": 1080,
"protocol": "socks",
"settings": {
"auth": "noauth",
"userLevel": 0
},
"sniffing": {
"enabled": false
},
"tag": "socks_IN"
}
]
}

View File

@@ -0,0 +1,19 @@
{
"outbounds": [
{
"protocol": "blackhole",
"sendThrough": "0.0.0.0",
"settings": {
"response": {
"type": "none"
}
},
"streamSettings": {
"sockopt": {
"mark": 255
}
},
"tag": "outBound_BLACKHOLE"
}
]
}

View File

@@ -0,0 +1,19 @@
{
"outbounds": [
{
"protocol": "freedom",
"sendThrough": "0.0.0.0",
"settings": {
"domainStrategy": "UseIP",
"redirect": ":0",
"userLevel": 0
},
"streamSettings": {
"sockopt": {
"mark": 255
}
},
"tag": "outBound_DIRECT"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"outbounds": [
{
"protocol": "dns",
"streamSettings": {
"sockopt": {
"mark": 255
}
},
"tag": "dns-out"
}
]
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,3 @@
{
"stats": {}
}

View File

@@ -0,0 +1 @@
{}

2
v2ray_config/merge.sh Normal file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
jq -rs 'reduce .[] as $item ({}; . + $item + {inbounds: (.inbounds + $item.inbounds)} + {outbounds: ($item.outbounds + .outbounds)})' *.json |sudo tee /etc/v2ray/config.json > /dev/null

8
v2ray_config/readme.md Normal file
View File

@@ -0,0 +1,8 @@
## Usage
- Fill `06_outbounds_myproxy.json` with your vmess proxy config with tag `outBound_PROXY`.
- Start with `sudo v2ray -confdir .`
## Reference
- [v2ray multi-file config](https://www.v2fly.org/chapter_02/multiple_config.html)

View File

@@ -0,0 +1,18 @@
[Unit]
Description=V2Ray - A unified platform for anti-censorship
Documentation=https://v2ray.com https://guide.v2fly.org
After=network.target nss-lookup.target
Wants=network-online.target
[Service]
Type=exec
ExecStart=/usr/lib/v2ray/v2ray -config /etc/v2ray/config.json
User=nobody
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
Restart=on-failure
# Don't restart in the case of configuration error
RestartPreventExitStatus=23
[Install]
WantedBy=multi-user.target