33 Commits
v0.06 ... v0.10

Author SHA1 Message Date
fancy
ee3a5d0fa2 merge from dev 2020-05-16 16:05:56 +08:00
fancy
f2210f9bda updated readme 2020-05-16 15:17:40 +08:00
fancy
e86ea01f6e updated readme 2020-05-16 15:12:39 +08:00
fancy
bc9f6d4d4e clean from v3.x, add json dependency 2020-05-16 14:35:59 +08:00
fancy
6de88897b2 add todo comment 2020-05-16 14:22:04 +08:00
fancy
39275452da fix precess args 2020-05-16 14:12:44 +08:00
fancy
a16cefbfb2 handle signal, robust iptables clean 2020-05-16 14:07:07 +08:00
fancy
2adba75b3e cgproxyd as class 2020-05-16 11:53:15 +08:00
fancy
fbcc499ba8 rename .h to .hpp 2020-05-16 10:49:47 +08:00
fancy
1c16f57193 now based on unix socket and json config 2020-05-16 10:29:34 +08:00
fancy
87cd5a6d99 missing one file 2020-05-16 00:17:37 +08:00
fancy
138fa698be update readme 2020-05-16 00:12:03 +08:00
fancy
ffea0fb2b9 add local aur build 2020-05-16 00:12:03 +08:00
fancy
696fcb6b4e update readme 2020-05-16 00:12:03 +08:00
fancy
9b7d6804f7 update readme 2020-05-16 00:12:03 +08:00
fancy
ad362998d8 allow array input for cgroup_proxy and cgroup_noproxy 2020-05-16 00:11:25 +08:00
fancy
2b5ff745ac core socket feature 2020-05-16 00:07:04 +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
b5701d8b49 allow array input for cgroup_proxy and cgroup_noproxy 2020-05-14 04:39:02 +08:00
fancy
4e37bccc1a add basic unix socket control 2020-05-13 23:43:28 +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
34 changed files with 901 additions and 350 deletions

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@ build
.vscode
v2ray_config/proxy
v2ray_config/06_outbounds_proxy.json
aur-*

View File

@@ -1,26 +1,37 @@
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_BUILD_TYPE DEBUG)
# set(CMAKE_BUILD_TYPE RELEASE)
project(cgproxy VERSION 4.0)
find_package(Threads REQUIRED)
find_package(nlohmann_json REQUIRED)
include_directories(${PROJECT_SOURCE_DIR})
project(cgproxy VERSION 3.6)
add_executable(cgattach cgattach.cpp)
add_executable(cgproxyd cgproxyd.cpp)
add_executable(cgproxy cgproxy.cpp)
add_executable(cgnoproxy cgnoproxy.cpp)
target_link_libraries(cgproxyd Threads::Threads nlohmann_json::nlohmann_json)
target_link_libraries(cgproxy nlohmann_json::nlohmann_json)
target_link_libraries(cgnoproxy nlohmann_json::nlohmann_json)
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 cgnoproxy.sh DESTINATION /usr/bin
RENAME cgnoproxy
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
# install(FILES run_in_cgroup.sh DESTINATION /usr/bin
# RENAME run_in_cgroup
# PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
# add_executable(client_test socket_client_test.cpp)
# target_link_libraries(client_test nlohmann_json::nlohmann_json)
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/)
set(basic_permission OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(TARGETS cgattach DESTINATION /usr/bin PERMISSIONS ${basic_permission})
install(TARGETS cgproxyd DESTINATION /usr/bin PERMISSIONS ${basic_permission})
install(TARGETS cgproxy DESTINATION /usr/bin PERMISSIONS ${basic_permission})
install(TARGETS cgnoproxy DESTINATION /usr/bin PERMISSIONS ${basic_permission})
install(FILES cgproxy.service DESTINATION /usr/lib/systemd/system/)
install(FILES config.json DESTINATION /etc/cgproxy/)
install(FILES cgroup-tproxy.sh DESTINATION /usr/share/cgproxy/scripts/)
install(FILES readme.md DESTINATION /share/doc/cgproxy/)
## package for deb and rpm
@@ -31,7 +42,7 @@ set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "cgproxy will transparent proxy anything r
## 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_DEPENDS "systemd" "nlohmann-json3-dev")
set(CPACK_DEBIAN_PACKAGE_SECTION "network")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "Optional")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/springzfx/cgproxy")
@@ -41,7 +52,7 @@ set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CONTROL_DIR}/postinst;${CONTROL_DIR}/p
## rpm pack
set(CPACK_RPM_PACKAGE_ARCHITECTURE, "x86_64")
set(CPACK_RPM_PACKAGE_REQUIRES "systemd")
set(CPACK_RPM_PACKAGE_REQUIRES "systemd" "json-devel")
set(CPACK_RPM_PACKAGE_GROUP "network")
set(CPACK_RPM_PACKAGE_URL "https://github.com/springzfx/cgproxy")
set(CONTROL_DIR ${CMAKE_SOURCE_DIR}/control)

