add execsnoop

This commit is contained in:
springzfx
2020-05-23 05:02:05 +08:00
parent 92abcb1851
commit 792a156647
9 changed files with 187 additions and 16 deletions

View File

@@ -23,7 +23,8 @@ 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/)
install(FILES cgroup-tproxy.sh DESTINATION /usr/share/cgproxy/scripts/)
install(FILES cgroup-tproxy.sh DESTINATION /usr/share/cgproxy/scripts/ PERMISSIONS ${basic_permission})
install(FILES execsnoop.py DESTINATION /usr/share/cgproxy/scripts/ PERMISSIONS ${basic_permission})
install(FILES readme.md DESTINATION /usr/share/doc/cgproxy/)
# man pages

View File

@@ -4,7 +4,7 @@ After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/cgproxyd
ExecStart=/usr/bin/cgproxyd --execsnoop
[Install]
WantedBy=multi-user.target

View File

@@ -1,11 +1,13 @@
{
"port": 12345,
"program_noproxy": ["/usr/lib/v2ray/v2ray", "/usr/bin/qv2ray"],
"program_proxy": [],
"cgroup_noproxy": ["/system.slice/v2ray.service"],
"cgroup_proxy": [],
"enable_dns": true,
"enable_gateway": false,
"enable_dns": true,
"enable_ipv4": true,
"enable_ipv6": true,
"enable_tcp": true,
"enable_udp": true,
"port": 12345
"enable_udp": true
}

133
execsnoop.py Normal file
View File

