4 Commits
v0.11 ... v0.12

Author SHA1 Message Date
fancy
1fa0d51e1d bump version 2020-05-18 21:34:30 +08:00
fancy
aedebf4e31 merge to one executable 2020-05-18 21:34:30 +08:00
fancy
051742eef1 rename .hpp to .h 2020-05-18 21:34:30 +08:00
fancy
619fcaae8e build library 2020-05-18 21:34:30 +08:00
23 changed files with 462 additions and 397 deletions

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(cgproxy VERSION 4.1)
project(cgproxy VERSION 0.12)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-result")
set(build_tools OFF)
@@ -19,6 +19,7 @@ if (build_test)
add_subdirectory(test)
endif()
install(FILES cgproxyd DESTINATION /usr/bin PERMISSIONS ${basic_permission})
install(FILES cgnoproxy DESTINATION /usr/bin PERMISSIONS ${basic_permission})
install(FILES cgproxy.service DESTINATION /usr/lib/systemd/system/)
install(FILES config.json DESTINATION /etc/cgproxy/)

2
cgproxyd Normal file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
/usr/bin/cgproxy --daemon $@

View File

@@ -3,10 +3,12 @@ find_package(nlohmann_json REQUIRED)
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_executable(cgproxyd cgproxyd.cpp)
add_executable(cgproxy cgproxy.cpp)
target_link_libraries(cgproxyd PRIVATE Threads::Threads nlohmann_json::nlohmann_json)
target_link_libraries(cgproxy PRIVATE nlohmann_json::nlohmann_json)
add_executable(main main.cpp
common.cpp config.cpp cgroup_attach.cpp
socket_client.cpp socket_server.cpp)
target_link_libraries(main nlohmann_json::nlohmann_json Threads::Threads)
set_target_properties(main PROPERTIES LINKER_LANGUAGE CXX)
set_target_properties(main PROPERTIES OUTPUT_NAME cgproxy)
install(TARGETS cgproxyd DESTINATION /usr/bin PERMISSIONS ${basic_permission})
install(TARGETS cgproxy DESTINATION /usr/bin PERMISSIONS ${basic_permission})
install(TARGETS main DESTINATION /usr/bin PERMISSIONS ${basic_permission})

View File