View File

@@ -1,98 +1,23 @@
#include <errno.h>
#include <fstream>
#include <iostream>
#include <regex>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "cgroup_attach.hpp"
using namespace std;
void print_usage() { fprintf(stdout, "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;
fprintf(stderr, "paramater validate error\n");
print_usage();
exit(EXIT_FAILURE);
}
string get_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){
fprintf(stderr, "cgroup2 not supported\n");
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 need root");
exit(EXIT_FAILURE);
}
if (argc != 3) {
fprintf(stderr, "only need 2 paramaters\n");
error("need exact 2 paramaters");
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_mount_point = get_cgroup2_mount_point();
string cgroup_target_path = cgroup_mount_point + cgroup_target;
string cgroup_target_procs = cgroup_target_path + "/cgroup.procs";
// check if exist, we will 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, errno %d\n",
cgroup_target.c_str(), errno);
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 may 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;
CGPROXY::CGROUP::attach(pid,cgroup_target);
}

31
cgnoproxy.cpp Normal file
View File

@@ -0,0 +1,31 @@
#include <nlohmann/json.hpp>
#include "socket_client.hpp"
using json = nlohmann::json;
using namespace CGPROXY;
bool attach2cgproxy(){
pid_t pid=getpid();
json j;
j["type"] = MSG_TYPE_NOPROXY_PID;
j["data"] = pid;
int status;
SOCKET::send(j.dump(), status);
return status==0;
}
int main(int argc, char *argv[]){
int shift=1;
if (argc==1){
error("usage: cgnoproxy [--debug] <CMD>\nexample: cgnoproxy curl -I https://www.google.com");
exit(EXIT_FAILURE);
}
processArgs(argc,argv,shift);
if (!attach2cgproxy()){
error("attach process failed");
exit(EXIT_FAILURE);
}
string s=join2str(argc-shift,argv+shift,' ');
return system(s.c_str());
}

View File

@@ -1,16 +0,0 @@
#!/bin/bash
config="/etc/cgproxy.conf"
source $config
# test suid bit
if [ -u "$(which cgattach)" ]; then
cgattach $$ $cgroup_noproxy && attached=1
else
sudo cgattach $$ $cgroup_noproxy && attached=1
fi
# test attach success or not
[[ -z "$attached" ]] && echo "attach error" && exit 1
exec "$@"

View File

@@ -1,33 +0,0 @@
# 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"
cgroup_noproxy="/noproxy.slice"
# cgroup_noproxy="/system.slice/v2ray.service"
########################################################################
## 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
enable_dns=true
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
table=100
fwmark=0x01
mark_newin=0x02

31
cgproxy.cpp Normal file
View File

@@ -0,0 +1,31 @@
#include <nlohmann/json.hpp>
#include "socket_client.hpp"
using json = nlohmann::json;
using namespace CGPROXY;
bool attach2cgproxy(){
pid_t pid=getpid();
json j;
j["type"] = MSG_TYPE_PROXY_PID;
j["data"] = pid;
int status;
SOCKET::send(j.dump(), status);
return status==0;
}
int main(int argc, char *argv[]){
int shift=1;
if (argc==1){
error("usage: cgproxy [--debug] <CMD>\nexample: cgroxy curl -I https://www.google.com");
exit(EXIT_FAILURE);
}
processArgs(argc,argv,shift);
if (!attach2cgproxy()){
error("attach process failed");
exit(EXIT_FAILURE);
}
string s=join2str(argc-shift,argv+shift,' ');
return system(s.c_str());
}

View File

@@ -1,11 +1,10 @@
[Unit]
Description=proxy cgroup
Description=cgproxy service
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
Type=simple
ExecStart=/usr/bin/cgproxyd
[Install]
WantedBy=multi-user.target

View File

@@ -1,16 +0,0 @@
#!/bin/bash
config="/etc/cgproxy.conf"
source $config
# test suid bit
if [ -u "$(which cgattach)" ]; then
cgattach $$ $cgroup_proxy && attached=1
else
sudo cgattach $$ $cgroup_proxy && attached=1
fi
# test attach success or not
[[ -z "$attached" ]] && echo "attach error" && exit 1
exec "$@"

140
cgproxyd.cpp Normal file
View File