@@ -0,0 +1,133 @@
#!/usr/bin/python
# This won't catch all new processes: an application may fork() but not exec().
from __future__ import print_function
from bcc import BPF
from bcc.utils import ArgString, printb
import bcc.utils as utils
import argparse
import re
import time
from collections import defaultdict
import os
import sys
import signal
import time
import shutil
# define BPF program
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <linux/sched.h>
#include <linux/fs.h>
#define ARGSIZE 256
struct data_t {
u32 pid; // PID as in the userspace term (i.e. task->tgid in kernel)
char path[ARGSIZE];
int retval;
};
BPF_PERF_OUTPUT(events);
int syscall__execve(struct pt_regs *ctx,
const char __user *filename,
const char __user *const __user *__argv,
const char __user *const __user *__envp)
{
// create data here and pass to submit_arg to save stack space (#555)
struct data_t data = {};
struct task_struct *task;
data.pid = bpf_get_current_pid_tgid() >> 32;
bpf_probe_read(data.path, sizeof(data.path), filename);
events.perf_submit(ctx, &data, sizeof(struct data_t));
return 0;
}
"""
def getRealPath(exec_path):
path=exec_path.strip()
if not path.startswith("/"):
path=shutil.which(path)
if path:
path=os.path.realpath(path)
if path and os.path.isfile(path):
return path
print("'{0}' can not be find".format(exec_path))
def getParam():
global exec_path_proxy, exec_path_noproxy
exec_path_str=os.getenv('program_proxy')
if exec_path_str:
paths=exec_path_str.split(':')
exec_path_proxy=[getRealPath(x) for x in paths]
print("program with proxy:", end =" ")
print(*exec_path_proxy,flush=True)
exec_path_str=os.getenv('program_noproxy')
if exec_path_str:
paths=exec_path_str.split(':')
exec_path_noproxy=[getRealPath(x) for x in paths]
print("program without proxy:", end =" ")
print(*exec_path_noproxy, flush=True)
def exit_gracefully(signum, frame):
print("execsnoop receive signal: {0}".format(signum),flush=True)
sys.exit(0)
def attach(pid, path, proxy=True):
if proxy:
print("proxy: %-6d %s" % (pid, path),flush=True)
os.system("/usr/bin/cgproxy --pid {0}".format(pid))
else:
print("noproxy: %-6d %s" % (pid, path),flush=True)
os.system("/usr/bin/cgproxy --pid {0} --noproxy".format(pid))
def processAlreadyRunning():
from subprocess import check_output
def get_pid(name):
return map(int,check_output(["pidof",name]).split())
global exec_path_proxy, exec_path_noproxy
for path in exec_path_proxy:
for pid in get_pid(path):
attach(pid,path,True)
for path in exec_path_noproxy:
for pid in get_pid(path):
attach(pid,path,False)
signal.signal(signal.SIGINT, exit_gracefully)
signal.signal(signal.SIGHUP, exit_gracefully)
signal.signal(signal.SIGTERM, exit_gracefully)
show_ignore=False
exec_path_proxy=[]
exec_path_noproxy=[]
getParam()
processAlreadyRunning()
# initialize BPF
b = BPF(text=bpf_text)
execve_fnname = b.get_syscall_fnname("execve")
b.attach_kprobe(event=execve_fnname, fn_name="syscall__execve")
# process event
def print_event(cpu, data, size):
event = b["events"].event(data)
pid=event.pid
exec_path=event.path.decode('utf-8')
if (exec_path in exec_path_noproxy):
attach(pid, exec_path, False)
elif (exec_path in exec_path_proxy):
attach(pid, exec_path, True)
elif (show_ignore):
print("ignore: %-6d %s" % (pid, exec_path),flush=True)
# loop with callback to print_event
b["events"].open_perf_buffer(print_event)
while 1:
b.perf_buffer_poll()

View File

@@ -11,7 +11,8 @@ using namespace CGPROXY::CONFIG;
namespace CGPROXY::CGPROXY {
bool print_help = false, proxy = true;
bool attach_pid=false; string arg_pid;
bool attach_pid = false;
string arg_pid;
inline void print_usage() {
if (proxy) {
cout << "Run program with proxy" << endl;
@@ -29,8 +30,8 @@ bool processArgs(const int argc, char *argv[], int &shift) {
if (strcmp(argv[i], "--pid") == 0) {
attach_pid = true;
i++;
if (i==argc) return false;
arg_pid=argv[i];
if (i == argc) return false;
arg_pid = argv[i];
if (!validPid(arg_pid)) return false;
continue;
}
@@ -52,7 +53,7 @@ void send_pid(const pid_t pid, bool proxy, int &status) {
int main(int argc, char *argv[]) {
int shift = -1;
if (!processArgs(argc, argv, shift)){
if (!processArgs(argc, argv, shift)) {
error("parameter error");
exit(EXIT_FAILURE);
}
@@ -68,10 +69,10 @@ int main(int argc, char *argv[]) {
}
int status = -1;
send_pid(attach_pid?stoi(arg_pid):getpid(), proxy, status);
send_pid(attach_pid ? stoi(arg_pid) : getpid(), proxy, status);
if (status != 0) {
error("attach process failed");
if (status==1) error("maybe cgproxy.service not running");
if (status == 1) error("maybe cgproxy.service not running");
exit(EXIT_FAILURE);
}

View File

@@ -8,6 +8,7 @@
#include <csignal>
#include <fstream>
#include <nlohmann/json.hpp>
#include <sched.h>
#include <sys/file.h>
#include <unistd.h>
@@ -19,10 +20,14 @@ using namespace ::CGPROXY::CGROUP;
namespace CGPROXY::CGPROXYD {
bool print_help = false;
bool enable_execsnoop = false;
class cgproxyd {
thread_arg arg_t;
Config config;
pthread_t socket_thread_id = -1;
pid_t exec_snoop_pid = -1;
static cgproxyd *instance;
static int handle_msg_static(char *msg) {
@@ -40,7 +45,7 @@ class cgproxyd {
} else {
instance->stop();
}
exit(signum);
exit(0);
}
// single process instance
@@ -113,6 +118,22 @@ class cgproxyd {
return thread_id;
}
void startExecSnoopProc() {
if (exec_snoop_pid != -1){
kill(exec_snoop_pid, SIGINT);
exec_snoop_pid=-1;
}
pid_t pid = fork();
if (pid == 0) {
execl(BPF_EXEC_SNOOP_START, (char *) NULL);
exit(0);
} else if (pid<0){
error("fork precess failed");
}else {
exec_snoop_pid = pid;
}
}
void assignStaticInstance() { instance = this; }
public:
@@ -134,6 +155,7 @@ public:
system(TPROXY_IPTABLS_CLEAN);
c->toEnv();
system(TPROXY_IPTABLS_START);
if (enable_execsnoop) startExecSnoopProc();
// no need to track running status
return 0;
}
@@ -141,6 +163,7 @@ public:
void stop() {
debug("stopping");
system(TPROXY_IPTABLS_CLEAN);
// if (exec_snoop_pid != -1) kill(exec_snoop_pid, SIGINT);
unlock();
}
@@ -149,8 +172,6 @@ public:
cgproxyd *cgproxyd::instance = NULL;
bool print_help = false;
void print_usage() {
cout << "Start a daemon with unix socket to accept control" << endl;
cout << "Usage: cgproxyd [--help] [--debug]" << endl;
@@ -161,6 +182,7 @@ 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 (strcmp(argv[i], "--execsnoop") == 0) { enable_execsnoop = true; }
if (argv[i][0] != '-') { break; }
}
}

View File

@@ -7,8 +7,9 @@
#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"
#define TPROXY_IPTABLS_START "/usr/share/cgproxy/scripts/cgroup-tproxy.sh"
#define TPROXY_IPTABLS_CLEAN "/usr/share/cgproxy/scripts/cgroup-tproxy.sh stop"
#define BPF_EXEC_SNOOP_START "/usr/share/cgproxy/scripts/execsnoop.py"
#define PID_LOCK_FILE "/var/run/cgproxyd.pid"
#define SOCKET_PATH "/tmp/cgproxy_unix_socket"

View File

@@ -21,6 +21,8 @@ namespace CGPROXY::CONFIG {
void Config::toEnv() {
mergeReserved();
setenv("program_proxy", join2str(program_proxy, ':').c_str(), 1);
setenv("program_noproxy", join2str(program_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);
@@ -43,6 +45,8 @@ int Config::saveToFile(const string f) {
string Config::toJsonStr() {
json j;
add2json(program_proxy);
add2json(program_noproxy);
add2json(cgroup_proxy);
add2json(cgroup_noproxy);
add2json(enable_gateway);
@@ -74,6 +78,8 @@ int Config::loadFromJsonStr(const string js) {
return PARAM_ERROR;
}
json j = json::parse(js);
tryassign(program_proxy);
tryassign(program_noproxy);
tryassign(cgroup_proxy);
tryassign(cgroup_noproxy);
tryassign(enable_gateway);
@@ -96,6 +102,7 @@ bool Config::validateJsonStr(const string js) {
bool status = true;
const set<string> boolset = {"enable_gateway", "enable_dns", "enable_tcp",
"enable_udp", "enable_ipv4", "enable_ipv6"};
const set<string> allowset = {"program_proxy", "program_noproxy"};
for (auto &[key, value] : j.items()) {
if (key == "cgroup_proxy" || key == "cgroup_noproxy") {
if (value.is_string() && !validCgroup((string)value)) status = false;
@@ -106,6 +113,8 @@ bool Config::validateJsonStr(const string js) {
if (!validPort(value)) status = false;
} else if (boolset.find(key) != boolset.end()) {
if (!value.is_boolean()) status = false;
} else if (allowset.find(key) != allowset.end()) {
} else {
error("unknown key: %s", key.c_str());
return false;

View File

@@ -13,6 +13,8 @@ public:
const string cgroup_proxy_preserved = CGROUP_PROXY_PRESVERED;
const string cgroup_noproxy_preserved = CGROUP_NOPROXY_PRESVERED;
vector<string> program_proxy;
vector<string> program_noproxy;
vector<string> cgroup_proxy;
vector<string> cgroup_noproxy;
bool enable_gateway = false;