@@ -1,13 +1,25 @@
#include "common.hpp"
#include "socket_client.hpp"
#include "common.h"
#include "config.h"
#include "socket_client.h"
#include <cstdlib>
#include <nlohmann/json.hpp>
#include <unistd.h>
using json = nlohmann::json;
using namespace CGPROXY;
using namespace CGPROXY::CONFIG;
namespace CGPROXY::CGPROXY {
bool print_help = false, proxy = true;
void print_usage() {
fprintf(stdout, "Usage: cgproxy [--help] [--debug] [--noproxy] <CMD>\n");
fprintf(stdout, "Alias: cgnoproxy = cgproxy --noproxy\n");
inline void print_usage() {
if (proxy) {
cout << "Run program with proxy" << endl;
cout << "Usage: cgproxy [--help] [--debug] <CMD>" << endl;
} else {
cout << "Run program without proxy" << endl;
cout << "Usage: cgpnoroxy [--help] [--debug] <CMD>" << endl;
cout << "Alias: cgnoproxy = cgproxy --noproxy" << endl;
}
}
void processArgs(const int argc, char *argv[], int &shift) {
@@ -20,30 +32,35 @@ void processArgs(const int argc, char *argv[], int &shift) {
}
}
bool attach2cgroup(pid_t pid, bool proxy) {
void send_pid(const pid_t pid, bool proxy, int &status) {
json j;
j["type"] = proxy ? MSG_TYPE_PROXY_PID : 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;
processArgs(argc, argv, shift);
if (argc == shift || print_help) {
if (print_help) {
print_usage();
exit(0);
}
pid_t pid = getpid();
if (!attach2cgroup(pid, proxy)) {
if (argc == shift) {
error("no program specified");
exit(EXIT_FAILURE);
}
int status = -1;
send_pid(getpid(), proxy, status);
if (status != 0) {
error("attach process failed");
exit(EXIT_FAILURE);
}
string s = join2str(argc - shift, argv + shift, ' ');
return system(s.c_str());
}
}
} // namespace CGPROXY::CGPROXY

View File

@@ -1,26 +1,23 @@
#include "cgroup_attach.hpp"
#include "common.hpp"
#include "config.hpp"
#include "socket_server.hpp"
#ifndef CGPROXYD_HPP
#define CGPROXYD_HPP
#include "cgroup_attach.h"
#include "common.h"
#include "config.h"
#include "socket_server.h"
#include <csignal>
#include <errno.h>
#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>
#include <pthread.h>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <sys/file.h>
#include <unistd.h>
using namespace std;
using json = nlohmann::json;
using namespace CGPROXY::SOCKET;
using namespace CGPROXY::CONFIG;
using namespace CGPROXY::CGROUP;
using namespace ::CGPROXY::SOCKET;
using namespace ::CGPROXY::CONFIG;
using namespace ::CGPROXY::CGROUP;
namespace CGPROXY {
namespace CGPROXY::CGPROXYD {
class cgproxyd {
thread_arg arg_t;
@@ -81,8 +78,8 @@ class cgproxyd {
try {
type = j.at("type").get<int>();
switch (type) {
case MSG_TYPE_JSON:
status = config.loadFromJson(j.at("data"));
case MSG_TYPE_CONFIG_JSON:
status = config.loadFromJsonStr(j.at("data").dump());
if (status == SUCCESS) status = applyConfig(&config);
return status;
break;
@@ -152,11 +149,13 @@ public:
cgproxyd *cgproxyd::instance = NULL;
} // namespace CGPROXY
bool print_help = false;
void print_usage() { printf("cgproxyd [--help] [--debug]\n"); }
void print_usage() {
cout << "Start a daemon with unix socket to accept control" << endl;
cout << "Usage: cgproxyd [--help] [--debug]" << endl;
cout << "Alias: cgproxyd = cgproxy --daemon" << endl;
}
void processArgs(const int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
@@ -175,10 +174,11 @@ int main(int argc, char *argv[]) {
if (getuid() != 0) {
error("permission denied, need root");
print_usage();
exit(EXIT_FAILURE);
}
CGPROXY::cgproxyd d;
cgproxyd d;
return d.start();
}
}
} // namespace CGPROXY::CGPROXYD
#endif

View File

@@ -1,7 +1,5 @@
#ifndef CGPROUP_ATTACH_H
#define CGPROUP_ATTACH_H
#include "common.hpp"
#include "cgroup_attach.h"
#include "common.h"
#include <errno.h>
#include <fstream>
#include <iostream>
@@ -12,7 +10,6 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
namespace CGPROXY::CGROUP {
@@ -95,6 +92,4 @@ int attach(const int pid, const string cgroup_target) {
return attach(to_str(pid), cgroup_target);
}
} // namespace CGPROXY::CGROUP
#endif
} // namespace CGPROXY::CGROUP

18
src/cgroup_attach.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef CGPROUP_ATTACH_H
#define CGPROUP_ATTACH_H
#include <stdlib.h>
#include <string>
using namespace std;
namespace CGPROXY::CGROUP {
bool exist(string path);
bool validate(string pid, string cgroup);
string get_cgroup2_mount_point(int &status);
int attach(const string pid, const string cgroup_target);
int attach(const int pid, const string cgroup_target);
} // namespace CGPROXY::CGROUP
#endif

34
src/common.cpp Normal file
View File

@@ -0,0 +1,34 @@
#include "common.h"
#include <regex>
bool enable_debug = false;
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; }

View File

@@ -1,6 +1,12 @@
#ifndef COMMON_H
#define COMMON_H 1
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
#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"
@@ -12,7 +18,7 @@
#define CGROUP_PROXY_PRESVERED "/proxy.slice"
#define CGROUP_NOPROXY_PRESVERED "/noproxy.slice"
#define MSG_TYPE_JSON 1
#define MSG_TYPE_CONFIG_JSON 1
#define MSG_TYPE_CONFIG_PATH 2
#define MSG_TYPE_PROXY_PID 3
#define MSG_TYPE_NOPROXY_PID 4
@@ -28,24 +34,22 @@
#define CGROUP_ERROR 6
#define FILE_ERROR 7
#include <iostream>
#include <regex>
#include <sstream>
#include <string>
using namespace std;
static bool enable_debug = false;
extern bool enable_debug;
#define error(...) \
{ \
fprintf(stderr, "error: "); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
}
#define debug(...) \
if (enable_debug) { \
fprintf(stderr, "debug: "); \
fprintf(stdout, __VA_ARGS__); \
fprintf(stdout, "\n"); \
}
#define return_error return -1;
#define return_success return 0;
@@ -57,34 +61,12 @@ template <typename... T> string to_str(T... 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 vector<string> t, const char delm = ' ');
string join2str(const int argc, char **argv, const char delm = ' ');
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; }
bool validCgroup(const string cgroup);
bool validCgroup(const vector<string> cgroup);
bool validPid(const string pid);
bool validPort(const int port);
#endif

121
src/config.cpp Normal file
View File

@@ -0,0 +1,121 @@
#include "config.h"
#include "common.h"
#include <fstream>
#include <iomanip>
#include <nlohmann/json.hpp>
#include <set>
using json = nlohmann::json;
#define add2json(v) j[#v] = v;
#define tryassign(v) \
try { \
j.at(#v).get_to(v); \
} catch (exception & e) {}
#define merge(v) \
{ \
v.erase(std::remove(v.begin(), v.end(), v##_preserved), v.end()); \
v.insert(v.begin(), v##_preserved); \
}
namespace CGPROXY::CONFIG {
void Config::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 Config::saveToFile(const string f) {
ofstream o(f);
if (!o.is_open()) return FILE_ERROR;
string js = toJsonStr();
o << setw(4) << js << endl;
o.close();
return 0;
}
string Config::toJsonStr() {
json j;
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);
return j.dump();
}
int Config::loadFromFile(const string f) {
debug("loading config: %s", f.c_str());
ifstream ifs(f);
if (ifs.is_open()) {
string js = to_str(ifs.rdbuf());
ifs.close();
return loadFromJsonStr(js);
} else {
error("open failed: %s", f.c_str());
return FILE_ERROR;
}
}
int Config::loadFromJsonStr(const string js) {
if (!validateJsonStr(js)) {
error("json validate fail");
return PARAM_ERROR;
}
json j = json::parse(js);
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);
return 0;
}
void Config::mergeReserved() {
merge(cgroup_proxy);
merge(cgroup_noproxy);
}
bool Config::validateJsonStr(const string js) {
json j = json::parse(js);
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;
}
} // namespace CGPROXY::CONFIG

38
src/config.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef CONFIG_H
#define CONFIG_H
#include "common.h"
#include <stdlib.h>
#include <string>
#include <vector>
using namespace std;
namespace CGPROXY::CONFIG {
class Config {
public:
const string cgroup_proxy_preserved = CGROUP_PROXY_PRESVERED;
const string cgroup_noproxy_preserved = CGROUP_NOPROXY_PRESVERED;
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;
void toEnv();
int saveToFile(const string f);
string toJsonStr();
int loadFromFile(const string f);
int loadFromJsonStr(const string js);
private:
void mergeReserved();
bool validateJsonStr(const string js);
};
} // namespace CGPROXY::CONFIG
#endif

View File

@@ -1,155 +0,0 @@
#ifndef CONFIG_H
#define CONFIG_H
#include "common.hpp"
#include <fstream>
#include <iomanip>
#include <iostream>
#include <nlohmann/json.hpp>
#include <set>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
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;
}
#define add2json(v) j[#v] = v;
json toJson() {
json j;
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);
return j;
}
#undef add2json
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;
}
}
#define tryassign(v) \
try { \
j.at(#v).get_to(v); \
} catch (exception & e) {}
int loadFromJson(const json &j) {
if (!validateJson(j)) {
error("json validate fail");
return PARAM_ERROR;
}
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);
return 0;
}
#undef assign
#define merge(v) \
{ \
v.erase(std::remove(v.begin(), v.end(), v##_preserved), v.end()); \
v.insert(v.begin(), v##_preserved); \
}
void mergeReserved() {
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;
}
};
} // namespace CGPROXY::CONFIG
#endif

17
src/main.cpp Normal file
View File

@@ -0,0 +1,17 @@
#include "cgproxy.hpp"
#include "cgproxyd.hpp"
bool as_cgproxyd = false;
void processArgs(const int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--daemon") == 0) { as_cgproxyd = true; }
if (argv[i][0] != '-') { break; }
}
}
int main(int argc, char *argv[]) {
processArgs(argc, argv);
if (as_cgproxyd) ::CGPROXY::CGPROXYD::main(argc, argv);
else
::CGPROXY::CGPROXY::main(argc, argv);
}

View File

@@ -1,20 +1,9 @@
#ifndef SOCKET_CLIENT_H
#define SOCKET_CLIENT_H
#include "common.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "socket_client.h"
#include "common.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
using namespace std;
namespace CGPROXY::SOCKET {
#define return_if_error(flag, msg) \
if (flag == -1) { \
perror(msg); \
@@ -23,6 +12,8 @@ namespace CGPROXY::SOCKET {
return; \
}
namespace CGPROXY::SOCKET {
void send(const char *msg, int &status) {
debug("send msg: %s", msg);
status = UNKNOWN_ERROR;
@@ -59,5 +50,4 @@ void send(const string msg, int &status) {
debug("return status: %d", status);
}
} // namespace CGPROXY::SOCKET
#endif
} // namespace CGPROXY::SOCKET

14
src/socket_client.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef SOCKET_CLIENT_H
#define SOCKET_CLIENT_H
#include <stdlib.h>
#include <string>
using namespace std;
namespace CGPROXY::SOCKET {
void send(const char *msg, int &status);
void send(const string msg, int &status);
} // namespace CGPROXY::SOCKET
#endif

65
src/socket_server.cpp Normal file
View File

@@ -0,0 +1,65 @@
#include "socket_server.h"
#include "common.h"
#include <filesystem>
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
namespace fs = std::filesystem;
namespace CGPROXY::SOCKET {
void SocketServer::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");
}
}
void *SocketServer::startThread(void *arg) {
thread_arg *p = (thread_arg *)arg;
SocketServer server;
server.socketListening(p->handle_msg);
return (void *)0;
}
SocketServer::~SocketServer() {
close(sfd);
close(cfd);
unlink(SOCKET_PATH);
}
} // namespace CGPROXY::SOCKET

33
src/socket_server.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef SOCKET_SERVER_H
#define SOCKET_SERVER_H
#include <functional>
#include <stdlib.h>
#include <sys/un.h>
using namespace std;
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);
~SocketServer();
static void *startThread(void *arg);
};
} // namespace CGPROXY::SOCKET
#endif