@@ -0,0 +1,140 @@
#include "common.hpp"
#include "socket_server.hpp"
#include <fstream>
#include <iostream>
#include <libconfig.h++>
#include <nlohmann/json.hpp>
#include <pthread.h>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <csignal>
#include "config.hpp"
#include "cgroup_attach.hpp"
using namespace std;
using json = nlohmann::json;
using namespace CGPROXY::SOCKET;
using namespace CGPROXY::CONFIG;
using namespace CGPROXY::CGROUP;
namespace CGPROXY{
class cgproxyd{
thread_arg arg_t;
Config config;
pthread_t socket_thread_id = -1;
static cgproxyd* instance;
static int handle_msg_static(char* msg){
if (!instance) {
error("no cgproxyd instance assigned");
return ERROR;
}
return instance->handle_msg(msg);
}
static void signalHandler( int signum ){
debug("Signal %d received.", &signum);
if (!instance){ error("no cgproxyd instance assigned");}
else { instance->stop(); }
exit(signum);
}
int handle_msg(char *msg) {
debug("received msg: %s", msg);
json j;
try{ j = json::parse(msg); }catch(exception& e){debug("msg paser error");return MSG_ERROR;}
int type, status;
int pid, cgroup_target;
try {
type = j.at("type").get<int>();
switch (type)
{
case MSG_TYPE_JSON:
status=config.loadFromJson(j.at("data"));
if (status==SUCCESS) status=applyConfig(&config);
return status;
break;
case MSG_TYPE_CONFIG_PATH:
status=config.loadFromFile(j.at("data").get<string>());
if (status==SUCCESS) status=applyConfig(&config);
return status;
break;
case MSG_TYPE_PROXY_PID:
pid=j.at("data").get<int>();
status=attach(pid, config.cgroup_proxy_preserved);
return status;
break;
case MSG_TYPE_NOPROXY_PID:
pid=j.at("data").get<int>();
status=attach(pid, config.cgroup_noproxy_preserved);
return status;
break;
default:
return MSG_ERROR;
break;
};
} catch (out_of_range &e) {
return MSG_ERROR;
} catch (exception &e){
return ERROR;
}
}
pthread_t startSocketListeningThread() {
arg_t.handle_msg = &handle_msg_static;
pthread_t thread_id;
int status =
pthread_create(&thread_id, NULL, &SocketServer::startThread, &arg_t);
if (status != 0)
error("socket thread create failed");
return thread_id;
}
void assignStaticInstance(){
instance=this;
}
public:
int start(int argc, char* argv[]) {
signal(SIGINT, &signalHandler);
signal(SIGTERM,&signalHandler);
signal(SIGHUP,&signalHandler);
int shift=1;
processArgs(argc,argv,shift);
config.loadFromFile(DEFAULT_CONFIG_FILE);
applyConfig(&config);
assignStaticInstance();
socket_thread_id = startSocketListeningThread();
pthread_join(socket_thread_id, NULL);
return 0;
}
int applyConfig(Config *c) {
system(TPROXY_IPTABLS_CLEAN);
c->toEnv();
system(TPROXY_IPTABLS_START);
// no need to track running status
return 0;
}
void stop(){
debug("stopping");
system(TPROXY_IPTABLS_CLEAN);
}
~cgproxyd(){
stop();
}
};
cgproxyd* cgproxyd::instance=NULL;
}
int main(int argc, char* argv[]) {
CGPROXY::cgproxyd d;
return d.start(argc,argv);
}

View File

