mirror of
https://github.com/springzfx/cgproxy.git
synced 2026-01-07 13:07:56 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86fe42eccb | ||
|
|
f88748bd28 | ||
|
|
096af74237 | ||
|
|
fd01861c62 | ||
|
|
aaa628a76b | ||
|
|
5902a64926 | ||
|
|
372e4be6d9 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
build*
|
||||
.cache
|
||||
.directory
|
||||
.clangd
|
||||
v2ray_config/proxy
|
||||
|
||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -2,6 +2,8 @@
|
||||
"cmake.configureOnOpen": true,
|
||||
"cmake.configureArgs": [
|
||||
"-Dbuild_static=OFF",
|
||||
"-Dbuild_execsnoop_dl=OFF"
|
||||
"-Dbuild_execsnoop_dl=ON",
|
||||
"-Dbuild_tools=ON",
|
||||
"-Dbuild_test=ON"
|
||||
]
|
||||
}
|
||||
@@ -2,11 +2,11 @@ cmake_minimum_required(VERSION 3.14)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
project(cgproxy VERSION 0.18)
|
||||
project(cgproxy VERSION 0.20)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
add_compile_options(-Wall -Wextra -Wpedantic -Wno-unused-result -Wno-unused-parameter -Wl,--no-undefined)
|
||||
add_compile_options(-Wall -Wextra -Wpedantic -Wno-unused-result -Wno-unused-parameter -Wno-overlength-strings)
|
||||
|
||||
# for clangd
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
@@ -18,7 +18,7 @@ option(build_tools OFF)
|
||||
option(build_test "for develop" OFF)
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(execsnoop-kernel)
|
||||
add_subdirectory(execsnoop-libbpf)
|
||||
add_subdirectory(pack)
|
||||
if (build_tools)
|
||||
add_subdirectory(tools)
|
||||
@@ -32,8 +32,8 @@ configure_file(cgproxyd.cmake cgproxyd)
|
||||
configure_file(cgproxy.service.cmake cgproxy.service)
|
||||
|
||||
# instal scripts and other things
|
||||
install(PROGRAMS ${CMAKE_BINARY_DIR}/cgproxyd TYPE BIN)
|
||||
install(PROGRAMS ${CMAKE_BINARY_DIR}/cgnoproxy TYPE BIN)
|
||||
install(PROGRAMS ${CMAKE_BINARY_DIR}/cgproxyd DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
|
||||
install(PROGRAMS ${CMAKE_BINARY_DIR}/cgnoproxy DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
|
||||
install(PROGRAMS cgroup-tproxy.sh DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/cgproxy/scripts)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/cgproxy.service DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/systemd/system)
|
||||
install(FILES config.json DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/cgproxy)
|
||||
@@ -46,4 +46,4 @@ add_custom_command(OUTPUT ${man_gz}
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/man
|
||||
)
|
||||
add_custom_target(man ALL DEPENDS ${man_gz})
|
||||
install(FILES ${man_gz} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1/)
|
||||
install(FILES ${man_gz} DESTINATION ${CMAKE_INSTALL_FULL_MANDIR}/man1/)
|
||||
|
||||
21
execsnoop-libbpf/CMakeLists.txt
Normal file
21
execsnoop-libbpf/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
find_library(LIBBPF bpf REQUIRED)
|
||||
|
||||
# generate execsnoop.skel.h
|
||||
if (EXISTS /sys/kernel/btf/vmlinux)
|
||||
add_custom_command(OUTPUT execsnoop.skel.h
|
||||
COMMAND bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
|
||||
COMMAND clang -O2 -g -target bpf -c execsnoop.bpf.c -o execsnoop.bpf.o
|
||||
COMMAND bpftool gen skeleton execsnoop.bpf.o > execsnoop.skel.h
|
||||
DEPENDS execsnoop.bpf.c
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
if (build_execsnoop_dl)
|
||||
add_library(execsnoop MODULE execsnoop_share.cpp execsnoop.skel.h)
|
||||
target_link_libraries(execsnoop PRIVATE ${LIBBPF})
|
||||
install(TARGETS execsnoop DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cgproxy/)
|
||||
else()
|
||||
add_library(execsnoop execsnoop_share.cpp execsnoop.skel.h)
|
||||
target_link_libraries(execsnoop PRIVATE ${LIBBPF})
|
||||
endif()
|
||||
92
execsnoop-libbpf/execsnoop.bpf.c
Normal file
92
execsnoop-libbpf/execsnoop.bpf.c
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "vmlinux.h"
|
||||
#include <linux/version.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
#define TASK_COMM_LEN 16
|
||||
struct event {
|
||||
char comm[TASK_COMM_LEN];
|
||||
pid_t pid;
|
||||
pid_t tgid;
|
||||
pid_t ppid;
|
||||
uid_t uid;
|
||||
};
|
||||
|
||||
/* /sys/kernel/debug/tracing/events/syscalls/sys_enter_execve/format */
|
||||
struct syscalls_enter_execve_args {
|
||||
__u64 unused;
|
||||
int syscall_nr;
|
||||
const char filename_ptr;
|
||||
const char *const * argv;
|
||||
const char *const * envp;
|
||||
};
|
||||
|
||||
/* /sys/kernel/debug/tracing/events/syscalls/sys_exit_execve/format */
|
||||
struct syscalls_exit_execve_args {
|
||||
__u64 unused;
|
||||
int syscall_nr;
|
||||
long ret;
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 10240);
|
||||
__type(key, pid_t);
|
||||
__type(value, struct event);
|
||||
} records SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(max_entries, 128);
|
||||
__type(key, u32);
|
||||
__type(value, u32);
|
||||
} perf_events SEC(".maps");
|
||||
|
||||
SEC("tracepoint/syscalls/sys_enter_execve")
|
||||
int syscall_enter_execve(struct syscalls_enter_execve_args *ctx){
|
||||
pid_t pid, tgid; uid_t uid;
|
||||
struct event *event;
|
||||
struct task_struct *task, *task_p;
|
||||
|
||||
u64 id = bpf_get_current_pid_tgid();
|
||||
pid = (pid_t)id;
|
||||
tgid = id >> 32;
|
||||
uid = (u32)bpf_get_current_uid_gid();
|
||||
|
||||
struct event empty_event={};
|
||||
if (bpf_map_update_elem(&records, &pid, &empty_event, BPF_NOEXIST)!=0) return 0;
|
||||
event = bpf_map_lookup_elem(&records, &pid);
|
||||
if (!event) return 0;
|
||||
|
||||
event->pid = pid;
|
||||
event->tgid = tgid;
|
||||
event->uid = uid;
|
||||
|
||||
/* ppid is not reliable here, normal in arch, but become 0 in ubuntu 20.04 */
|
||||
task = (struct task_struct*)bpf_get_current_task();
|
||||
bpf_probe_read(&task_p, sizeof(struct task_struct*),&task->real_parent);
|
||||
bpf_probe_read(&event->ppid,sizeof(pid_t),&task_p->tgid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tracepoint/syscalls/sys_exit_execve")
|
||||
int syscall_exit_execve(struct syscalls_exit_execve_args *ctx){
|
||||
pid_t pid;
|
||||
struct event *event;
|
||||
|
||||
pid = (pid_t)bpf_get_current_pid_tgid();
|
||||
event = bpf_map_lookup_elem(&records,&pid);
|
||||
if (!event) return 0;
|
||||
if (ctx->ret < 0) goto cleanup;
|
||||
|
||||
/* get comm */
|
||||
bpf_get_current_comm(&event->comm,sizeof(event->comm));
|
||||
bpf_perf_event_output(ctx, &perf_events, BPF_F_CURRENT_CPU, event, sizeof(struct event));
|
||||
cleanup:
|
||||
bpf_map_delete_elem(&records, &pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
u32 _version SEC("version") = LINUX_VERSION_CODE;
|
||||
71
execsnoop-libbpf/execsnoop.c
Normal file
71
execsnoop-libbpf/execsnoop.c
Normal file
@@ -0,0 +1,71 @@
|
||||
#include <signal.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include <sys/resource.h>
|
||||
#include "execsnoop.skel.h"
|
||||
|
||||
#define TASK_COMM_LEN 16
|
||||
struct event {
|
||||
char comm[TASK_COMM_LEN];
|
||||
pid_t pid;
|
||||
pid_t tgid;
|
||||
pid_t ppid;
|
||||
uid_t uid;
|
||||
};
|
||||
|
||||
#define PERF_BUFFER_PAGES 64
|
||||
|
||||
static void handle_event(void *ctx, int cpu, void *data, __u32 size) {
|
||||
auto e = static_cast<event*>(data);
|
||||
printf("comm: %s, pid: %d, tgid: %d, ppid: %d, uid: %d\n",e->comm,e->pid,e->tgid,e->ppid,e->uid);
|
||||
}
|
||||
|
||||
void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt) {
|
||||
fprintf(stderr, "Lost %llu events on CPU #%d!\n", lost_cnt, cpu);
|
||||
}
|
||||
|
||||
int bump_memlock_rlimit(void) {
|
||||
struct rlimit rlim_new = { RLIM_INFINITY, RLIM_INFINITY };
|
||||
return setrlimit(RLIMIT_MEMLOCK, &rlim_new);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
struct perf_buffer_opts pb_opts = {};
|
||||
struct perf_buffer *pb;
|
||||
int err;
|
||||
|
||||
err = bump_memlock_rlimit();
|
||||
if (err) {
|
||||
fprintf(stderr, "failed to increase rlimit: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct execsnoop_bpf *obj=execsnoop_bpf__open_and_load();
|
||||
if (!obj) {
|
||||
fprintf(stderr, "failed to open and/or load BPF object\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = execsnoop_bpf__attach(obj);
|
||||
if (err) {
|
||||
fprintf(stderr, "failed to attach BPF programs\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LIBBPF_MAJOR_VERSION == 0
|
||||
pb_opts.sample_cb = handle_event;
|
||||
pb_opts.lost_cb = handle_lost_events;
|
||||
pb = perf_buffer__new(bpf_map__fd(obj->maps.perf_events), PERF_BUFFER_PAGES, &pb_opts);
|
||||
#else
|
||||
pb_opts.sz = sizeof(pb_opts);
|
||||
pb = perf_buffer__new(bpf_map__fd(obj->maps.perf_events), PERF_BUFFER_PAGES, handle_event, handle_lost_events, nullptr, &pb_opts);
|
||||
#endif
|
||||
err = libbpf_get_error(pb);
|
||||
if (err) {
|
||||
printf("failed to setup perf_buffer: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while ((err = perf_buffer__poll(pb, -1)) >= 0) {}
|
||||
kill(0, SIGINT);
|
||||
return err;
|
||||
}
|
||||
31698
execsnoop-libbpf/execsnoop.skel.h
Normal file
31698
execsnoop-libbpf/execsnoop.skel.h
Normal file
File diff suppressed because it is too large
Load Diff
96
execsnoop-libbpf/execsnoop_share.cpp
Normal file
96
execsnoop-libbpf/execsnoop_share.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "execsnoop_share.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include <sys/resource.h>
|
||||
#include "execsnoop.skel.h"
|
||||
|
||||
namespace CGPROXY::EXECSNOOP {
|
||||
|
||||
#define PERF_BUFFER_PAGES 64
|
||||
#define TASK_COMM_LEN 16
|
||||
struct event {
|
||||
char comm[TASK_COMM_LEN];
|
||||
pid_t pid;
|
||||
pid_t tgid;
|
||||
pid_t ppid;
|
||||
uid_t uid;
|
||||
};
|
||||
|
||||
function<int(int)> callback = NULL;
|
||||
promise<void> status;
|
||||
|
||||
static void handle_event(void *ctx, int cpu, void *data, __u32 size) {
|
||||
auto e = static_cast<event*>(data);
|
||||
if (callback) callback(e->pid);
|
||||
}
|
||||
|
||||
void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt) {
|
||||
fprintf(stderr, "Lost %llu events on CPU #%d!\n", lost_cnt, cpu);
|
||||
}
|
||||
|
||||
int bump_memlock_rlimit(void) {
|
||||
struct rlimit rlim_new = { RLIM_INFINITY, RLIM_INFINITY };
|
||||
return setrlimit(RLIMIT_MEMLOCK, &rlim_new);
|
||||
}
|
||||
|
||||
int execsnoop() {
|
||||
struct perf_buffer_opts pb_opts = {};
|
||||
struct perf_buffer *pb;
|
||||
int err;
|
||||
bool notified=false;
|
||||
|
||||
err = bump_memlock_rlimit();
|
||||
if (err) {
|
||||
fprintf(stderr, "failed to increase rlimit: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct execsnoop_bpf *obj=execsnoop_bpf__open_and_load();
|
||||
if (!obj) {
|
||||
fprintf(stderr, "failed to open and/or load BPF object\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = execsnoop_bpf__attach(obj);
|
||||
if (err) {
|
||||
fprintf(stderr, "failed to attach BPF programs\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
main_loop:
|
||||
#if LIBBPF_MAJOR_VERSION == 0
|
||||
pb_opts.sample_cb = handle_event;
|
||||
pb_opts.lost_cb = handle_lost_events;
|
||||
pb = perf_buffer__new(bpf_map__fd(obj->maps.perf_events), PERF_BUFFER_PAGES, &pb_opts);
|
||||
#else
|
||||
pb_opts.sz = sizeof(pb_opts);
|
||||
pb = perf_buffer__new(bpf_map__fd(obj->maps.perf_events), PERF_BUFFER_PAGES, handle_event, handle_lost_events, nullptr, &pb_opts);
|
||||
#endif
|
||||
err = libbpf_get_error(pb);
|
||||
if (err) {
|
||||
printf("failed to setup perf_buffer: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// notify
|
||||
if (!notified) {status.set_value(); notified=true;}
|
||||
|
||||
while ((err = perf_buffer__poll(pb, -1)) >= 0) {}
|
||||
perf_buffer__free(pb);
|
||||
/* handle Interrupted system call when sleep */
|
||||
if (err == -EINTR) goto main_loop;
|
||||
|
||||
perror("perf_buffer__poll");
|
||||
kill(0, SIGINT);
|
||||
return err;
|
||||
}
|
||||
|
||||
void startThread(function<int(int)> c, promise<void> _status) {
|
||||
status = move(_status);
|
||||
callback = c;
|
||||
execsnoop();
|
||||
}
|
||||
|
||||
}
|
||||
20
execsnoop-libbpf/execsnoop_share.h
Normal file
20
execsnoop-libbpf/execsnoop_share.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef EXECSNOOP_SHARE_HPP
|
||||
#define EXECSNOOP_SHARE_HPP 1
|
||||
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
namespace CGPROXY::EXECSNOOP {
|
||||
|
||||
extern "C" void startThread(function<int(int)> c, promise<void> _status);
|
||||
|
||||
#ifdef BUIlD_EXECSNOOP_DL
|
||||
// only for dlsym()
|
||||
using startThread_t=decltype(startThread);
|
||||
startThread_t *_startThread;
|
||||
#endif
|
||||
|
||||
} // namespace CGPROXY::EXECSNOOP
|
||||
#endif
|
||||
18
execsnoop-libbpf/readme.md
Normal file
18
execsnoop-libbpf/readme.md
Normal file
@@ -0,0 +1,18 @@
|
||||
generate `vmlinux.h`
|
||||
|
||||
```shell
|
||||
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
|
||||
```
|
||||
|
||||
compiled into BPF ELF file
|
||||
|
||||
```shell
|
||||
clang -O2 -g -target bpf -c execsnoop.bpf.c -o execsnoop.bpf.o
|
||||
```
|
||||
|
||||
generate BPF skeleton .skel.h
|
||||
|
||||
```shell
|
||||
bpftool gen skeleton execsnoop.bpf.o > execsnoop.skel.h
|
||||
```
|
||||
|
||||
@@ -65,7 +65,7 @@ Main feature:
|
||||
|
||||
### build
|
||||
|
||||
- before build, install depencies: clang(if to build bpf obj from scratch), nlohmann-json, libbpf
|
||||
- before build, install depencies: clang, nlohmann-json, libbpf, bpf(bpftool)
|
||||
- then cmake standard build
|
||||
|
||||
```bash
|
||||
@@ -217,7 +217,7 @@ sudo systemctl restart cgproxy.service
|
||||
sudo setcap "cap_net_admin,cap_net_bind_service=ep" /usr/lib/v2ray/v2ray
|
||||
```
|
||||
|
||||
- Why not outbound mark solution, because in v2ray [when `"localhost"` is used, out-going DNS traffic is not controlled by V2Ray](https://www.v2fly.org/en/configuration/dns.html), so no mark at all, that's pity.
|
||||
- Why not outbound mark solution, because in v2ray [when `"localhost"` is used, out-going DNS traffic is not controlled by V2Ray](https://www.v2fly.org/config/dns.html#dnsobject), so no mark at all, that's pity.
|
||||
|
||||
## TIPS
|
||||
|
||||
@@ -227,7 +227,7 @@ sudo systemctl restart cgproxy.service
|
||||
- Offer you qv2ray config example
|
||||
|
||||
|
||||

|
||||

|
||||
|
||||
## Licences
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
include_directories(${PROJECT_SOURCE_DIR})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/execsnoop-kernel/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/execsnoop-libbpf/)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
configure_file(common.h.cmake common.h)
|
||||
configure_file(common.cmake.h ${CMAKE_CURRENT_SOURCE_DIR}/common.h)
|
||||
|
||||
if (build_execsnoop_dl)
|
||||
add_definitions(-DBUIlD_EXECSNOOP_DL)
|
||||
@@ -17,7 +17,7 @@ endif()
|
||||
add_executable(main main.cpp common.cpp config.cpp cgroup_attach.cpp socket_client.cpp socket_server.cpp)
|
||||
target_link_libraries(main PRIVATE nlohmann_json::nlohmann_json ${DL_LIB} ${EXECSNOOP_LIB})
|
||||
set_target_properties(main PROPERTIES OUTPUT_NAME cgproxy)
|
||||
install(TARGETS main RUNTIME)
|
||||
install(TARGETS main DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
|
||||
|
||||
if (build_static)
|
||||
target_link_libraries(main PRIVATE -static -Wl,--whole-archive -lpthread -Wl,--no-whole-archive)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
## Usage
|
||||
- Fill `06_outbounds_myproxy.json` with your vmess proxy config with tag `outBound_PROXY`.
|
||||
- Fill `06_outbounds_myproxy.json` with your VMess proxy config with tag `outBound_PROXY`.
|
||||
- Start with `sudo v2ray -confdir .`
|
||||
|
||||
## Reference
|
||||
|
||||
- [v2ray multi-file config](https://www.v2fly.org/chapter_02/multiple_config.html)
|
||||
- [v2ray multi-file config](https://www.v2fly.org/config/multiple_config.html)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user