From 64452a7aa7eec0e590975188645234166125e1e5 Mon Sep 17 00:00:00 2001 From: dongl <2725096176@qq.com> Date: Mon, 10 Jul 2023 13:22:50 +0800 Subject: [PATCH] main.cpp g++ -Wall -fPIC -shared -o net_ip_hook.so main.cpp -ldl sudo gedit /etc/environment #LD_LIBRARY_PATH #LD_PRELOAD LD_PRELOAD="/home/dongl/code/safe_test/hook.so" #LD_PRELOAD="/home/dongl/code/safe_test/net_ip_hook.so" --- CMakeLists.txt | 7 ++ hook.bin.cpp | 273 +++++++++++++++++++++++++++++++++++++++++++++++++ hook.so | Bin 0 -> 87368 bytes main.cpp | 270 ++++++++++++++++++++++++++++++++++++++++++++++++ old.cpp | 270 ++++++++++++++++++++++++++++++++++++++++++++++++ temp.cpp | 0 6 files changed, 820 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 hook.bin.cpp create mode 100755 hook.so create mode 100644 main.cpp create mode 100644 old.cpp create mode 100644 temp.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..bfa2250 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.25) +project(ko_open) + +set(CMAKE_CXX_STANDARD 17) + +#add_executable(ko_open main.cpp) +add_executable(ko_open hook.bin.cpp) diff --git a/hook.bin.cpp b/hook.bin.cpp new file mode 100644 index 0000000..3b23935 --- /dev/null +++ b/hook.bin.cpp @@ -0,0 +1,273 @@ +// +// Created by dongl on 23-7-10. +// + + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ACCEPT 9999 +#define CONNECT 19999 + + + +// 定义指向原始open函数的函数指针 +typedef int (*file_open_func_t)(const char *pathname, int flags, ...); +static file_open_func_t original_file_open = nullptr; +static file_open_func_t file_open = nullptr; +//read +typedef ssize_t (*file_read_func_t)(int fd, void *buf, size_t nbytes); +static file_read_func_t original_file_read = nullptr; +static file_read_func_t file_read = nullptr; +// connect +typedef int (*ip_connect_fun_t)(int, const struct sockaddr *, socklen_t); +static ip_connect_fun_t original_file_connect = nullptr; +static ip_connect_fun_t file_connect = nullptr; +// accept +typedef int (*ip_accept_fun_t)(int, struct sockaddr *, socklen_t *); +static ip_accept_fun_t original_file_accept = nullptr; +static ip_accept_fun_t file_accept = nullptr; + + +// 定义原始的do_sys_open()函数指针 +//static long (*real_do_sys_open)(int dfd, const char __user *filename, int flags, umode_t mode) = nullptr; + +// 定义日志文件路径和配置文件路径的环境变量 +const char *LOG_FILE_PATH = "/home/dongl/code/safe_test/log"; +const char *CONFIG_FILE_PATH = "/home/dongl/code/safe_test/config.txt"; +const char *LOG_NET_IP_PATH = "/home/dongl/code/safe_test/net-log"; +const char *CONFIG_NET_IP_PATH = "/home/dongl/code/safe_test/net-config.txt"; + +// 将时间戳转换为字符串 +std::string Time_t2String(time_t t) { + char tmp[64] = {0}; + strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", localtime(&t)); + return tmp; +} + +// 获取当前进程的可执行文件路径和名称 +size_t get_executable_path(char *processdir, char *processname, size_t len) { + char *path_end; + if (readlink("/proc/self/exe", processdir, len) <= 0) + return -1; + path_end = strrchr(processdir, '/'); + if (path_end == nullptr) + return -1; + ++path_end; + strcpy(processname, path_end); + *path_end = '\0'; + return (size_t) (path_end - processdir); +} + +// 读取配置文件并填充文件和进程集合 +void read_config_file(std::set& file_set, std::set& process_set, const char* config_name) { + // 打开配置文件 + int config_fd = original_file_open(config_name, O_RDONLY); + if (config_fd < 0) + return; + + // 读取配置文件 + char buff[4096]; + std::string data; + bool state = true; + while (original_file_read(config_fd, buff, sizeof(buff)) > 0) { + for (const auto &item: buff) { + if (item != '\n') { + data.push_back(item); + } else if (item == '\n') { + // 检查行是文件部分还是进程部分 + std::string temp = config_name == CONFIG_FILE_PATH ? "[safe_file]" : "[black_ip]"; + if (data == temp) { + state = true; + data.clear(); + continue; + } else if (data == "[safe_process]") { + state = false; + data.clear(); + continue; + } + + // 将文件或进程添加到相应的集合中 + if (state) { + file_set.insert(data); + data.clear(); + } else { + process_set.insert(data); + data.clear(); + } + } + } + } + + // 关闭配置文件 + close(config_fd); +} + +// 将文件访问日志写入日志文件 +void write_log(const std::string &pathname, int mode, const std::string &result, const char* log_name) { + char run_path[40960] = {0}; + char process_name[10240] = {0}; + get_executable_path(run_path, process_name, sizeof(run_path)); + + std::string access_mode; + if (mode == O_RDONLY) + access_mode = "读取"; + else if (mode == ACCEPT) + access_mode = "ACCEPT"; + else if (mode == CONNECT) + access_mode = "CONNECT"; + else if (mode == O_WRONLY) + access_mode = "写入"; + else if (mode == O_RDWR) + access_mode = "读写"; + else if (mode == (O_WRONLY | O_APPEND)) + access_mode = "追加"; + + std::string log = "[" + Time_t2String(time(nullptr)) + "] " + + "<" + pathname + "> " + access_mode + " {" + process_name + ":" + run_path + "} " + result + "\n"; + int log_fd = original_file_open(log_name, O_WRONLY | O_CREAT | O_APPEND, 0644); + if (log_fd > 0) { + write(log_fd, log.c_str(), log.size()); + close(log_fd); + } +} + +// +ssize_t read(int fd, void *buf, size_t nbytes) { + std::set file_set; + std::set process_set; + read_config_file(file_set, process_set, CONFIG_FILE_PATH); + // 查进程名 及 运行路径 + char run_path[4096] = {0}; + char process_name[1024] = {0}; + get_executable_path(run_path, process_name, sizeof(run_path)); + // 根据fd取文件名 + char file_name[4096] = {'\0'}; + char file_path[4096] = {'\0'}; + snprintf(file_name, sizeof(file_name), "/proc/%d/fd/%d", getpid(), fd); + ssize_t ret = readlink(file_name, file_path, sizeof(file_path) - 1); + if (ret == -1) { + return original_file_read(fd, buf, nbytes); + } + + // 检查 + auto safe_file = file_set.find(file_path); + auto safe_process = process_set.find(process_name); + + // 校验 + if (safe_file != file_set.end()) { + if (safe_process != process_set.end()) { + write_log(file_path, O_RDONLY, "正常访问", LOG_FILE_PATH); + } else { + write_log(file_path, O_RDONLY, "拒绝访问", LOG_FILE_PATH); + errno = EACCES; + return original_file_read(fd, buf, 0); + } + } + return original_file_read(fd, buf, nbytes); +} + +// 判断接入的网络是否为过滤IP,如果是则提前返回 +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + // 获取链接ip + char ip[128]; + memset(ip, 0, sizeof(ip)); // ip地址 + int port = -1; // 端口号 + if (AF_INET == addr->sa_family) { + auto *sa4 = (struct sockaddr_in *) addr; + inet_ntop(AF_INET, (void *) (struct sockaddr *) &sa4->sin_addr, ip, sizeof(ip)); + port = ntohs(sa4->sin_port); + printf("\nAF_INET IP===%s:%d\n", ip, port); + } + + // 查进程名 及 运行路径 + char run_path[4096] = {0}; + char process_name[1024] = {0}; + get_executable_path(run_path, process_name, sizeof(run_path)); + + // 获取黑名单ip + std::set ip_set; + std::set process_set; + read_config_file(ip_set, process_set, CONFIG_NET_IP_PATH); + auto black_ip = ip_set.find(ip); + auto safe_process = process_set.find(process_name); + + // 比较IP 是黑名单ip + if (black_ip != ip_set.end()) { + // log ip + std::string temp; + temp.append(ip); + temp.append(":"+std::to_string(port)+"<"+std::to_string(sockfd)+">"); + + if (safe_process != process_set.end()) { + write_log(temp, CONNECT, "允许访问", LOG_NET_IP_PATH); + return original_file_connect(sockfd, addr, addrlen); + } else { + write_log(temp, CONNECT, "拒绝访问", LOG_NET_IP_PATH); + return -1; + } + } + + return original_file_connect(sockfd, addr, addrlen); +} + +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + // 获取链接ip + char ip[128]; + memset(ip, 0, sizeof(ip)); // ip地址 + int port = -1; // 端口号 + if (AF_INET == addr->sa_family) { + auto *sa4 = (struct sockaddr_in *) addr; + inet_ntop(AF_INET, (void *) (struct sockaddr *) &sa4->sin_addr, ip, sizeof(ip)); + port = ntohs(sa4->sin_port); + printf("\nAF_INET IP===%s:%d\n", ip, port); + } + + // 查进程名 及 运行路径 + char run_path[4096] = {0}; + char process_name[1024] = {0}; + get_executable_path(run_path, process_name, sizeof(run_path)); + + // 获取黑名单ip + std::set ip_set; + std::set process_set; + read_config_file(ip_set, process_set, CONFIG_NET_IP_PATH); + auto black_ip = ip_set.find(ip); + auto safe_process = process_set.find(process_name); + + // log ip + std::string temp; + temp.append(ip); + temp.append(":"+std::to_string(port)+"<"+std::to_string(sockfd)+">"); + + // 比较IP 是黑名单ip + if (black_ip != ip_set.end()) { + if (safe_process != process_set.end()) { + write_log(temp, ACCEPT, "允许访问",LOG_NET_IP_PATH); + return original_file_accept(sockfd, addr, addrlen); + } else { + write_log(temp, ACCEPT, "拒绝访问", LOG_NET_IP_PATH); + return -1; + } + } + + // 放行 + return original_file_accept(sockfd, addr, addrlen); +} + + + + +// 初始化函数,获取原始文件访问函数的地址并替换为拦截函数 +int main() { + original_file_open = (file_open_func_t) dlsym(RTLD_NEXT, "open"); + original_file_read = (file_read_func_t) dlsym(RTLD_NEXT, "read"); + original_file_connect = (ip_connect_fun_t) dlsym(RTLD_NEXT, "connect"); + original_file_accept = (ip_accept_fun_t) dlsym(RTLD_NEXT, "accept"); +} \ No newline at end of file diff --git a/hook.so b/hook.so new file mode 100755 index 0000000000000000000000000000000000000000..5cc6c505c9c56522bef6d4d60c7b82084a6ee0e1 GIT binary patch literal 87368 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­-)MM@hM%wDu^N7zh99HhXKQ$zhW|># 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 Oez~v;3kr20OtUYvXZZL4 literal 0 HcmV?d00001 diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..09c138b --- /dev/null +++ b/main.cpp @@ -0,0 +1,270 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ACCEPT 9999 +#define CONNECT 19999 + + +// 定义指向原始文件访问函数的函数指针 +typedef int (*file_access_func_t)(const char *pathname, int mode, ...); +static file_access_func_t original_file_access = nullptr; +// 定义指向原始open函数的函数指针 +typedef int (*file_open_func_t)(const char *pathname, int flags, ...); +static file_open_func_t original_file_open = nullptr; +// 定义指向原始creat函数的函数指针 +typedef int (*file_creat_func_t)(const char *pathname, mode_t mode); +static file_creat_func_t original_file_creat = nullptr; +//read +typedef ssize_t (*file_read_func_t)(int fd, void *buf, size_t nbytes); +static file_read_func_t original_file_read = nullptr; +// connect +typedef int (*ip_connect_fun_t)(int, const struct sockaddr *, socklen_t); +static ip_connect_fun_t original_file_connect = nullptr; +// accept +typedef int (*ip_accept_fun_t)(int, struct sockaddr *, socklen_t *); +static ip_accept_fun_t original_file_accept = nullptr; + + +// 定义原始的do_sys_open()函数指针 +//static long (*real_do_sys_open)(int dfd, const char __user *filename, int flags, umode_t mode) = nullptr; + +// 定义日志文件路径和配置文件路径的环境变量 +const char *LOG_FILE_PATH = "/home/dongl/code/safe_test/log"; +const char *CONFIG_FILE_PATH = "/home/dongl/code/safe_test/config.txt"; +const char *LOG_NET_IP_PATH = "/home/dongl/code/safe_test/net-log"; +const char *CONFIG_NET_IP_PATH = "/home/dongl/code/safe_test/net-config.txt"; + +// 将时间戳转换为字符串 +std::string Time_t2String(time_t t) { + char tmp[64] = {0}; + strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", localtime(&t)); + return tmp; +} + +// 获取当前进程的可执行文件路径和名称 +size_t get_executable_path(char *processdir, char *processname, size_t len) { + char *path_end; + if (readlink("/proc/self/exe", processdir, len) <= 0) + return -1; + path_end = strrchr(processdir, '/'); + if (path_end == nullptr) + return -1; + ++path_end; + strcpy(processname, path_end); + *path_end = '\0'; + return (size_t) (path_end - processdir); +} + +// 读取配置文件并填充文件和进程集合 +void read_config_file(std::set& file_set, std::set& process_set, const char* config_name) { + // 打开配置文件 + int config_fd = original_file_open(config_name, O_RDONLY); + if (config_fd < 0) + return; + + // 读取配置文件 + char buff[4096]; + std::string data; + bool state = true; + while (original_file_read(config_fd, buff, sizeof(buff)) > 0) { + for (const auto &item: buff) { + if (item != '\n') { + data.push_back(item); + } else if (item == '\n') { + // 检查行是文件部分还是进程部分 + std::string temp = config_name == CONFIG_FILE_PATH ? "[safe_file]" : "[black_ip]"; + if (data == temp) { + state = true; + data.clear(); + continue; + } else if (data == "[safe_process]") { + state = false; + data.clear(); + continue; + } + + // 将文件或进程添加到相应的集合中 + if (state) { + file_set.insert(data); + data.clear(); + } else { + process_set.insert(data); + data.clear(); + } + } + } + } + + // 关闭配置文件 + close(config_fd); +} + +// 将文件访问日志写入日志文件 +void write_log(const std::string &pathname, int mode, const std::string &result, const char* log_name) { + char run_path[40960] = {0}; + char process_name[10240] = {0}; + get_executable_path(run_path, process_name, sizeof(run_path)); + + std::string access_mode; + if (mode == O_RDONLY) + access_mode = "读取"; + else if (mode == ACCEPT) + access_mode = "ACCEPT"; + else if (mode == CONNECT) + access_mode = "CONNECT"; + else if (mode == O_WRONLY) + access_mode = "写入"; + else if (mode == O_RDWR) + access_mode = "读写"; + else if (mode == (O_WRONLY | O_APPEND)) + access_mode = "追加"; + + std::string log = "[" + Time_t2String(time(nullptr)) + "] " + + "<" + pathname + "> " + access_mode + " {" + process_name + ":" + run_path + "} " + result + "\n"; + int log_fd = original_file_open(log_name, O_WRONLY | O_CREAT | O_APPEND, 0644); + if (log_fd > 0) { + write(log_fd, log.c_str(), log.size()); + close(log_fd); + } +} + +// +ssize_t read(int fd, void *buf, size_t nbytes) { + std::set file_set; + std::set process_set; + read_config_file(file_set, process_set, CONFIG_FILE_PATH); + // 查进程名 及 运行路径 + char run_path[4096] = {0}; + char process_name[1024] = {0}; + get_executable_path(run_path, process_name, sizeof(run_path)); + // 根据fd取文件名 + char file_name[4096] = {'\0'}; + char file_path[4096] = {'\0'}; + snprintf(file_name, sizeof(file_name), "/proc/%d/fd/%d", getpid(), fd); + ssize_t ret = readlink(file_name, file_path, sizeof(file_path) - 1); + if (ret == -1) { + return original_file_read(fd, buf, nbytes); + } + + // 检查 + auto safe_file = file_set.find(file_path); + auto safe_process = process_set.find(process_name); + + // 校验 + if (safe_file != file_set.end()) { + if (safe_process != process_set.end()) { + write_log(file_path, O_RDONLY, "正常访问", LOG_FILE_PATH); + } else { + write_log(file_path, O_RDONLY, "拒绝访问", LOG_FILE_PATH); + errno = EACCES; + return original_file_read(fd, buf, 0); + } + } + return original_file_read(fd, buf, nbytes); +} + +// 判断接入的网络是否为过滤IP,如果是则提前返回 +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + // 获取链接ip + char ip[128]; + memset(ip, 0, sizeof(ip)); // ip地址 + int port = -1; // 端口号 + if (AF_INET == addr->sa_family) { + auto *sa4 = (struct sockaddr_in *) addr; + inet_ntop(AF_INET, (void *) (struct sockaddr *) &sa4->sin_addr, ip, sizeof(ip)); + port = ntohs(sa4->sin_port); + printf("\nAF_INET IP===%s:%d\n", ip, port); + } + + // 查进程名 及 运行路径 + char run_path[4096] = {0}; + char process_name[1024] = {0}; + get_executable_path(run_path, process_name, sizeof(run_path)); + + // 获取黑名单ip + std::set ip_set; + std::set process_set; + read_config_file(ip_set, process_set, CONFIG_NET_IP_PATH); + auto black_ip = ip_set.find(ip); + auto safe_process = process_set.find(process_name); + + // 比较IP 是黑名单ip + if (black_ip != ip_set.end()) { + // log ip + std::string temp; + temp.append(ip); + temp.append(":"+std::to_string(port)+"<"+std::to_string(sockfd)+">"); + + if (safe_process != process_set.end()) { + write_log(temp, CONNECT, "允许访问", LOG_NET_IP_PATH); + return original_file_connect(sockfd, addr, addrlen); + } else { + write_log(temp, CONNECT, "拒绝访问", LOG_NET_IP_PATH); + return -1; + } + } + + return original_file_connect(sockfd, addr, addrlen); +} + +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + // 获取链接ip + char ip[128]; + memset(ip, 0, sizeof(ip)); // ip地址 + int port = -1; // 端口号 + if (AF_INET == addr->sa_family) { + auto *sa4 = (struct sockaddr_in *) addr; + inet_ntop(AF_INET, (void *) (struct sockaddr *) &sa4->sin_addr, ip, sizeof(ip)); + port = ntohs(sa4->sin_port); + printf("\nAF_INET IP===%s:%d\n", ip, port); + } + + // 查进程名 及 运行路径 + char run_path[4096] = {0}; + char process_name[1024] = {0}; + get_executable_path(run_path, process_name, sizeof(run_path)); + + // 获取黑名单ip + std::set ip_set; + std::set process_set; + read_config_file(ip_set, process_set, CONFIG_NET_IP_PATH); + auto black_ip = ip_set.find(ip); + auto safe_process = process_set.find(process_name); + + // log ip + std::string temp; + temp.append(ip); + temp.append(":"+std::to_string(port)+"<"+std::to_string(sockfd)+">"); + + // 比较IP 是黑名单ip + if (black_ip != ip_set.end()) { + if (safe_process != process_set.end()) { + write_log(temp, ACCEPT, "允许访问",LOG_NET_IP_PATH); + return original_file_accept(sockfd, addr, addrlen); + } else { + write_log(temp, ACCEPT, "拒绝访问", LOG_NET_IP_PATH); + return -1; + } + } + + // 放行 + return original_file_accept(sockfd, addr, addrlen); +} + + +// 初始化函数,获取原始文件访问函数的地址并替换为拦截函数 +__attribute__((constructor)) void init() { + original_file_access = (file_access_func_t) dlsym(RTLD_NEXT, "access"); + original_file_open = (file_open_func_t) dlsym(RTLD_NEXT, "open"); + original_file_creat = (file_creat_func_t) dlsym(RTLD_NEXT, "creat"); + original_file_read = (file_read_func_t) dlsym(RTLD_NEXT, "read"); + original_file_connect = (ip_connect_fun_t) dlsym(RTLD_NEXT, "connect"); + original_file_accept = (ip_accept_fun_t) dlsym(RTLD_NEXT, "accept"); +} \ No newline at end of file diff --git a/old.cpp b/old.cpp new file mode 100644 index 0000000..09c138b --- /dev/null +++ b/old.cpp @@ -0,0 +1,270 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ACCEPT 9999 +#define CONNECT 19999 + + +// 定义指向原始文件访问函数的函数指针 +typedef int (*file_access_func_t)(const char *pathname, int mode, ...); +static file_access_func_t original_file_access = nullptr; +// 定义指向原始open函数的函数指针 +typedef int (*file_open_func_t)(const char *pathname, int flags, ...); +static file_open_func_t original_file_open = nullptr; +// 定义指向原始creat函数的函数指针 +typedef int (*file_creat_func_t)(const char *pathname, mode_t mode); +static file_creat_func_t original_file_creat = nullptr; +//read +typedef ssize_t (*file_read_func_t)(int fd, void *buf, size_t nbytes); +static file_read_func_t original_file_read = nullptr; +// connect +typedef int (*ip_connect_fun_t)(int, const struct sockaddr *, socklen_t); +static ip_connect_fun_t original_file_connect = nullptr; +// accept +typedef int (*ip_accept_fun_t)(int, struct sockaddr *, socklen_t *); +static ip_accept_fun_t original_file_accept = nullptr; + + +// 定义原始的do_sys_open()函数指针 +//static long (*real_do_sys_open)(int dfd, const char __user *filename, int flags, umode_t mode) = nullptr; + +// 定义日志文件路径和配置文件路径的环境变量 +const char *LOG_FILE_PATH = "/home/dongl/code/safe_test/log"; +const char *CONFIG_FILE_PATH = "/home/dongl/code/safe_test/config.txt"; +const char *LOG_NET_IP_PATH = "/home/dongl/code/safe_test/net-log"; +const char *CONFIG_NET_IP_PATH = "/home/dongl/code/safe_test/net-config.txt"; + +// 将时间戳转换为字符串 +std::string Time_t2String(time_t t) { + char tmp[64] = {0}; + strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", localtime(&t)); + return tmp; +} + +// 获取当前进程的可执行文件路径和名称 +size_t get_executable_path(char *processdir, char *processname, size_t len) { + char *path_end; + if (readlink("/proc/self/exe", processdir, len) <= 0) + return -1; + path_end = strrchr(processdir, '/'); + if (path_end == nullptr) + return -1; + ++path_end; + strcpy(processname, path_end); + *path_end = '\0'; + return (size_t) (path_end - processdir); +} + +// 读取配置文件并填充文件和进程集合 +void read_config_file(std::set& file_set, std::set& process_set, const char* config_name) { + // 打开配置文件 + int config_fd = original_file_open(config_name, O_RDONLY); + if (config_fd < 0) + return; + + // 读取配置文件 + char buff[4096]; + std::string data; + bool state = true; + while (original_file_read(config_fd, buff, sizeof(buff)) > 0) { + for (const auto &item: buff) { + if (item != '\n') { + data.push_back(item); + } else if (item == '\n') { + // 检查行是文件部分还是进程部分 + std::string temp = config_name == CONFIG_FILE_PATH ? "[safe_file]" : "[black_ip]"; + if (data == temp) { + state = true; + data.clear(); + continue; + } else if (data == "[safe_process]") { + state = false; + data.clear(); + continue; + } + + // 将文件或进程添加到相应的集合中 + if (state) { + file_set.insert(data); + data.clear(); + } else { + process_set.insert(data); + data.clear(); + } + } + } + } + + // 关闭配置文件 + close(config_fd); +} + +// 将文件访问日志写入日志文件 +void write_log(const std::string &pathname, int mode, const std::string &result, const char* log_name) { + char run_path[40960] = {0}; + char process_name[10240] = {0}; + get_executable_path(run_path, process_name, sizeof(run_path)); + + std::string access_mode; + if (mode == O_RDONLY) + access_mode = "读取"; + else if (mode == ACCEPT) + access_mode = "ACCEPT"; + else if (mode == CONNECT) + access_mode = "CONNECT"; + else if (mode == O_WRONLY) + access_mode = "写入"; + else if (mode == O_RDWR) + access_mode = "读写"; + else if (mode == (O_WRONLY | O_APPEND)) + access_mode = "追加"; + + std::string log = "[" + Time_t2String(time(nullptr)) + "] " + + "<" + pathname + "> " + access_mode + " {" + process_name + ":" + run_path + "} " + result + "\n"; + int log_fd = original_file_open(log_name, O_WRONLY | O_CREAT | O_APPEND, 0644); + if (log_fd > 0) { + write(log_fd, log.c_str(), log.size()); + close(log_fd); + } +} + +// +ssize_t read(int fd, void *buf, size_t nbytes) { + std::set file_set; + std::set process_set; + read_config_file(file_set, process_set, CONFIG_FILE_PATH); + // 查进程名 及 运行路径 + char run_path[4096] = {0}; + char process_name[1024] = {0}; + get_executable_path(run_path, process_name, sizeof(run_path)); + // 根据fd取文件名 + char file_name[4096] = {'\0'}; + char file_path[4096] = {'\0'}; + snprintf(file_name, sizeof(file_name), "/proc/%d/fd/%d", getpid(), fd); + ssize_t ret = readlink(file_name, file_path, sizeof(file_path) - 1); + if (ret == -1) { + return original_file_read(fd, buf, nbytes); + } + + // 检查 + auto safe_file = file_set.find(file_path); + auto safe_process = process_set.find(process_name); + + // 校验 + if (safe_file != file_set.end()) { + if (safe_process != process_set.end()) { + write_log(file_path, O_RDONLY, "正常访问", LOG_FILE_PATH); + } else { + write_log(file_path, O_RDONLY, "拒绝访问", LOG_FILE_PATH); + errno = EACCES; + return original_file_read(fd, buf, 0); + } + } + return original_file_read(fd, buf, nbytes); +} + +// 判断接入的网络是否为过滤IP,如果是则提前返回 +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + // 获取链接ip + char ip[128]; + memset(ip, 0, sizeof(ip)); // ip地址 + int port = -1; // 端口号 + if (AF_INET == addr->sa_family) { + auto *sa4 = (struct sockaddr_in *) addr; + inet_ntop(AF_INET, (void *) (struct sockaddr *) &sa4->sin_addr, ip, sizeof(ip)); + port = ntohs(sa4->sin_port); + printf("\nAF_INET IP===%s:%d\n", ip, port); + } + + // 查进程名 及 运行路径 + char run_path[4096] = {0}; + char process_name[1024] = {0}; + get_executable_path(run_path, process_name, sizeof(run_path)); + + // 获取黑名单ip + std::set ip_set; + std::set process_set; + read_config_file(ip_set, process_set, CONFIG_NET_IP_PATH); + auto black_ip = ip_set.find(ip); + auto safe_process = process_set.find(process_name); + + // 比较IP 是黑名单ip + if (black_ip != ip_set.end()) { + // log ip + std::string temp; + temp.append(ip); + temp.append(":"+std::to_string(port)+"<"+std::to_string(sockfd)+">"); + + if (safe_process != process_set.end()) { + write_log(temp, CONNECT, "允许访问", LOG_NET_IP_PATH); + return original_file_connect(sockfd, addr, addrlen); + } else { + write_log(temp, CONNECT, "拒绝访问", LOG_NET_IP_PATH); + return -1; + } + } + + return original_file_connect(sockfd, addr, addrlen); +} + +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + // 获取链接ip + char ip[128]; + memset(ip, 0, sizeof(ip)); // ip地址 + int port = -1; // 端口号 + if (AF_INET == addr->sa_family) { + auto *sa4 = (struct sockaddr_in *) addr; + inet_ntop(AF_INET, (void *) (struct sockaddr *) &sa4->sin_addr, ip, sizeof(ip)); + port = ntohs(sa4->sin_port); + printf("\nAF_INET IP===%s:%d\n", ip, port); + } + + // 查进程名 及 运行路径 + char run_path[4096] = {0}; + char process_name[1024] = {0}; + get_executable_path(run_path, process_name, sizeof(run_path)); + + // 获取黑名单ip + std::set ip_set; + std::set process_set; + read_config_file(ip_set, process_set, CONFIG_NET_IP_PATH); + auto black_ip = ip_set.find(ip); + auto safe_process = process_set.find(process_name); + + // log ip + std::string temp; + temp.append(ip); + temp.append(":"+std::to_string(port)+"<"+std::to_string(sockfd)+">"); + + // 比较IP 是黑名单ip + if (black_ip != ip_set.end()) { + if (safe_process != process_set.end()) { + write_log(temp, ACCEPT, "允许访问",LOG_NET_IP_PATH); + return original_file_accept(sockfd, addr, addrlen); + } else { + write_log(temp, ACCEPT, "拒绝访问", LOG_NET_IP_PATH); + return -1; + } + } + + // 放行 + return original_file_accept(sockfd, addr, addrlen); +} + + +// 初始化函数,获取原始文件访问函数的地址并替换为拦截函数 +__attribute__((constructor)) void init() { + original_file_access = (file_access_func_t) dlsym(RTLD_NEXT, "access"); + original_file_open = (file_open_func_t) dlsym(RTLD_NEXT, "open"); + original_file_creat = (file_creat_func_t) dlsym(RTLD_NEXT, "creat"); + original_file_read = (file_read_func_t) dlsym(RTLD_NEXT, "read"); + original_file_connect = (ip_connect_fun_t) dlsym(RTLD_NEXT, "connect"); + original_file_accept = (ip_accept_fun_t) dlsym(RTLD_NEXT, "accept"); +} \ No newline at end of file diff --git a/temp.cpp b/temp.cpp new file mode 100644 index 0000000..e69de29