@@ -30,22 +30,35 @@ cat << 'DOC'
DOC
}
## check root
[ ! $(id -u) -eq 0 ] && { >&2 echo "need root to modify iptables";exit -1; }
## any process in this cgroup will be proxied
cgroup_proxy="/proxy.slice"
cgroup_noproxy="/noproxy.slice"
if [ -z ${cgroup_proxy+x} ]; then
cgroup_proxy="/proxy.slice"
else
IFS=':' read -r -a cgroup_proxy <<< "$cgroup_proxy"
fi
## any process in this cgroup will not be proxied
if [ -z ${cgroup_noproxy+x} ]; then
cgroup_noproxy="/noproxy.slice"
else
IFS=':' read -r -a cgroup_noproxy <<< "$cgroup_noproxy"
fi
# allow as gateway for local network
enable_gateway=false
[ -z ${enable_gateway+x} ] && enable_gateway=false
## some variables
port=12345
[ -z ${port+x} ] && port=12345
## some options
enable_dns=true
enable_tcp=true
enable_udp=true
enable_ipv4=true
enable_ipv6=true
[ -z ${enable_dns+x} ] && enable_dns=true
[ -z ${enable_tcp+x} ] && enable_tcp=true
[ -z ${enable_udp+x} ] && enable_udp=true
[ -z ${enable_ipv4+x} ] && enable_ipv4=true
[ -z ${enable_ipv6+x} ] && enable_ipv6=true
## do not modify this if you don't known what you are doing
table=100
@@ -53,46 +66,50 @@ 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"
stop(){
iptables -t mangle -L TPROXY_PRE &> /dev/null || return
echo "cleaning 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
ip6tables -t mangle -X TPROXY_ENT
ip rule delete fwmark $fwmark lookup $table
ip route flush table $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 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
}
## parse parameter
for i in "$@"
do
case $i in
stop)
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
ip6tables -t mangle -X TPROXY_ENT
ip rule delete fwmark $fwmark lookup $table
ip route flush table $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 not reliable
iptables -t nat -D POSTROUTING -m owner ! --socket-exists -j MASQUERADE &> /dev/null
ip6tables -t nat -D POSTROUTING -m owner ! --socket-exists -j MASQUERADE &> /dev/null
stop
exit 0
;;
--config=*)
config=${i#*=}
source $config
shift
;;
--help)
print_help
@@ -102,9 +119,12 @@ 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;
echo "applying tproxy iptables"
## use TPROXY
#ipv4#
ip rule add fwmark $fwmark table $table
@@ -127,10 +147,14 @@ iptables -t mangle -A PREROUTING -j TPROXY_PRE
iptables -t mangle -N TPROXY_OUT
iptables -t mangle -A TPROXY_OUT -p icmp -j RETURN
iptables -t mangle -A TPROXY_OUT -m connmark --mark $make_newin -j RETURN
iptables -t mangle -A TPROXY_PRE -m addrtype --dst-type LOCAL -j RETURN
iptables -t mangle -A TPROXY_PRE -m addrtype ! --dst-type UNICAST -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 $fwmark
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#
@@ -154,10 +178,14 @@ ip6tables -t mangle -A PREROUTING -j TPROXY_PRE
ip6tables -t mangle -N TPROXY_OUT
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_PRE -m addrtype --dst-type LOCAL -j RETURN
ip6tables -t mangle -A TPROXY_PRE -m addrtype ! --dst-type UNICAST -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 $fwmark
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
@@ -192,14 +220,14 @@ ip6tables -t mangle -I TPROXY_PRE -m addrtype ! --src-type LOCAL -m conntrack --
## message for user
cat << DOC
noproxy cgroup: $cgroup_noproxy
proxied cgroup: $cgroup_proxy
noproxy cgroup: ${cgroup_noproxy[@]}
proxied cgroup: ${cgroup_proxy[@]}
DOC
if $enable_gateway; then
iptables -t nat -A POSTROUTING -m owner ! --socket-exists -j MASQUERADE
ip6tables -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"

103
cgroup_attach.hpp Normal file
View File

@@ -0,0 +1,103 @@
#ifndef CGPROUP_ATTACH_H
#define CGPROUP_ATTACH_H
#include <errno.h>
#include <fstream>
#include <iostream>
#include <regex>
#include <stdlib.h>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include "common.hpp"
using namespace std;
namespace CGPROXY::CGROUP{
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 = validPid(pid);
bool cg_v = validCgroup(cgroup);
if (pid_v && cg_v)
return true;
error("attach paramater validate error");
return_error
}
string get_cgroup2_mount_point(int &status){
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");
status=-1;
return NULL;
}
status=0;
return cgroup2_mount_point;
}
int attach(const string pid, const string cgroup_target) {
if (getuid()!=0) {
error("need root to attach cgroup");
return_error
}
debug("attaching %s to %s",pid.c_str(),cgroup_target.c_str());
int status;
if (!validate(pid, cgroup_target)) return_error
string cgroup_mount_point = get_cgroup2_mount_point(status);
if (status!=0) return_error
string cgroup_target_path = cgroup_mount_point + cgroup_target;
string cgroup_target_procs = cgroup_target_path + "/cgroup.procs";
// check if exist, we will 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) {
debug("created cgroup %s success", cgroup_target.c_str());
} else {
error("created cgroup %s failed, errno %d", cgroup_target.c_str(), errno);
return_error
}
// error("cgroup %s not exist",cgroup_target.c_str());
// return_error
}
// put pid to target cgroup
ofstream procs(cgroup_target_procs, ofstream::app);
if (!procs.is_open()) {
error("open file %s failed", cgroup_target_procs.c_str());
return_error
}
procs << pid.c_str() << endl;
procs.close();
// maybe there some write error, for example process pid may not exist
if (!procs) {
error("write %s to %s failed, maybe process %s not exist",
pid.c_str(), cgroup_target_procs.c_str(), pid.c_str());
return_error
}
return_success
}
int attach(const int pid, const string cgroup_target){
return attach(to_str(pid), cgroup_target);
}
}
#endif

107
common.hpp Normal file
View File

