fix: 修复socket路径不一致,提供测试

This commit is contained in:
Pan Qiancheng 2025-12-07 20:37:23 +08:00
parent 8bcfa9e7cc
commit 21027a79be
16 changed files with 132 additions and 253 deletions

View File

@ -8,6 +8,7 @@ HOOK_NAME = hook_write.so
BUILD_DIR = build BUILD_DIR = build
SRC_DIR = src SRC_DIR = src
TESTS_DIR = tests
SRC = $(wildcard $(SRC_DIR)/*.c) SRC = $(wildcard $(SRC_DIR)/*.c)
SRC := $(filter-out $(SRC_DIR)/hook_write.c, $(SRC)) # 排除 hook_write.c SRC := $(filter-out $(SRC_DIR)/hook_write.c, $(SRC)) # 排除 hook_write.c
@ -19,6 +20,11 @@ HOOK_SRC = $(SRC_DIR)/hook_write.c
HOOK_OBJ = $(BUILD_DIR)/hook_write.o HOOK_OBJ = $(BUILD_DIR)/hook_write.o
HOOK_TARGET = $(BUILD_DIR)/$(HOOK_NAME) HOOK_TARGET = $(BUILD_DIR)/$(HOOK_NAME)
# 测试客户端
TEST_CLIENT = $(BUILD_DIR)/test_client
TEST_CLIENT_SRC = $(TESTS_DIR)/test_client.c
TEST_CLIENT_DEPS = $(BUILD_DIR)/client.o $(BUILD_DIR)/debug.o
# 如果需要开启 debug只需执行 make DEBUG=1 # 如果需要开启 debug只需执行 make DEBUG=1
ifeq ($(DEBUG),1) ifeq ($(DEBUG),1)
CFLAGS += -DDEBUG -g CFLAGS += -DDEBUG -g
@ -34,10 +40,12 @@ ifeq ($(NO_CONFIG_CHECK),1)
CFLAGS += -DNO_CONFIG_CHECK CFLAGS += -DNO_CONFIG_CHECK
endif endif
.PHONY: all clean debug hook rebuild pre_build .PHONY: all clean debug hook rebuild pre_build test_client
all: pre_build $(TARGET) $(HOOK_TARGET) all: pre_build $(TARGET) $(HOOK_TARGET)
test_client: pre_build $(TEST_CLIENT)
pre_build: pre_build:
ifeq ($(DEBUG),1) ifeq ($(DEBUG),1)
@echo "Building with debug flags..." @echo "Building with debug flags..."
@ -65,6 +73,10 @@ $(HOOK_OBJ): $(HOOK_SRC)
@mkdir -p $(BUILD_DIR) @mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) -Wno-error=unused-result -c $< -o $@ $(CC) $(CFLAGS) -Wno-error=unused-result -c $< -o $@
$(TEST_CLIENT): $(TEST_CLIENT_SRC) $(TEST_CLIENT_DEPS)
@mkdir -p $(BUILD_DIR)
$(CC) -Wall -Wextra -o $@ $(TEST_CLIENT_SRC) $(TEST_CLIENT_DEPS)
clean: clean:
rm -rf $(BUILD_DIR) rm -rf $(BUILD_DIR)

View File

@ -12,7 +12,7 @@
#include <linux/limits.h> // for PATH_MAX #include <linux/limits.h> // for PATH_MAX
#include <errno.h> #include <errno.h>
#define SOCKET_PATH "/etc/exec_hook/exec.sock" #define SOCKET_PATH "/var/run/bash-smart.sock"
#define MAX_BUF_SIZE 4096 #define MAX_BUF_SIZE 4096
// 函数声明 // 函数声明

6
test_log.stderr.log Normal file
View File

@ -0,0 +1,6 @@
pip is not installed. Please install pip to proceed.
Installing required Python packages...
Successfully installed click-8.1.3
Finished installing Python packages.
This is a test error log file for testing the client functionality.

43
tests/README.md Normal file
View File

@ -0,0 +1,43 @@
# 客户端测试程序
## 编译
```bash
make test_client
```
## 运行测试
确保 Go 服务端正在运行,然后执行:
```bash
./build/test_client /tmp/test_error.log
```
## 测试说明
测试程序会:
1. 连接到 Unix socket (`/etc/exec_hook/exec.sock`)
2. 发送模拟的执行参数(命令、参数、环境变量、日志路径)
3. 接收并显示服务端返回的所有消息
4. 等待 socket 关闭后退出
## 创建测试日志文件
如果需要自定义测试日志内容:
```bash
cat > /tmp/test_error.log << 'EOF'
This is a test error log file.
Error: command not found
Usage: test_script.py [OPTIONS]
Exit code: 127
EOF
```
## 预期行为
- 成功情况: 显示服务端返回的所有消息,最后输出 "✓ 测试成功"
- 失败情况: 输出错误信息,返回非零退出码

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,18 +0,0 @@
CC = gcc
CFLAGS = -Wall -g
all: client-tests
client-tests: client-tests.o client.o
$(CC) $(CFLAGS) -o client-tests client-tests.o client.o
client-tests.o: client-tests.c client.h
$(CC) $(CFLAGS) -c client-tests.c
client.o: client.c client.h
$(CC) $(CFLAGS) -c client.c
clean:
rm -f client-tests *.o
.PHONY: all clean

Binary file not shown.

View File

@ -1,30 +0,0 @@
#include "client.h"
int main() {
// 测试参数
const char *filename = "/usr/bin/ls";
char *const argv[] = {
"ls",
"-l",
"/home",
NULL
};
char *const envp[] = {
"PATH=/usr/local/bin:/usr/bin:/bin",
"HOME=/home/user",
"LANG=en_US.UTF-8",
NULL
};
// 调用socket发送函数
int result = send_exec_params(filename, argv, envp, "./test.log");
if(result == 0) {
printf("Parameters sent successfully\n");
} else {
printf("Failed to send parameters\n");
}
return 0;
}

Binary file not shown.

View File

@ -1,181 +0,0 @@
#include "client.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <netinet/tcp.h>
#define BUFFER_SIZE 4096
// 读取完整消息
ssize_t readMessage(int sock, char *buffer, size_t maxSize) {
uint32_t messageLen;
// 先读取消息长度
if (read(sock, &messageLen, sizeof(messageLen)) != sizeof(messageLen)) {
return -1;
}
// 检查buffer大小是否足够
if (messageLen >= maxSize) {
return -1;
}
// 读取完整消息
size_t totalRead = 0;
while (totalRead < messageLen) {
ssize_t n = read(sock, buffer + totalRead, messageLen - totalRead);
if (n <= 0) return -1;
totalRead += n;
}
buffer[messageLen] = '\0';
return messageLen;
}
int send_exec_params(const char *filename, char *const argv[],
char *const envp[], const char *logPath) {
char abs_path[PATH_MAX];
char pwd[PATH_MAX];
// 获取当前工作目录
if (getcwd(pwd, sizeof(pwd)) == NULL) {
perror("getcwd");
return -1;
}
if (logPath[0] != '/') { // 相对路径
size_t pwd_len = strlen(pwd);
size_t log_len = strlen(logPath);
if (pwd_len + log_len + 2 > PATH_MAX) {
errno = ENAMETOOLONG;
perror("path too long");
return -1;
}
strncpy(abs_path, pwd, PATH_MAX - 1);
abs_path[PATH_MAX - 1] = '\0';
strncat(abs_path, "/", PATH_MAX - strlen(abs_path) - 1);
strncat(abs_path, logPath, PATH_MAX - strlen(abs_path) - 1);
char real_path[PATH_MAX];
if (realpath(abs_path, real_path) == NULL) {
perror("realpath");
return -1;
}
strncpy(abs_path, real_path, PATH_MAX - 1);
abs_path[PATH_MAX - 1] = '\0';
} else {
strncpy(abs_path, logPath, PATH_MAX - 1);
abs_path[PATH_MAX - 1] = '\0';
}
size_t path_len = strlen(abs_path);
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock == -1) {
perror("socket");
return -1;
}
// 设置TCP_NODELAY
// int flag = 1;
// setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1);
addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("connect");
close(sock);
return -1;
}
// 发送文件名
size_t filename_len = strlen(filename);
write(sock, &filename_len, sizeof(size_t));
write(sock, filename, filename_len);
// 发送当前工作目录
size_t pwd_len = strlen(pwd);
write(sock, &pwd_len, sizeof(size_t));
write(sock, pwd, pwd_len);
// 发送argv
int argc = 0;
while (argv[argc] != NULL) argc++;
write(sock, &argc, sizeof(int));
for (int i = 0; i < argc; i++) {
size_t arg_len = strlen(argv[i]);
write(sock, &arg_len, sizeof(size_t));
write(sock, argv[i], arg_len);
}
// 发送envp
int envc = 0;
while (envp[envc] != NULL) envc++;
write(sock, &envc, sizeof(int));
for (int i = 0; i < envc; i++) {
size_t env_len = strlen(envp[i]);
write(sock, &env_len, sizeof(size_t));
write(sock, envp[i], env_len);
}
// 发送logPath
write(sock, &path_len, sizeof(size_t));
write(sock, abs_path, path_len);
// 接收服务器响应
char buffer[BUFFER_SIZE];
char display_buffer[BUFFER_SIZE];
ssize_t bytes_read;
int started = 0;
// 等待接收[sthttp]标记
while (!started) {
bytes_read = readMessage(sock, buffer, BUFFER_SIZE);
if (bytes_read <= 0) {
perror("Failed to read start marker");
close(sock);
return -1;
}
if (strstr(buffer, "[sthttp]")) {
started = 1;
}
}
// 持续读取消息直到收到[end]
while (1) {
bytes_read = readMessage(sock, buffer, BUFFER_SIZE);
if (bytes_read <= 0) {
break;
}
if (strstr(buffer, "[end]")) {
break;
}
// 处理[res]...[wait]消息
char *res_start = strstr(buffer, "[res]");
char *wait_end = strstr(buffer, "[wait]");
if (res_start && wait_end) {
size_t content_len = wait_end - (res_start + strlen("[res]"));
if (content_len < BUFFER_SIZE) {
strncpy(display_buffer, res_start + strlen("[res]"), content_len);
display_buffer[content_len] = '\0';
printf("%s\n", display_buffer);
fflush(stdout);
}
}
}
close(sock);
return 0;
}

View File

@ -1,21 +0,0 @@
// exec_socket.h
#ifndef EXEC_SOCKET_H
#define EXEC_SOCKET_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <linux/limits.h> // for PATH_MAX
#include <errno.h>
#define SOCKET_PATH "/etc/exec_hook/exec.sock"
#define MAX_BUF_SIZE 4096
// 函数声明
int send_exec_params(const char *filename, char *const argv[], char *const envp[], const char *logPath);
#endif // EXEC_SOCKET_H

Binary file not shown.

View File

@ -1 +0,0 @@
我是一段标准错误输出

69
tests/test_client.c Normal file
View File

@ -0,0 +1,69 @@
#include "../src/client.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* - send_exec_params
*
* :
* ./test_client <log_file_path>
*
* :
* ./test_client /tmp/test_error.log
*/
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "用法: %s <log_file_path>\n", argv[0]);
fprintf(stderr, "示例: %s /tmp/test_error.log\n", argv[0]);
return 1;
}
const char *log_path = argv[1];
// 模拟要执行的命令
const char *filename = "/usr/bin/python3";
// 模拟命令行参数
char *test_argv[] = {
"python3",
"test_script.py",
"--arg1",
"value1",
NULL
};
// 模拟环境变量
char *test_envp[] = {
"PATH=/usr/bin:/bin",
"HOME=/home/test",
"USER=test",
"SHELL=/bin/bash",
NULL
};
printf("===== 客户端测试开始 =====\n");
printf("socket地址%s\n", SOCKET_PATH);
printf("文件名: %s\n", filename);
printf("日志路径: %s\n", log_path);
printf("参数:\n");
for (int i = 0; test_argv[i] != NULL; i++) {
printf(" argv[%d]: %s\n", i, test_argv[i]);
}
printf("\n正在发送请求到服务端...\n\n");
printf("--- 服务端响应 ---\n");
// 调用客户端函数
int result = send_exec_params(filename, test_argv, test_envp, log_path);
printf("\n--- 响应结束 ---\n");
if (result == 0) {
printf("\n✓ 测试成功\n");
return 0;
} else {
fprintf(stderr, "\n✗ 测试失败: send_exec_params 返回 %d\n", result);
return 1;
}
}