View File

@@ -1,93 +0,0 @@
#ifndef SOCKET_SERVER_H
#define SOCKET_SERVER_H
#include "common.hpp"
#include <filesystem>
#include <functional>
#include <iostream>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
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;
}
};
} // namespace CGPROXY::SOCKET
#endif

View File

@@ -2,5 +2,6 @@ include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR}/src)
find_package(nlohmann_json REQUIRED)
add_executable(client_test socket_client_test.cpp)
add_executable(client_test socket_client_test.cpp
../src/socket_client.cpp ../src/common.cpp ../src/config.cpp)
target_link_libraries(client_test nlohmann_json::nlohmann_json)

View File

@@ -1,48 +1,48 @@
#include "socket_client.hpp"
#include "common.h"
#include "config.h"
#include "socket_client.h"
#include <nlohmann/json.hpp>
using namespace std;
using json = nlohmann::json;
using namespace CGPROXY;
using namespace CGPROXY::CONFIG;
void test_json() {
void send_config(Config &config, int &status) {
json j;
j["type"] = MSG_TYPE_JSON;
j["data"]["cgroup_proxy"] = "/";
j["data"]["enable_dns"] = false;
int status;
j["type"] = MSG_TYPE_CONFIG_JSON;
j["data"] = config.toJsonStr();
SOCKET::send(j.dump(), status);
}
void test_json_array() {
json j;
j["type"] = MSG_TYPE_JSON;
j["data"]["cgroup_proxy"] = "/proxy.slice";
j["data"]["cgroup_noproxy"] = {"/noproxy.slice", "/system.slice/v2ray.service"};
int status;
SOCKET::send(j.dump(), status);
}
void test_file() {
void send_config_path(const string s, int &status) {
json j;
j["type"] = MSG_TYPE_CONFIG_PATH;
j["data"] = "/etc/cgproxy.conf";
int status;
j["data"] = s;
SOCKET::send(j.dump(), status);
}
void test_pid() {
void send_pid(const pid_t pid, bool proxy, int &status) {
json j;
j["type"] = MSG_TYPE_PROXY_PID;
j["data"] = "9999";
int status;
j["type"] = proxy ? MSG_TYPE_PROXY_PID : MSG_TYPE_NOPROXY_PID;
j["data"] = pid;
SOCKET::send(j.dump(), status);
}
void test_config() {
Config config;
config.cgroup_proxy = {"/"};
int status;
send_config(config, status);
}
void test_config_path() {
string path = "/etc/cgproxy/config.json";
int status;
send_config_path(path, status);
}
int main() {
test_json_array();
test_file();
test_json();
test_pid();
test_config();
return 0;
}

View File

@@ -1,18 +0,0 @@
// #include "common.h"
#include "config.hpp"
#include <fstream>
#include <iostream>
#include <pthread.h>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
using namespace std;
using namespace CGPROXY::CONFIG;
int main() {
Config c;
c.saveToFile("./config.json");
return 0;
}

View File

@@ -1,4 +1,4 @@
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR}/src)
add_executable(cgattach cgattach.cpp)
add_executable(cgattach cgattach.cpp ../src/cgroup_attach.cpp ../src/common.cpp)
install(TARGETS cgattach DESTINATION /usr/bin PERMISSIONS ${basic_permission})

View File

@@ -1,6 +1,7 @@
#include "cgroup_attach.hpp"
#include "common.hpp"
#include "cgroup_attach.h"
#include "common.h"
#include <cstdlib>
#include <unistd.h>
using namespace std;
void print_usage() { fprintf(stdout, "usage: cgattach <pid> <cgroup>\n"); }