now based on unix socket and json config

This commit is contained in:
fancy
2020-05-16 00:45:38 +08:00
parent 87cd5a6d99
commit 1c16f57193
12 changed files with 173 additions and 66 deletions

View File

@@ -1,33 +1,32 @@
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 3.7)
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})
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)
add_executable(main main.cpp)
target_link_libraries(main Threads::Threads nlohmann_json::nlohmann_json)
# add_executable(client_test socket_client_test.cpp)
# target_link_libraries(client_test nlohmann_json::nlohmann_json)
add_executable(client_test socket_client_test.cpp)
target_link_libraries(client_test nlohmann_json::nlohmann_json)
set(basic_permission OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
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(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/)
@@ -40,8 +39,6 @@ install(FILES readme.md
DESTINATION /share/doc/cgproxy/)
## package for deb and rpm
set(CPACK_GENERATOR "DEB;RPM")
set(CPACK_PACKAGE_NAME "cgproxy")

View File

@@ -1,6 +1,6 @@
# Maintainer: Fancy Zhang <springzfx@gmail.com>
pkgname=cgproxy-git
pkgver=v3.8.r1.gc0668fd
pkgver=v4.0.r1.g3fde647
pkgrel=1
pkgdesc="A transparent proxy program with cgroup2, like proxychains"
arch=('x86_64')
@@ -13,8 +13,8 @@ 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")
# source=("${pkgname}::git+file://${curr_dir}/../.git")
source=("${pkgname}::git+file:///home/fancy/workspace/cgproxy#branch=dev")
md5sums=('SKIP')
pkgver() {

34
cgnoproxy.cpp Normal file
View File

@@ -0,0 +1,34 @@
#include <nlohmann/json.hpp>
#include "socket_client.h"
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);
}
if (argv[1]=="--debug"){
enable_debug=true;
shift+=1;
}
if (!attach2cgproxy()){
error("attach process failed");
exit(EXIT_FAILURE);
}
string s=join2str(argc-shift,argv+shift,' ');
return system(s.c_str());
}

31
cgproxy.cpp Normal file
View File

@@ -0,0 +1,31 @@
#include <nlohmann/json.hpp>
#include "socket_client.h"
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

@@ -36,7 +36,7 @@ int handle_msg(char *msg) {
try{ j = json::parse(msg); }catch(exception& e){debug("msg paser error");return MSG_ERROR;}
int type, status;
string pid, cgroup_target;
int pid, cgroup_target;
try {
type = j.at("type").get<int>();
switch (type)
@@ -52,12 +52,12 @@ int handle_msg(char *msg) {
return status;
break;
case MSG_TYPE_PROXY_PID:
pid=j.at("data").get<string>();
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<string>();
pid=j.at("data").get<int>();
status=attach(pid, config.cgroup_noproxy_preserved);
return status;
break;
@@ -83,7 +83,10 @@ pthread_t startSocketListeningThread() {
return thread_id;
}
int main() {
int main(int argc, char* argv[]) {
int shift=1;
processArgs(argc,argv,shift);
bool enable_socket = true;
string config_path = DEFAULT_CONFIG_FILE;
config.loadFromFile(config_path);

View File

@@ -30,29 +30,35 @@ cat << 'DOC'
DOC
}
check_root(){
uid=$(id -u)
[ ! $uid -eq 0 ] && { >&2 echo "permission denied, need root";exit 0; }
}
check_root
## 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

View File

@@ -30,7 +30,7 @@ bool validate(string pid, string cgroup) {
if (pid_v && cg_v)
return true;
error("paramater validate error");
error("attach paramater validate error");
return_error
}
@@ -53,8 +53,11 @@ int attach(const string pid, const string cgroup_target) {
error("need root to attach cgroup");
return_error
}
debug("attaching %s to %s",pid.c_str(),cgroup_target.c_str());
int status;
validate(pid, cgroup_target);
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;
@@ -91,6 +94,10 @@ int attach(const string pid, const string cgroup_target) {
return_success
}
int attach(const int pid, const string cgroup_target){
return attach(to_str(pid), cgroup_target);
}
}
#endif

View File

@@ -1,9 +1,9 @@
#ifndef COMMON_H
#define COMMON_H
#define COMMON_H 1
#define SOCKET_PATH "/tmp/unix_socket"
#define SOCKET_PATH "/tmp/cgproxy_unix_socket"
#define LISTEN_BACKLOG 64
#define DEFAULT_CONFIG_FILE "/etc/cgproxy.conf"
#define DEFAULT_CONFIG_FILE "/etc/cgproxy/config.json"
#define CGROUP_PROXY_PRESVERED "/proxy.slice"
#define CGROUP_NOPROXY_PRESVERED "/noproxy.slice"
@@ -31,27 +31,53 @@
#include <regex>
using namespace std;
extern bool enable_debug=false;
extern bool print_help=false;
#define error(...) {fprintf(stderr, __VA_ARGS__);fprintf(stderr, "\n");}
#define debug(...) {fprintf(stdout, __VA_ARGS__);fprintf(stdout, "\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 << ... << args) << endl;
ss << std::boolalpha;
(ss << ... << args);
return ss.str();
}
template <typename T>
string join2str(const T t){
string join2str(const vector<string> t, const char delm=' '){
string s;
string delm=" ", prefix="(", tail=")", wrap="\"";
for (const auto &e : t)
e!=*(t.end()-1)?s+=wrap+e+wrap+delm:s+=wrap+e+wrap;
return prefix+s+tail;
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){
@@ -71,8 +97,8 @@ bool validPid(const string pid){
return regex_match(pid, regex("^[0-9]+$"));
}
bool validPort(const string port){
return regex_match(port, regex("^[0-9]+$"));
bool validPort(const int port){
return port>0;
}
#endif

View File

@@ -36,8 +36,8 @@ struct Config {
public:
void toEnv() {
mergeReserved();
setenv("cgroup_proxy", join2str(cgroup_proxy).c_str(), 1);
setenv("cgroup_noproxy", join2str(cgroup_noproxy).c_str(), 1);
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);
@@ -122,9 +122,9 @@ public:
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;
if (!validPort(value)) status=false;
}else if (boolset.find(key)!=boolset.end()){
if (value.is_boolean()) status=false;
if (!value.is_boolean()) status=false;
}else{
error("unknown key: %s", key.c_str());
return false;

View File

@@ -1,5 +1,5 @@
{
"cgroup_noproxy": [],
"cgroup_noproxy": ["/system.slice/v2ray.service"],
"cgroup_proxy": [],
"enable_dns": true,
"enable_gateway": false,

View File

@@ -12,8 +12,10 @@
#include <sys/un.h>
#include <unistd.h>
#include <sys/stat.h>
#include <filesystem>
#include "common.h"
using namespace std;
namespace fs = std::filesystem;
namespace CGPROXY::SOCKET{
@@ -38,8 +40,10 @@ public:
debug("starting socket listening");
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
flag=unlink(SOCKET_PATH);
if (flag==-1) {error("%s exist, and can't unlink",SOCKET_PATH); exit(EXIT_FAILURE);}
if (fs::exists(SOCKET_PATH)&&unlink(SOCKET_PATH)==-1){
error("%s exist, and can't unlink",SOCKET_PATH);
exit(EXIT_FAILURE);
}
memset(&unix_socket, '\0', sizeof(struct sockaddr_un));
unix_socket.sun_family = AF_UNIX;
strncpy(unix_socket.sun_path, SOCKET_PATH,