@@ -0,0 +1,107 @@
#ifndef COMMON_H
#define COMMON_H 1
#define TPROXY_IPTABLS_START "sh /usr/share/cgproxy/scripts/cgroup-tproxy.sh"
#define TPROXY_IPTABLS_CLEAN "sh /usr/share/cgproxy/scripts/cgroup-tproxy.sh stop"
#define SOCKET_PATH "/tmp/cgproxy_unix_socket"
#define LISTEN_BACKLOG 64
#define DEFAULT_CONFIG_FILE "/etc/cgproxy/config.json"
#define CGROUP_PROXY_PRESVERED "/proxy.slice"
#define CGROUP_NOPROXY_PRESVERED "/noproxy.slice"
#define MSG_TYPE_JSON 1
#define MSG_TYPE_CONFIG_PATH 2
#define MSG_TYPE_PROXY_PID 3
#define MSG_TYPE_NOPROXY_PID 4
#define UNKNOWN_ERROR 99
#define ERROR -1
#define SUCCESS 0
#define CONN_ERROR 1
#define MSG_ERROR 2
#define PARSE_ERROR 3
#define PARAM_ERROR 4
#define APPLY_ERROR 5
#define CGROUP_ERROR 6
#define FILE_ERROR 7
#include <iostream>
#include <sstream>
#include <string>
#include <regex>
using namespace std;
static bool enable_debug=false;
static bool print_help=false;
#define error(...) {fprintf(stderr, __VA_ARGS__);fprintf(stderr, "\n");}
#define debug(...) if (enable_debug) {fprintf(stdout, __VA_ARGS__);fprintf(stdout, "\n");}
#define return_error return -1;
#define return_success return 0;
void processArgs(const int argc, char *argv[], int &shift){
for (int i=1;i<argc;i++){
if (strcmp(argv[i], "--debug")==0){
enable_debug=true;
}
if (strcmp(argv[i], "--help")==0){
print_help=true;
}
if (argv[i][0]!='-') {
break;
}
shift+=1;
}
}
template <typename... T>
string to_str(T... args) {
stringstream ss;
ss.clear();
ss << std::boolalpha;
(ss << ... << args);
return ss.str();
}
string join2str(const vector<string> t, const char delm=' '){
string s;
for (const auto &e : t)
e!=*(t.end()-1)?s+=e+delm:s+=e;
return s;
}
string join2str(const int argc,char** argv, const char delm=' '){
string s;
for (int i=0;i<argc;i++){
s+=argv[i];
if (i!=argc-1) s+=delm;
}
return s;
}
bool validCgroup(const string cgroup){
return regex_match(cgroup, regex("^/[a-zA-Z0-9\\-_./@]*$"));
}
bool validCgroup(const vector<string> cgroup){
for (auto &e:cgroup){
if (!regex_match(e, regex("^/[a-zA-Z0-9\\-_./@]*$"))){
return false;
}
}
return true;
}
bool validPid(const string pid){
return regex_match(pid, regex("^[0-9]+$"));
}
bool validPort(const int port){
return port>0;
}
#endif

143
config.hpp Normal file
View File

