diff --git a/CMakeLists.txt b/CMakeLists.txt index 29b25e9..2611474 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,39 +1,30 @@ 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}) - -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(client_test socket_client_test.cpp) -# target_link_libraries(client_test nlohmann_json::nlohmann_json) +set(build_tools OFF) +# set(build_tools ON) +set(build_test OFF) +# set(build_test ON) 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}) +add_subdirectory(src) +if (build_tools) + add_subdirectory(tools) +endif() +if (build_test) + add_subdirectory(test) +endif() + +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/) 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") diff --git a/_clang-format b/_clang-format new file mode 100644 index 0000000..7eecddb --- /dev/null +++ b/_clang-format @@ -0,0 +1,137 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Always +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 90 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + - Regex: '.*' + Priority: 1 + SortPriority: 0 +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: Latest +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +... + diff --git a/cgnoproxy b/cgnoproxy new file mode 100644 index 0000000..5898ff9 --- /dev/null +++ b/cgnoproxy @@ -0,0 +1,2 @@ +#!/bin/sh +/usr/bin/cgproxy --noproxy $@ \ No newline at end of file diff --git a/cgnoproxy.cpp b/cgnoproxy.cpp deleted file mode 100644 index 0dcf7ba..0000000 --- a/cgnoproxy.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "socket_client.hpp" -#include -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] \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()); -} \ No newline at end of file diff --git a/cgproxy.cpp b/cgproxy.cpp deleted file mode 100644 index 9d72972..0000000 --- a/cgproxy.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "socket_client.hpp" -#include -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] \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()); -} \ No newline at end of file diff --git a/readme.md b/readme.md index 8a1a3c4..26d9d76 100644 --- a/readme.md +++ b/readme.md @@ -67,7 +67,7 @@ mkdir build && cd build && cmake .. && make && make install - For example, test proxy ```bash - cgproxy curl -I https://www.google.com + cgproxy curl -vI https://www.google.com ``` - To completely stop @@ -153,7 +153,7 @@ sudo systemctl restart cgproxy.service ## NOTES -- v2ray TPROXY need root or special permission +- v2ray TPROXY need root or special permission, use [service](https://github.com/springzfx/cgproxy/blob/v3.x/v2ray_config/v2ray.service) or ```bash sudo setcap "cap_net_admin,cap_net_bind_service=ep" /usr/lib/v2ray/v2ray diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..ac3d66b --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,12 @@ +find_package(Threads REQUIRED) +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) + +install(TARGETS cgproxyd DESTINATION /usr/bin PERMISSIONS ${basic_permission}) +install(TARGETS cgproxy DESTINATION /usr/bin PERMISSIONS ${basic_permission}) diff --git a/src/cgproxy.cpp b/src/cgproxy.cpp new file mode 100644 index 0000000..072dcd8 --- /dev/null +++ b/src/cgproxy.cpp @@ -0,0 +1,47 @@ +#include "socket_client.hpp" +#include +using json = nlohmann::json; +using namespace CGPROXY; + +void print_usage() { + fprintf(stdout, "Usage: cgproxy [--help] [--debug] [--noproxy] \n"); + fprintf(stdout, "Alias: cgnoproxy = cgproxy --noproxy\n"); +} + +void processArgs(const int argc, char *argv[], int &shift, bool &proxy) { + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--noproxy") == 0) { proxy = false; } + 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; + } +} + +bool attach2cgroup(pid_t pid,bool proxy) { + 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[]) { + if (argc == 1) { + error( + "usage: cgproxy [--debug] \nexample: cgroxy curl -I https://www.google.com"); + exit(EXIT_FAILURE); + } + + int shift = 1; bool proxy=true; + processArgs(argc, argv, shift,proxy); + pid_t pid = getpid(); + if (!attach2cgroup(pid,proxy)) { + error("attach process failed"); + exit(EXIT_FAILURE); + } + + string s = join2str(argc - shift, argv + shift, ' '); + return system(s.c_str()); +} \ No newline at end of file diff --git a/cgproxyd.cpp b/src/cgproxyd.cpp similarity index 90% rename from cgproxyd.cpp rename to src/cgproxyd.cpp index 06aeade..53b4274 100644 --- a/cgproxyd.cpp +++ b/src/cgproxyd.cpp @@ -96,14 +96,11 @@ class cgproxyd { void assignStaticInstance() { instance = this; } public: - int start(int argc, char *argv[]) { + int start() { signal(SIGINT, &signalHandler); signal(SIGTERM, &signalHandler); signal(SIGHUP, &signalHandler); - int shift = 1; - processArgs(argc, argv, shift); - config.loadFromFile(DEFAULT_CONFIG_FILE); applyConfig(&config); @@ -119,10 +116,12 @@ public: // no need to track running status return 0; } + void stop() { debug("stopping"); system(TPROXY_IPTABLS_CLEAN); } + ~cgproxyd() { stop(); } }; @@ -130,7 +129,16 @@ cgproxyd *cgproxyd::instance = NULL; } // namespace CGPROXY +void processArgs(const int argc, char *argv[]) { + 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; } + } +} + int main(int argc, char *argv[]) { + processArgs(argc, argv); CGPROXY::cgproxyd d; - return d.start(argc, argv); + return d.start(); } \ No newline at end of file diff --git a/cgroup_attach.hpp b/src/cgroup_attach.hpp similarity index 97% rename from cgroup_attach.hpp rename to src/cgroup_attach.hpp index 7b52bb5..b04e7c1 100644 --- a/cgroup_attach.hpp +++ b/src/cgroup_attach.hpp @@ -34,9 +34,9 @@ bool validate(string pid, string cgroup) { 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); + int count = fscanf(fp, "%s", cgroup2_mount_point); fclose(fp); - if (count = 0) { + if (count == 0) { error("cgroup2 not supported"); status = -1; return NULL; diff --git a/common.hpp b/src/common.hpp similarity index 90% rename from common.hpp rename to src/common.hpp index f891b88..b471f6c 100644 --- a/common.hpp +++ b/src/common.hpp @@ -49,15 +49,6 @@ static bool print_help = false; #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 string to_str(T... args) { stringstream ss; ss.clear(); diff --git a/config.hpp b/src/config.hpp similarity index 100% rename from config.hpp rename to src/config.hpp diff --git a/socket_client.hpp b/src/socket_client.hpp similarity index 100% rename from socket_client.hpp rename to src/socket_client.hpp diff --git a/socket_server.hpp b/src/socket_server.hpp similarity index 100% rename from socket_server.hpp rename to src/socket_server.hpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..7bd3acc --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,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) +target_link_libraries(client_test nlohmann_json::nlohmann_json) \ No newline at end of file diff --git a/test/socket_client_test.cpp b/test/socket_client_test.cpp new file mode 100644 index 0000000..be28277 --- /dev/null +++ b/test/socket_client_test.cpp @@ -0,0 +1,48 @@ +#include "socket_client.hpp" +#include + +using namespace std; +using json = nlohmann::json; +using namespace CGPROXY; + +void test_json() { + json j; + j["type"] = MSG_TYPE_JSON; + j["data"]["cgroup_proxy"] = "/"; + j["data"]["enable_dns"] = false; + int status; + 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() { + json j; + j["type"] = MSG_TYPE_CONFIG_PATH; + j["data"] = "/etc/cgproxy.conf"; + int status; + SOCKET::send(j.dump(), status); +} + +void test_pid() { + json j; + j["type"] = MSG_TYPE_PROXY_PID; + j["data"] = "9999"; + int status; + SOCKET::send(j.dump(), status); +} + +int main() { + test_json_array(); + test_file(); + test_json(); + test_pid(); + return 0; +} \ No newline at end of file diff --git a/test/test.cpp b/test/test.cpp new file mode 100644 index 0000000..db79503 --- /dev/null +++ b/test/test.cpp @@ -0,0 +1,18 @@ +// #include "common.h" +#include "config.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +using namespace CGPROXY::CONFIG; + +int main() { + Config c; + c.saveToFile("./config.json"); + return 0; +} \ No newline at end of file diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 0000000..8e369b9 --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,4 @@ +include_directories(${PROJECT_SOURCE_DIR}) +include_directories(${PROJECT_SOURCE_DIR}/src) +add_executable(cgattach cgattach.cpp) +install(TARGETS cgattach DESTINATION /usr/bin PERMISSIONS ${basic_permission}) \ No newline at end of file diff --git a/cgattach.cpp b/tools/cgattach.cpp similarity index 68% rename from cgattach.cpp rename to tools/cgattach.cpp index d89ab07..7a9f970 100644 --- a/cgattach.cpp +++ b/tools/cgattach.cpp @@ -1,4 +1,6 @@ #include "cgroup_attach.hpp" +#include "common.hpp" +#include using namespace std; void print_usage() { fprintf(stdout, "usage: cgattach \n"); } @@ -19,5 +21,10 @@ int main(int argc, char *argv[]) { string pid = string(argv[1]); string cgroup_target = string(argv[2]); - CGPROXY::CGROUP::attach(pid, cgroup_target); + if (validPid(pid)&&validCgroup(cgroup_target)){ + CGPROXY::CGROUP::attach(pid, cgroup_target); + }else{ + error("param not valid"); + exit(EXIT_FAILURE); + } }