@@ -0,0 +1,143 @@
#ifndef CONFIG_H
#define CONFIG_H
#include "common.hpp"
#include "socket_server.hpp"
#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>
#include <pthread.h>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <set>
#include <iomanip>
using namespace std;
using json = nlohmann::json;
namespace CGPROXY::CONFIG{
struct Config {
public:
const string cgroup_proxy_preserved=CGROUP_PROXY_PRESVERED;
const string cgroup_noproxy_preserved=CGROUP_NOPROXY_PRESVERED;
private:
vector<string> cgroup_proxy;
vector<string> cgroup_noproxy;
bool enable_gateway = false;
int port = 12345;
bool enable_dns = true;
bool enable_tcp = true;
bool enable_udp = true;
bool enable_ipv4 = true;
bool enable_ipv6 = true;
public:
void toEnv() {
mergeReserved();
setenv("cgroup_proxy", join2str(cgroup_proxy,':').c_str(), 1);
setenv("cgroup_noproxy", join2str(cgroup_noproxy, ':').c_str(), 1);
setenv("enable_gateway", to_str(enable_gateway).c_str(), 1);
setenv("port", to_str(port).c_str(), 1);
setenv("enable_dns", to_str(enable_dns).c_str(), 1);
setenv("enable_tcp", to_str(enable_tcp).c_str(), 1);
setenv("enable_udp", to_str(enable_udp).c_str(), 1);
setenv("enable_ipv4", to_str(enable_ipv4).c_str(), 1);
setenv("enable_ipv6", to_str(enable_ipv6).c_str(), 1);
}
int saveToFile(const string f){
ofstream o(f);
if (!o.is_open()) return FILE_ERROR;
json j=toJson();
o << setw(4) << j << endl;
o.close();
return 0;
}
json toJson(){
json j;
#define add2json(v) j[#v]=v;
add2json(cgroup_proxy);
add2json(cgroup_noproxy);
add2json(enable_gateway);
add2json(port);
add2json(enable_dns);
add2json(enable_tcp);
add2json(enable_udp);
add2json(enable_ipv4);
add2json(enable_ipv6);
#undef add2json
return j;
}
int loadFromFile(const string f) {
debug("loading config: %s", f.c_str());
ifstream ifs(f);
if (ifs.is_open()){
json j;
try { ifs >> j; }catch (exception& e){error("parse error: %s", f.c_str());ifs.close();return PARSE_ERROR;}
ifs.close();
return loadFromJson(j);
}else{
error("open failed: %s",f.c_str());
return FILE_ERROR;
}
}
int loadFromJson(const json &j) {
if (!validateJson(j)) {error("json validate fail"); return PARAM_ERROR;}
#define tryassign(v) try{j.at(#v).get_to(v);}catch(exception &e){}
tryassign(cgroup_proxy);
tryassign(cgroup_noproxy);
tryassign(enable_gateway);
tryassign(port);
tryassign(enable_dns);
tryassign(enable_tcp);
tryassign(enable_udp);
tryassign(enable_ipv4);
tryassign(enable_ipv6);
#undef assign
return 0;
}
void mergeReserved(){
#define merge(v) { \
v.erase(std::remove(v.begin(), v.end(), v ## _preserved), v.end()); \
v.insert(v.begin(), v ## _preserved); \
}
merge(cgroup_proxy);
merge(cgroup_noproxy);
#undef merge
}
bool validateJson(const json &j){
bool status=true;
const set<string> boolset={"enable_gateway","enable_dns","enable_tcp","enable_udp","enable_ipv4","enable_ipv6"};
for (auto& [key, value] : j.items()) {
if (key=="cgroup_proxy"||key=="cgroup_noproxy"){
if (value.is_string()&&!validCgroup((string)value)) status=false;
// TODO what if vector<int> etc.
if (value.is_array()&&!validCgroup((vector<string>)value)) status=false;
if (!value.is_string()&&!value.is_array()) status=false;
}else if (key=="port"){
if (!validPort(value)) status=false;
}else if (boolset.find(key)!=boolset.end()){
if (!value.is_boolean()) status=false;
}else{
error("unknown key: %s", key.c_str());
return false;
}
if (!status) {
error("invalid value for key: %s", key.c_str());
return false;
}
}
return true;
}
};
}
#endif

11
config.json Normal file
View File

@@ -0,0 +1,11 @@
{
"cgroup_noproxy": ["/system.slice/v2ray.service"],
"cgroup_proxy": [],
"enable_dns": true,
"enable_gateway": false,
"enable_ipv4": true,
"enable_ipv6": true,
"enable_tcp": true,
"enable_udp": true,
"port": 12345
}

119
readme.md
View File

@@ -8,15 +8,15 @@
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-->
* [Transparent Proxy with cgroup v2](#transparent-proxy-with-cgroup-v2)
* [Introduction](#introduction)
* [Prerequest](#prerequest)
* [How to install](#how-to-install)
* [How to use](#how-to-use)
* [Default usage](#default-usage)
* [Configuration](#configuration)
* [Global transparent proxy](#global-transparent-proxy)
* [Gateway proxy](#gateway-proxy)
* [Other useful tools provided in this project](#other-useful-tools-provided-in-this-project)
@@ -24,7 +24,7 @@ It aslo supports global transparent proxy and gateway proxy. See [Global transpa
* [TIPS](#tips)
* [Licences](#licences)
<!-- Added by: fancy, at: Thu 23 Apr 2020 01:23:57 PM HKT -->
<!-- Added by: fancy, at: Sat 16 May 2020 03:12:07 PM HKT -->
<!--te-->
@@ -43,14 +43,14 @@ It aslo supports global transparent proxy and gateway proxy. See [Global transpa
## How to install
```bash
mkdir build && cd build && cmake .. && make && sudo make install
mkdir build && cd build && cmake .. && make && 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
## Default usage
- First enable and start service
@@ -60,57 +60,51 @@ mkdir build && cd build && cmake .. && make && sudo make install
- Then prefix with cgproxy with your command, just like proxychains
```
cgproxy <CMD>
```bash
cgproxy [--debug] <CMD>
```
- For example, test proxy
```bash
cgproxy curl -vIs https://www.google.com
cgproxy curl -I https://www.google.com
```
- To completely stop
```
sudo systemctl disable --now cgproxy.service
```
----
<details>
<summary>More config in <i>/etc/cgproxy.conf</i> (click to expand)</summary>
```bash
########################################################################
## cgroup transparent proxy
## any process in cgroup_proxy will be proxied, and cgroup_noproxy the opposite
## cgroup must start with slash '/'
# cgroup_proxy="/"
# cgroup_noproxy="/system.slice/v2ray.service"
cgroup_proxy="/proxy.slice"
cgroup_noproxy="/noproxy.slice"
## Configuration
########################################################################
## allow as gateway for local network
enable_gateway=false
Config file: **/etc/cgproxy/config.json**
########################################################################
## 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_dns=true
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
table=100
fwmark=0x01
mark_newin=0x02
```json
{
"cgroup_noproxy": ["/system.slice/v2ray.service"],
"cgroup_proxy": [],
"enable_dns": true,
"enable_gateway": false,
"enable_ipv4": true,
"enable_ipv6": true,
"enable_tcp": true,
"enable_udp": true,
"port": 12345
}
```
</details>
- **port** tproxy listenning port
- **cgroup_noproxy** cgroup array that no need to proxy, `/noproxy.slice` is preserved
- **cgroup_proxy** cgroup array that need to proxy, `/proxy.slice` is preserved
- **enable_gateway** enable gateway proxy for local devices
- **enable_dns** enable dns to go to proxy
- **enable_tcp**
- **enable_udp**
- **enable_ipv4**
- **enable_ipv6**
**Note**: cgroup in configuration need to be exist, otherwise ignored
If you changed config, remember to restart service
```bash
@@ -119,43 +113,34 @@ sudo systemctl restart cgproxy.service
## Global transparent proxy
- Set `cgroup_proxy="/"` in */etc/cgproxy.conf*, this will proxy all connection
- Set `"cgroup_proxy":["/"]` in configuration, this will proxy all connection
- And allow your proxy program (v2ray) direct to internet, two ways:
- active way
run `cgnoproxy <PROXY PROGRAM>`
example: `cgnoproxy sudo v2ray -config config_file`
- passive way
- Allow your proxy program (v2ray) direct to internet to avoid loop. Two ways:
set `cgroup_noproxy="<PROXY PROGRAM's CGROUP>"`
- active way, run command
example: `cgnoproxy sudo v2ray -config config_file`
example: `cgnoproxy qv2ray`
- passive way, set it's cgroup in configuration, very useful for service
example: `cgroup_noproxy="/system.slice/v2ray.service"`
example: `"cgroup_noproxy":["/system.slice/v2ray.service"]`
- Finally, restart cgproxy service, that's all
## Gateway proxy
- 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
- Set `"enable_gateway":true` in configuration
- And allow your proxy software (v2ray) direct to internet if necessary, described above
- Other device set this host as gateway, and set public dns if need
## Other useful tools provided in this project
- `cgnoproxy` run program wihout proxy, very useful in global transparent proxy
```bash
cgnoproxy <CMD>
```
- `run_in_cgroup` run command in specific cgroup which will create if not exist , cgroup can be only one level down exist cgroup, otherwise created fail.
```bash
run_in_cgroup --cgroup=CGROUP <COMMAND>
# example
run_in_cgroup --cgroup=/mycgroup.slice ping 127.0.0.1
cgnoproxy [--debug] <CMD>
```
- `cgattach` attach specific process pid to specific cgroup which will create if not exist , cgroup can be only one level down exist cgroup, otherwise created fail.
@@ -168,8 +153,6 @@ sudo systemctl restart cgproxy.service
## NOTES
- `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
```bash

View File

@@ -1,50 +0,0 @@
#!/bin/bash
print_help(){
cat << 'DOC'
usage:
run_in_cgroup --cgroup=CGROUP <COMMAND>
run_in_cgroup --help
note:
CGROUP must start will slash '/' , and no special character
example:
run_in_cgroup --cggroup=/mycgroup.slice ping 127.0.0.1
DOC
}
## parse parameter
for i in "$@"
do
case $i in
--cgroup=*)
cgroup=${i#*=}
shift
;;
--help)
print_help
exit 0
shift
;;
-*)
shift
;;
*)
break
;;
esac
done
[[ -z "$cgroup" ]] && print_help && exit 1
[[ -z "$@" ]] && print_help && exit 1
# test suid bit
if [ -u "$(which cgattach)" ]; then
cgattach $$ $cgroup && attached=1
else
sudo cgattach $$ $cgroup && attached=1
fi
# test attach success or not
[[ -z "$attached" ]] && print_help && exit 1
exec "$@"

64
socket_client.hpp Normal file
View File

@@ -0,0 +1,64 @@
#ifndef SOCKET_CLIENT_H
#define SOCKET_CLIENT_H
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include "common.hpp"
using namespace std;
namespace CGPROXY::SOCKET{
#define return_if_error(flag, msg) \
if (flag == -1) { \
perror(msg); \
status = CONN_ERROR; \
close(sfd); \
return; \
}
void send(const char *msg, int &status) {
debug("send msg: %s", msg);
status = UNKNOWN_ERROR;
int flag;
int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un unix_socket;
memset(&unix_socket, '\0', sizeof(struct sockaddr_un));
unix_socket.sun_family = AF_UNIX;
strncpy(unix_socket.sun_path, SOCKET_PATH, sizeof(unix_socket.sun_path) - 1);
flag =
connect(sfd, (struct sockaddr *)&unix_socket, sizeof(struct sockaddr_un));
return_if_error(flag, "connect");
int msg_len = strlen(msg);
flag = write(sfd, &msg_len, sizeof(int));
return_if_error(flag, "write length");
flag = write(sfd, msg, msg_len * sizeof(char));
return_if_error(flag, "write msg");
flag = read(sfd, &status, sizeof(int));
return_if_error(flag, "read return value");
close(sfd);
}
void send(const string msg, int &status) {
int msg_len = msg.length();
char buff[msg_len];
msg.copy(buff, msg_len, 0);
buff[msg_len] = '\0';
send(buff, status);
debug("return status: %d", status);
}
}
#endif

94
socket_server.hpp Normal file
View File

@@ -0,0 +1,94 @@
#ifndef SOCKET_SERVER_H
#define SOCKET_SERVER_H
#include <functional>
#include <iostream>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <sys/stat.h>
#include <filesystem>
#include "common.hpp"
using namespace std;
namespace fs = std::filesystem;
namespace CGPROXY::SOCKET{
#define continue_if_error(flag, msg) \
if (flag == -1) { \
perror(msg); \
continue; \
}
struct thread_arg {
function<int(char *)> handle_msg;
};
class SocketServer {
public:
int sfd = -1, cfd = -1, flag = -1;
struct sockaddr_un unix_socket;
void socketListening(function<int(char *)> callback) {
debug("starting socket listening");
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fs::exists(SOCKET_PATH)&&unlink(SOCKET_PATH)==-1){
error("%s exist, and can't unlink",SOCKET_PATH);
return;
}
memset(&unix_socket, '\0', sizeof(struct sockaddr_un));
unix_socket.sun_family = AF_UNIX;
strncpy(unix_socket.sun_path, SOCKET_PATH,
sizeof(unix_socket.sun_path) - 1);
bind(sfd, (struct sockaddr *)&unix_socket, sizeof(struct sockaddr_un));
listen(sfd, LISTEN_BACKLOG);
chmod(SOCKET_PATH,S_IRWXU|S_IRWXG|S_IRWXO);
while (true) {
close(cfd);
cfd = accept(sfd, NULL, NULL);
continue_if_error(cfd, "accept");
debug("accept connection: %d", cfd);
// read length
int msg_len;
flag = read(cfd, &msg_len, sizeof(int));
continue_if_error(flag, "read length");
// read msg
char msg[msg_len];
flag = read(cfd, msg, msg_len * sizeof(char));
continue_if_error(flag, "read msg");
msg[msg_len]='\0';
// handle msg
int status = callback(msg);
// send back flag
flag = write(cfd, &status, sizeof(int));
continue_if_error(flag, "write back");
}
}
~SocketServer() {
close(sfd);
close(cfd);
unlink(SOCKET_PATH);
}
static void *startThread(void *arg) {
thread_arg *p = (thread_arg *)arg;
SocketServer server;
server.socketListening(p->handle_msg);
return (void *)0;
}
};
}
#endif

View File

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

View File

@@ -1,7 +1,10 @@
{
"dns": {
"hosts": {
"geosite:category-ads": "127.0.0.1"
},
"servers": [
"https://223.5.5.5/dns-query",
"https+local://223.5.5.5/dns-query",
"https://1.1.1.1/dns-query",
{
"address": "localhost",

View File

@@ -21,13 +21,6 @@
"port": "53",
"type": "field"
},
{
"inboundTag": [
"dns_inbound"
],
"outboundTag": "outBound_DIRECT",
"type": "field"
},
{
"domain": [
"geosite:google",

View File

@@ -1,2 +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
jq -rs 'reduce .[] as $item ({}; . + $item + {inbounds: (.inbounds + $item.inbounds)} + {outbounds: ($item.outbounds + .outbounds)})' *.json |sudo tee /etc/v2ray/config.json > /dev/null

View File

@@ -5,15 +5,14 @@ After=network.target nss-lookup.target
Wants=network-online.target
[Service]
Type=simple
Type=exec
ExecStart=/usr/lib/v2ray/v2ray -config /etc/v2ray/config.json
User=nobody
#AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
ExecStart=+/usr/lib/v2ray/v2ray -config /etc/v2ray/config.json
Restart=on-failure
# Don't restart in the case of configuration error
RestartPreventExitStatus=23
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target