From b5bd70ec7120e4672b3ab8f094cc7fe507b8dbff Mon Sep 17 00:00:00 2001 From: aixiao Date: Tue, 21 May 2024 09:08:14 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0Ng=E9=98=B2=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- nginx.c | 127 +++ nginx.h | 15 + rhost.c | 2536 ++++++++++++++++++++++++---------------------------- rhost.conf | 9 +- rhost.h | 2 - 6 files changed, 1304 insertions(+), 1387 deletions(-) create mode 100644 nginx.c create mode 100644 nginx.h diff --git a/Makefile b/Makefile index d49ab05..1aaca5f 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ LIBCOMMON_LIB += ./clamav/common/cert_util.c.o ./clamav/common/actions.c.o ./cla all: libclamav_rust libclamav rhost -rhost: conf.o rhost.o libiptc.o ccronexpr.o +rhost: conf.o rhost.o libiptc.o ccronexpr.o nginx.o $(CC) $(ip2region_CFLAGS) ip2region/ip2region.c $(CC) $(ip2region_CFLAGS) ip2region/xdb_searcher.c $(CC) $(cJSON_CFLAGS) cJSON/cJSON.c diff --git a/nginx.c b/nginx.c new file mode 100644 index 0000000..d9db137 --- /dev/null +++ b/nginx.c @@ -0,0 +1,127 @@ +#include "nginx.h" +#include "ip2region/ip2region.h" + +#define EVENT_SIZE (sizeof(struct inotify_event)) +#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16)) +#define INITIAL_BUFFER_SIZE 8192 + +int IP_location(char *string) { + char *area = NULL; + char *xdb_path = "ip2region.xdb"; + char *p = strchr(string, ' '); + char IP[64]; + memset(IP, 0, 64); + + if ((p - string) > 0) { + memmove(IP, string, p - string); + } else { + printf("Invalid IP string format.\n"); + return -1; + } + + if (access(xdb_path, F_OK) == -1) { // 判断 ip2region 地址定位库是否存在 + xdb_path = "ip2region/ip2region.xdb"; + if (access(xdb_path, F_OK) == -1) { + printf("ip2region.xdb DOESN'T EXIST!\n"); + return -1; + } + } + + area = ip2region(xdb_path, IP); + if (area == NULL) { + printf("ip2region解析地域错误\n"); + return -1; + } + + printf("IP地址:%s, %s\n", IP, area); + + return 0; +} + +void nginx_read_log(const char *filename) { + int fd = open(filename, O_RDONLY); + if (fd == -1) { + perror("open"); + exit(EXIT_FAILURE); + } + + // Move to the end of the file + if (lseek(fd, 0, SEEK_END) == -1) { + perror("lseek"); + close(fd); + exit(EXIT_FAILURE); + } + + int inotify_fd = inotify_init(); + if (inotify_fd < 0) { + perror("inotify_init"); + close(fd); + exit(EXIT_FAILURE); + } + + int wd = inotify_add_watch(inotify_fd, filename, IN_MODIFY); + if (wd == -1) { + perror("inotify_add_watch"); + close(inotify_fd); + close(fd); + exit(EXIT_FAILURE); + } + + char buffer[EVENT_BUF_LEN]; + + // Set the file descriptor to non-blocking mode + int flags = fcntl(fd, F_GETFL, 0); + if (flags == -1) { + perror("fcntl F_GETFL"); + inotify_rm_watch(inotify_fd, wd); + close(inotify_fd); + close(fd); + exit(EXIT_FAILURE); + } + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { + perror("fcntl F_SETFL"); + inotify_rm_watch(inotify_fd, wd); + close(inotify_fd); + close(fd); + exit(EXIT_FAILURE); + } + + // Initial dynamic buffer allocation + size_t buffer_size = INITIAL_BUFFER_SIZE; + char *read_buf = alloca(buffer_size); + if (!read_buf) { + perror("alloca"); + inotify_rm_watch(inotify_fd, wd); + close(inotify_fd); + close(fd); + exit(EXIT_FAILURE); + } + + while (1) { + int length = read(inotify_fd, buffer, EVENT_BUF_LEN); + if (length < 0) { + perror("read"); + break; + } + + for (int i = 0; i < length;) { + struct inotify_event *event = (struct inotify_event *) &buffer[i]; + if (event->mask & IN_MODIFY) { + int bytes_read; + while ((bytes_read = read(fd, read_buf, buffer_size - 1)) > 0) { + read_buf[bytes_read] = '\0'; + IP_location(read_buf); + } + if (bytes_read == -1 && errno != EAGAIN) { + perror("read"); + break; + } + } + i += EVENT_SIZE + event->len; + } + } + + inotify_rm_watch(inotify_fd, wd); + close(inotify_fd); + close(fd); +} diff --git a/nginx.h b/nginx.h new file mode 100644 index 0000000..c5b0e66 --- /dev/null +++ b/nginx.h @@ -0,0 +1,15 @@ +#ifndef NGINX_H +#define NGINX_H + +#include +#include +#include +#include +#include +#include +#include + + +extern void nginx_read_log(const char *filename); + +#endif diff --git a/rhost.c b/rhost.c index 13b2cc9..47a87c9 100644 --- a/rhost.c +++ b/rhost.c @@ -1,1379 +1,1157 @@ -#include "conf.h" -#include "rhost.h" -#include "libiptc.h" -#include "libclamav.h" -#include "clamscan.h" - -#include "ccronexpr.h" - -// 存储公网IP -char *public_ip; - -struct MemoryStruct -{ - char *memory; - size_t size; -}; - -// 计算字符串长度 -int _strlen(char *str) -{ - char *_p = NULL; - - - if (str == NULL) - return 0; - - _p = strchr(str, '\0'); - - if (_p == NULL) - return 0; - - return _p-str; -} - -static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) -{ - size_t realsize = size * nmemb; - struct MemoryStruct *mem = (struct MemoryStruct *)userp; - - // 注意这里根据每次被调用获得的数据重新动态分配缓存区的大小 - char *ptr = realloc(mem->memory, mem->size + realsize + 1); - if (ptr == NULL) - { - /* 内存不足! */ - printf("not enough memory (realloc returned NULL)\n"); - return 0; - } - - mem->memory = ptr; - memcpy(&(mem->memory[mem->size]), contents, realsize); - mem->size += realsize; - mem->memory[mem->size] = 0; - - return realsize; -} - -// 获取公网IP -static char *GET_PUBLIC_IP(char *URL) -{ - CURL *curl_handle; - CURLcode res; - - struct curl_slist *headers = NULL; - struct MemoryStruct chunk; - - chunk.memory = malloc(1); /* 将根据上述再分配的需要增长 */ - chunk.size = 0; /* 此时没有数据 */ - - curl_global_init(CURL_GLOBAL_ALL); - - /* 初始化curl会话 */ - curl_handle = curl_easy_init(); - - char *p = NULL; - char *buff; - - p = strstr(URL, "-H"); - if (p) { - - buff = (char *)alloca(p - URL + 1); - if (buff == NULL) - perror("out of memory."); - - memset(buff, 0, p - URL + 1); - memcpy(buff, URL, (int)(p - URL - 1)); - - // 赋值header值 - headers = curl_slist_append(headers, p + 3); - - // 设置header - curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl_handle, CURLOPT_URL, buff); - - } else { - /* 指定要获取的URL */ - curl_easy_setopt(curl_handle, CURLOPT_URL, URL); - - } - - /* 将所有数据发送到此函数 */ - //对于同一次阻塞的curl_easy_perform而言,在写完获取的数据之前,会多次调用 WriteMemoryCallback - curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); - - /* 将"chunk"结构传递给回调函数 */ - curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); - - curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); - - //对于同一次阻塞的curl_easy_perform而言,在写完获取的数据之前,会多次调用 WriteMemoryCallback - res = curl_easy_perform(curl_handle); - - if (res != CURLE_OK) { - fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); - } else { - //printf("%lu bytes retrieved\n", (unsigned long)chunk.size); - //printf("%s", chunk.memory); - ; - } - - curl_easy_cleanup(curl_handle); - curl_global_cleanup(); - - return chunk.memory; -} - -// 解析Json -char *process_json(char *buff, char *api) -{ - char *area = NULL; - int area_len = 0; - char *p = NULL; - - if (buff == NULL) - { - return NULL; - } - - cJSON *cjson_init = cJSON_Parse(buff); - if (cjson_init == NULL) { - perror("cJSON_Parse"); - return NULL; - } - if ((p = strstr(api, "baidu")) != NULL) { // baidu Api - int i; - - cJSON *data = cJSON_GetObjectItem(cjson_init, "data"); - if (data != NULL) { - for (i = 0; i < cJSON_GetArraySize(data); i++) { - cJSON *svalue = cJSON_GetArrayItem(data, i); - cJSON *location = cJSON_GetObjectItem(svalue, "location"); - area_len = _strlen(location->valuestring); - - area = (char *)alloca(area_len + 1); - if (area == NULL) - perror("out of memory."); - memset(area, 0, area_len + 1); - - snprintf(area, area_len+1, "%s", location->valuestring); - } - - } else { - return NULL; - } - } - else - { - cJSON_Delete(cjson_init); - return NULL; - } - - cJSON_Delete(cjson_init); - return strdup(area); -} - -// 检测系统 -int check_system() -{ - if (0 == access("/etc/debian_version", F_OK)) - { - return DEBISN_SYSTEM; - } - else if (0 == access("/etc/centos-release", F_OK)) - { - return CENTOS_SYSTEM; - } - - return UNKNOWN_SYSTEM; -} - -// 钉钉告警 -int dingding_warning(char *illegal_ip, char *public_ip, char *ip, conf * conf) -{ - FILE *fp; - char temp[64]; - char jsonObj[BUFFER]; - - memset(jsonObj, 0, BUFFER); - memset(temp, 0, 64); - strcpy(temp, public_ip); - temp[_strlen(public_ip) - 1] = '\0'; - - if ((fp = fopen("libcurl.log", "wt+")) == NULL) - { - return 1; - } - - CURL *curl; - CURLcode res; - - curl_global_init(CURL_GLOBAL_ALL); - curl = curl_easy_init(); - if (curl == NULL) - { - fclose(fp); - return 1; - } -#define JSIN "{ \ - \"msgtype\": \"text\", \ - \"text\": { \ - \"content\": \"Alert @%s 服务器地址:%s,封禁非法入侵主机:(%s%s)\" \ - }, \ - \"at\": { \ - \"atMobiles\": [\"%s\"], \ - \"isAtAll\": false \ - } \ - }" - - snprintf(jsonObj, BUFFER, JSIN, conf->PHONE, temp, ip, illegal_ip, conf->PHONE); - printf("%s\n", jsonObj); - - struct curl_slist *headers = NULL; - headers = curl_slist_append(headers, "Accept: application/json"); - headers = curl_slist_append(headers, "Content-Type: application/json"); - headers = curl_slist_append(headers, "charset: utf-8"); - - curl_easy_setopt(curl, CURLOPT_URL, conf->DING_WEBHOOK); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); - curl_easy_setopt(curl, CURLOPT_POST, 1); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl/0.1"); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); - - res = curl_easy_perform(curl); - - curl_easy_cleanup(curl); - curl_global_cleanup(); - fclose(fp); - - return res; -} - -// 邮件告警 -int mail_warning(char *illegal_ip, char *public_ip, char *ip, conf * conf) -{ - FILE *fp = NULL; - char buff[BUFFER]; - char text[BUFFER]; - char temp[64]; - - memset(buff, 0, BUFFER); - memset(text, 0, BUFFER); - memset(temp, 0, 64); - - strcpy(temp, public_ip); - temp[_strlen(public_ip) - 1] = '\0'; - snprintf(text, BUFFER, "echo \"主机:%s, 禁止(%s%s)访问\" | mail -s \"System ban IP\" %s", temp, ip, illegal_ip, conf->RECV_MAIL); - - if (NULL == (fp = popen(text, "r"))) - { - perror("popen text"); - } - - while (fgets(buff, BUFFER, fp) != NULL) - { - buff[_strlen(buff) - 1] = '\0'; - } - - if (NULL != fp) - pclose(fp); - - return 0; -} - -// 第三方邮箱告警 -int QQ_mail_warning(char *illegal_ip, char *public_ip, char *ip, conf * conf) -{ - char string[BUFFER + (sizeof(QQMAIL)) + 1]; - char text[BUFFER]; - char temp[32]; - - memset(string, 0, BUFFER + (sizeof(QQMAIL)) + 1); - memset(text, 0, BUFFER); - memset(temp, 0, 32); - - strcpy(temp, public_ip); - temp[_strlen(public_ip) - 1] = '\0'; - - snprintf(text, BUFFER, "主机:%s, 禁止(%s%s)访问!", temp, ip, illegal_ip); - snprintf(string, BUFFER + (sizeof(QQMAIL)) + 1, QQMAIL, conf->RECV_MAIL, text); - - return system(string); -} - -// 第三方邮箱告警, 感染病毒邮件提醒 -int QQ_mail_warning_Virus_files(char *local_ip, int Virus_number, conf * conf) -{ - char *command; - char *text; - char temp[32]; - - - command = (char *)alloca(BUFFER + (sizeof(QQMAIL)) + 1); - text = (char *)alloca(BUFFER); - - memset(command, 0, BUFFER + (sizeof(QQMAIL)) + 1); - memset(text, 0, BUFFER); - memset(temp, 0, 32); - - strcpy(temp, local_ip); - temp[_strlen(local_ip) - 1] = '\0'; - - snprintf(text, BUFFER, "Host:%s, Infected files: %d, Please handle!", temp, Virus_number); - snprintf(command, BUFFER+BUFFER + (sizeof(QQMAIL)) + 1, QQMAIL_Virus, conf->RECV_MAIL, text); - - return system(command); -} - -// 第三方邮箱告警, 磁盘使用率 -int QQ_mail_warning_Disk_Use(char *local_ip, int disk_use, conf * conf) -{ - char *command; - char *text; - char temp[32]; - - - command = (char *)alloca(BUFFER + (sizeof(QQMAIL)) + 1); - text = (char *)alloca(BUFFER); - - memset(command, 0, BUFFER + (sizeof(QQMAIL)) + 1); - memset(text, 0, BUFFER); - memset(temp, 0, 32); - - strcpy(temp, local_ip); - temp[_strlen(local_ip) - 1] = '\0'; - - snprintf(text, BUFFER, "Host:%s, Disk usage reaches threshold!, Please handle!", temp); - snprintf(command, BUFFER, QQMAIL_DISK_USE, conf->RECV_MAIL, text); - - return system(command); -} - -// IP段白名单对比 -int whitelist(char *client_ip, char (*whitelist_ip)[WHITELIST_IP_NUM]) -{ - int i; - - for (i = 1; i < WHITELIST_IP_NUM - 1; i++) - { - if (strcmp(whitelist_ip[i], "\0") == 0) // 如果字符串为空就跳出循环 - { - break; - } - if ((strncmp(client_ip, whitelist_ip[i], _strlen(whitelist_ip[i]))) == 0) // 对比client_ip长度, - { - return 1; - } - } - - return 0; -} - -// 地域段白名单对比 -int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM]) -{ - int i; - char *p; - - for (i = 1; i < WHITELIST_IP_NUM - 1; i++) - { - if (strcmp(region_list[i], "\0") == 0) // 如果字符串为空就跳出循环 - { - break; - } - - //printf("%s %s\n", str, region_list[i]); - // 在str中查找region_list[i] - p = strstr(str, region_list[i]); - if (p != NULL) - { - return 1; - } - } - - return 0; -} - -// 去除空格 -char *remove_space(char *str) -{ - unsigned int i = 0, j = 0; - unsigned int uLen = _strlen(str); - char *strRet; - - if (0 == uLen) - { - return '\0'; - } - - strRet = (char *)malloc(uLen + 2); - memset(strRet, 0, uLen + 2); - - for (i = 0; i < uLen; i++) - { - if (str[i] != ' ') - { - strRet[j++] = str[i]; - } - } - strRet[j] = '\0'; - - return strRet; -} - -// 磁盘使用率 -int disk_waring(int threshold) -{ - FILE *fp = NULL; - char buffer[BUFFER]; - char command[BUFFER]; - int is = 0; - - #define DF "for u in `df -mh | grep -E -e \".:.\" -e \"^/dev\" | awk '{print $5}' | sed 's|%%||g'`; do if test \"$u\" -ge %d; then echo \"$u\"; fi done" - - memset(buffer, 0, BUFFER); - memset(command, 0, BUFFER); - - snprintf(command, BUFFER, DF, threshold); - - //printf("%s\n", command); - fp = popen(command, "r"); - - while(fgets(buffer, BUFFER, fp) != NULL) - { - printf("%s", buffer); - is = 1; - break; - } - pclose(fp); - - - return is; -} - -char *_time() -{ - char temp[BUFFER]; - char *wday[] = {"0", "1", "2", "3", "4", "5", "6"}; - time_t t; - struct tm *p; - time(&t); - p = localtime(&t); // 取得当地时间 - - memset(temp, 0, BUFFER); - snprintf(temp, BUFFER, "[%d/%02d/%02d %s %02d:%02d:%02d] ", (1900+p->tm_year), (1+p->tm_mon), p->tm_mday, wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec); - - return strdup(temp); -} - -int system_version() { - FILE *fp = fopen("/etc/debian_version", "r"); - - if (fp == NULL) { - perror("Failed to open file"); - return 0; - } - - char buff[256]; - if (fgets(buff, sizeof(buff), fp) == NULL) { - fclose(fp); - perror("Failed to read file"); - return 0; - } - - fclose(fp); - - size_t len = strlen(buff); - if (len <= 0) { - return 0; - } - - // Remove trailing newline character, if present - if (buff[len - 1] == '\n') { - buff[len - 1] = '\0'; - } - - return atoi(buff); -} - -// 封禁非法IP -int rule(conf * conf) -{ - char whitelist_ip[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } }; - char region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } }; - - char REGION_LIST_COPY[conf->REGION_LIST_LEN+1]; - char IPV4_WHITE_LIST_COPY[conf->IPV4_WHITE_LIST_LEN+1]; - - char p_two[2], *command, *splice_command, *temp, buffer[BUFFER], awk[BUFFER]; - FILE *fp, *fc; - time_t timep; - struct tm *tp; - long int ip_length = 1; - - - - fp = NULL; - fc = NULL; - timep = time(NULL); - tp = localtime(&timep); - memset(buffer, 0, BUFFER); - memset(awk, 0, BUFFER); - memset(p_two, 0, 2); - - - - char *t = NULL; - t = _time(); - - - if (DEBISN_SYSTEM == check_system()) // Debian 系统规则 - { - if (system_version() >= 12) - { - if ((fp = popen(GE_12, "r")) == NULL) - { - perror("GE_12"); - return -1; - } - } - else - { - if (tp->tm_mday >= 10) - { - if ((fp = popen(GE_10, "r")) == NULL) - { - perror("GE_10"); - return -1; - } - - } - else - { - if ((fp = popen(LE_10, "r")) == NULL) - { - perror("LE_10"); - return -1; - } - } - } - } - else if (CENTOS_SYSTEM == check_system()) // Centos 7系统规则 - { - if (tp->tm_mday >= 10) - { - if ((fp = popen(CENTOS_GE_10, "r")) == NULL) - { - perror("CENTOS_GE_10"); - return -1; - } - } - else - { - if ((fp = popen(CENTOS_LE_10, "r")) == NULL) - { - perror("CENTOS_LE_10"); - return -1; - } - } - - } - else - { - return UNKNOWN_SYSTEM; - } - - - splice_command = (char *)malloc(ip_length); - if (splice_command == NULL) { - free(splice_command); - return -1; - } - memset(splice_command, 0, ip_length); - - - - - while (fgets(buffer, BUFFER, fp) != NULL) - { - char *new_splice_command; - - - - - temp = strstr(buffer, "rhost"); - sscanf(temp, "rhost=%64s", temp); - if (atoi(strncpy(p_two, temp, 1)) > 0) - { - ip_length += _strlen(temp)+1; - - new_splice_command = (char *)realloc(splice_command, ip_length + 32); - if (new_splice_command == NULL) { - free(splice_command); - return -1; - } - splice_command = new_splice_command; - - //printf(RED"Hello World\n"COLOR_NONE); - printf(RED"%s Illegal IP: %s\n"COLOR_NONE, t, temp); - strcat(splice_command, temp); - strcat(splice_command, "\n"); - } - } - - - //printf("%s", splice_command); // 打印所有非法IP - //printf("%ld\n", ip_length); - - - - command = (char *)malloc(ip_length + BUFFER); - if (command == NULL) { - free(command); - return -1; - } - memset(command, 0, ip_length + BUFFER); - - - snprintf(awk, BUFFER, AWK, conf->REFUSE_NUMBER); // 拼接命令 - memcpy(command, "echo \"", 7); - strcat(command, splice_command); - strcat(command, "\""); - strcat(command, awk); - - - if ((fc = popen(command, "r")) == NULL) // 执行命令 - { - perror("popen command"); - return -1; - } - - if (splice_command != NULL) { - free(splice_command); - } - if (command != NULL) { - free(command); - } - - - while (fgets(buffer, BUFFER, fc) != NULL) // 执行命令后, 为空时就不会 - { - buffer[_strlen(buffer) - 1] = '\0'; // 去除回车 - - memset(REGION_LIST_COPY, 0, conf->REGION_LIST_LEN+1); - memset(IPV4_WHITE_LIST_COPY, 0, conf->IPV4_WHITE_LIST_LEN+1); - - memcpy(REGION_LIST_COPY, conf->REGION_LIST, conf->REGION_LIST_LEN); // 复制配置字符串,split_string()会改变原数据 - memcpy(IPV4_WHITE_LIST_COPY, conf->IPV4_WHITE_LIST, conf->IPV4_WHITE_LIST_LEN); // - - split_string(IPV4_WHITE_LIST_COPY, " ", whitelist_ip); - split_string(REGION_LIST_COPY, " ", region_list); - - - if (conf->IPV4_RESTRICTION == 1) // 是否启用白名单 - { - if (whitelist(buffer, whitelist_ip) == 1) - { - printf("%s 白名单IPV4:%s\n", t, buffer); - continue; - } - } - - if (0 != show_all_rule(buffer)) // libiptc库判断否存在规则 - { - char *location_json = NULL; - char *area = NULL; - char URL[conf->REGION_URL_LEN + 32]; - char *xdb_path = "ip2region.xdb"; - - - // 地域白名单 - if (conf->REGION == 1) - { - memset(URL, 0, conf->REGION_URL_LEN + 32); - snprintf(URL, conf->REGION_URL_LEN+32, conf->REGION_URL, buffer); - - - if (conf->IP2REGION == 1) { // ip2region 地址定位库 - printf("%s Use ip2region !!!\n", t); - - if (-1 == access(xdb_path, F_OK)) // 判断 ip2region 地址定位库是否存在 - { - xdb_path = "ip2region/ip2region.xdb"; - - if (-1 == access(xdb_path, F_OK)) { - printf("%s ip2region.xdb DOESN'T EXISIT!\n", t); - goto AREA; - } - } - - area = ip2region(xdb_path, buffer); - if (area == NULL) { - printf("%s ip2region解析地域错误\n", t); - goto BLOCKED; - } - } else { -AREA: - location_json = GET_PUBLIC_IP(URL); - if (location_json == NULL) { - printf("%s 获取地域错误\n", t); - goto BLOCKED; - } - - area = process_json(location_json, conf->REGION_URL); - if (area == NULL) { - printf("%s 解析地域错误\n", t); - goto BLOCKED; - } - } - - - if (isregion(area, region_list) == 1) { - printf(RED"%s Ip Address: %s, 地域白名单: %s\n"COLOR_NONE, t, buffer, area); - continue; - } - - } - - - printf(RED"%s 攻击者IP地址:%s, %s\n"COLOR_NONE, t, buffer, area); - - - if (conf->IS_DING_WEBHOOK == 1) // 钉钉告警 - { - dingding_warning(area, public_ip, buffer, conf); - sleep(3); - } - - if (conf->IS_MAIL == 1) // 邮件告警 - { - mail_warning(area, public_ip, buffer, conf); - sleep(3); - } - - if (conf->IS_QQMAIL == 1) // 邮件告警 - { - QQ_mail_warning(area, public_ip, buffer, conf); - sleep(3); - } - - -BLOCKED: - // 是否封禁攻击IP - if (conf->IS_BLOCKED == 1) - { - // libiptc 库插入规则 iptables -t filter -A INPUT -p tcp -m tcp -s xxxx -j DROP - unsigned int srcIp; - inet_pton(AF_INET, buffer, &srcIp); - iptc_add_rule("filter", "INPUT", IPPROTO_TCP, NULL, NULL, srcIp, 0, NULL, NULL, "DROP", NULL, 1); - } - - - if (location_json != NULL) - free(location_json); - if (area != NULL) - free(area); - } - - } - - if (fp != NULL) - pclose(fp); - - if (fc != NULL) - pclose(fc); - if (t) - free(t); - return 0; -} - -static void sig_child(int signo) -{ - pid_t pid; - int stat; - // 处理僵尸进程 - while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) ; - - return; -} - -static int get_executable_path(char *processdir, char *processname, int len) -{ - - char *processname_ptr; - - if (readlink("/proc/self/exe", processdir, len) <= 0) - return -1; - if ((processname_ptr = strrchr(processdir, '/')) == NULL) - return -1; - processname_ptr++; - strcpy(processname, processname_ptr); - *processname_ptr = '\0'; - - - return (int)(processname_ptr - processdir); -} - -// 处理参数 -int process_argv(int argc, char *argv[], char **argvs) -{ - argvs[0] = argv[0]; - int i; - int j; - for (i = 0; i <= argc - 1; i++) - { - if (i == 1) - { - for (j = i; j <= argc - 2; j++) - { - argvs[j] = argv[j + 1]; - } - } - } - - return 0; -} - -int _crontab(struct tm **calnext, char *string) -{ - const char *err = NULL; - time_t cur; - time_t datenext; - - time(&cur); - cron_expr parsed; - cron_parse_expr(string, &parsed, &err); - datenext = cron_next(&parsed, cur); - *calnext = localtime(&datenext); - assert(*calnext); - - return 0; -} - -static int get_clamav_log(char *file) -{ - FILE *fp = NULL; - char buffer[BUFFER], *temp=NULL, *command=NULL; - - command = (char *)alloca(BUFFER); - - memset(buffer, 0, BUFFER); - memset(command, 0, BUFFER); - - memcpy(command, "tail -n 12 ", 11); - strcat(command, file); - - fp = popen(command, "r"); - if (fp == NULL) { - perror("popen"); - return -1; - } - - while (fgets(buffer, BUFFER, fp) != NULL) - { - //printf("%s", buffer); - temp = strstr(buffer, "Infected"); - if (temp) - sscanf(temp, "Infected files: %32s", temp); - - if (temp != NULL) - { - //printf("%s\n", temp); - break; - } - } - - pclose(fp); - - if (temp != NULL) { - printf("%d\n", atoi(temp)); - return atoi(temp); - } - else - { - return -1; - } - - - return 0; -} - -int update_freshclam(int argc, char *argv[]) -{ - if (DEBISN_SYSTEM == check_system() || CENTOS_SYSTEM == check_system()) { - char **fre_argv; - int fre_argc = 0; - char *fre_argvss[ARGS_NUM] = { NULL }; - - fre_argvss[0] = argv[0]; - fre_argvss[1] = "--user=root"; - fre_argvss[2] = "--quiet"; - fre_argvss[3] = "--no-warnings"; - fre_argv = &(fre_argvss[0]); - fre_argc = 2; - - // freshclam配置文件 - if (access("/etc/clamav/freshclam.conf", F_OK) == -1) { - system("mkdir -p /etc/clamav/"); - system("cp freshclam.conf /etc/clamav/"); - } - - - // 打印clamav参数 - for(int i=0; i= conf->CLAMAV_ARG_LEN) - { - printf("\033[31mError reading configuration file, please check the configuration file!\033[0m\n"); - - exit(-1); - } - - // 更新病毒库 - update_freshclam(argc, argv); - - - // 创建移除目录 - if (conf->CLAMAV_ARG) - { - char temp[BUFFER]; - char *p, *p1; - - memset(temp, 0, BUFFER); - memset(move, 0, BUFFER); - - p = strstr(conf->CLAMAV_ARG, "--move="); - if (p != NULL) - { - p1 = strstr(p, " "); - - if ((p1-p) > 7) - { - memcpy(temp, p, p1-p); - p = strstr(temp, "="); - - strcpy(move, "mkdir -p "); - strcat(move, p+1); - - //printf("%s %ld \n", move, _strlen(move)); - - system(move); - } - } - } - - - // 处理clamav参数 - char **head_argvs; - int head_argc = 0; - char *argvs[ARGS_NUM] = { NULL }; - char args[ARGS_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } }; - //printf("%d\n", argc); - if (argc > 3) // 手动输入参数(如果手动输入参数个数大于3个, 则使用用户输入的参数) - { - process_argv(argc, argv, &(argvs[0])); - head_argvs = &(argvs[0]); // head_argvs指向argvs[0] - head_argc = argc - 1; // 改变argc数 - - } - else // 读取配置文件参数 - { - argvs[0] = argv[0]; - split_string(conf->CLAMAV_ARG, " ", args); - for (i=1; iPUBLIC_IP); - //printf("%s", public_ip); - - - if (0 == strcmp(conf->DAEMON, "on")) - { - goto goto_daemon; - } - - if (argv[1] != NULL && 0 == strcmp(argv[1], "-d")) - { -goto_daemon: - - -/* - if (daemon(1, 1)) // 守护进程 - { - perror("daemon"); - return -1; - } -*/ - - // 守护进程 - if ((pid = fork()) < 0) { - return 0; - } else if (0 != pid) { - for(i=1; iCLAMAV_TIME); - t->next_year = 1900 + calnext->tm_year; - t->next_mon = 1 + calnext->tm_mon; - t->next_day = calnext->tm_mday; - t->next_hour = calnext->tm_hour; - t->next_min = calnext->tm_min; - t->next_sec = calnext->tm_sec; - - // 取得现在时间 - time_t timep; - struct tm *p; - timep = time(NULL); - p = localtime(&timep); - t->now_year = 1900 + p->tm_year; - t->now_mon = 1 + p->tm_mon; - t->now_day = p->tm_mday; - t->now_hour = p->tm_hour; - t->now_min = p->tm_min; - t->now_sec = p->tm_sec; - - //printf("当前时间 %d%d%d %d:%d:%d\n", t->now_year, t->now_mon, t->now_day, t->now_hour, t->now_min, t->now_sec); - //printf("CRON %d%d%d %d:%d:%d\n", t->next_year, t->next_mon, t->next_day, t->next_hour, t->next_min, t->next_sec); - - // Clamav call - if (1 == conf->CLAMAV) - { - if ( t->now_year == t->next_year && t->now_mon == t->next_mon && t->now_day == t->next_day && t->now_hour == t->next_hour && t->now_min == t->next_min ) - { - //printf("%d%d%d %d:%d:%d\n", t->now_year, t->now_mon, t->now_day, t->now_hour, t->now_min, t->now_sec); - //printf("%d%d%d %d:%d:%d\n", t->next_year, t->next_mon, t->next_day, t->next_hour, t->next_min, t->next_sec); - - pid_t pid; - pid = fork(); - if (pid < 0) { - printf("fork error.\n"); - return -1; - } - else if (pid == 0) // child process - { - int r = 0; - int virus_files = -1; - - // 扫描病毒前,更新病毒库 - update_freshclam(argc, argv); - - r = _clamscan(head_argc, head_argvs); - virus_files = get_clamav_log("clamscan.log"); - - if (virus_files > 0) { - if (conf->IS_QQMAIL == 1) - { - QQ_mail_warning_Virus_files(public_ip, virus_files, conf); - sleep(3); - } - } - - - // 磁盘告警 - if (1 == conf->IS_DISK) - { - if (disk_waring(conf->DISK_USE) == 1) - { - printf("Disk usage reaches threshold!, Please handle!\n"); - if (conf->IS_QQMAIL == 1) - { - QQ_mail_warning_Disk_Use(public_ip, 0, conf); - sleep(3); - } - } - else - { - printf("Disk usage does not reach threshold!\n"); - } - } - - _exit(r); - } - else - { - int status = 0; - wait(&status); // wait the end of child process - if (WIFEXITED(status)) - { - ; - //printf("child process return %d\n", WEXITSTATUS(status)); - } - - sleep(60); // 跳过这一分钟 - } - } - } - - - rule(conf); - sleep(conf->TIME); - } - } - else - { - - rule(conf); - } - - free(t); - free_conf(conf); - free(conf); - free(public_ip); - for(i=1; imemory, mem->size + realsize + 1); + if (ptr == NULL) { + /* 内存不足! */ + printf("not enough memory (realloc returned NULL)\n"); + return 0; + } + + mem->memory = ptr; + memcpy(&(mem->memory[mem->size]), contents, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + + return realsize; +} + +// 获取公网IP +static char *GET_PUBLIC_IP(char *URL) +{ + CURL *curl_handle; + CURLcode res; + + struct curl_slist *headers = NULL; + struct MemoryStruct chunk; + + chunk.memory = malloc(1); /* 将根据上述再分配的需要增长 */ + chunk.size = 0; /* 此时没有数据 */ + + curl_global_init(CURL_GLOBAL_ALL); + + /* 初始化curl会话 */ + curl_handle = curl_easy_init(); + + char *p = NULL; + char *buff; + + p = strstr(URL, "-H"); + if (p) { + + buff = (char *)alloca(p - URL + 1); + if (buff == NULL) + perror("out of memory."); + + memset(buff, 0, p - URL + 1); + memcpy(buff, URL, (int)(p - URL - 1)); + + // 赋值header值 + headers = curl_slist_append(headers, p + 3); + + // 设置header + curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl_handle, CURLOPT_URL, buff); + + } else { + /* 指定要获取的URL */ + curl_easy_setopt(curl_handle, CURLOPT_URL, URL); + + } + + /* 将所有数据发送到此函数 */ + //对于同一次阻塞的curl_easy_perform而言,在写完获取的数据之前,会多次调用 WriteMemoryCallback + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); + + /* 将"chunk"结构传递给回调函数 */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); + + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + //对于同一次阻塞的curl_easy_perform而言,在写完获取的数据之前,会多次调用 WriteMemoryCallback + res = curl_easy_perform(curl_handle); + + if (res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } else { + //printf("%lu bytes retrieved\n", (unsigned long)chunk.size); + //printf("%s", chunk.memory); + ; + } + + curl_easy_cleanup(curl_handle); + curl_global_cleanup(); + + return chunk.memory; +} + +// 解析Json +char *process_json(char *buff, char *api) +{ + char *area = NULL; + int area_len = 0; + char *p = NULL; + + if (buff == NULL) { + return NULL; + } + + cJSON *cjson_init = cJSON_Parse(buff); + if (cjson_init == NULL) { + perror("cJSON_Parse"); + return NULL; + } + if ((p = strstr(api, "baidu")) != NULL) { // baidu Api + int i; + + cJSON *data = cJSON_GetObjectItem(cjson_init, "data"); + if (data != NULL) { + for (i = 0; i < cJSON_GetArraySize(data); i++) { + cJSON *svalue = cJSON_GetArrayItem(data, i); + cJSON *location = cJSON_GetObjectItem(svalue, "location"); + area_len = _strlen(location->valuestring); + + area = (char *)alloca(area_len + 1); + if (area == NULL) + perror("out of memory."); + memset(area, 0, area_len + 1); + + snprintf(area, area_len + 1, "%s", location->valuestring); + } + + } else { + return NULL; + } + } else { + cJSON_Delete(cjson_init); + return NULL; + } + + cJSON_Delete(cjson_init); + return strdup(area); +} + +// 检测系统 +int check_system() +{ + if (0 == access("/etc/debian_version", F_OK)) { + return DEBISN_SYSTEM; + } else if (0 == access("/etc/centos-release", F_OK)) { + return CENTOS_SYSTEM; + } + + return UNKNOWN_SYSTEM; +} + +// 钉钉告警 +int dingding_warning(char *illegal_ip, char *public_ip, char *ip, conf *conf) +{ + FILE *fp; + char temp[64]; + char jsonObj[BUFFER]; + + memset(jsonObj, 0, BUFFER); + memset(temp, 0, 64); + strcpy(temp, public_ip); + temp[_strlen(public_ip) - 1] = '\0'; + + if ((fp = fopen("libcurl.log", "wt+")) == NULL) { + return 1; + } + + CURL *curl; + CURLcode res; + + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if (curl == NULL) { + fclose(fp); + return 1; + } +#define JSIN "{ \ + \"msgtype\": \"text\", \ + \"text\": { \ + \"content\": \"Alert @%s 服务器地址:%s,封禁非法入侵主机:(%s%s)\" \ + }, \ + \"at\": { \ + \"atMobiles\": [\"%s\"], \ + \"isAtAll\": false \ + } \ + }" + + snprintf(jsonObj, BUFFER, JSIN, conf->PHONE, temp, ip, illegal_ip, conf->PHONE); + printf("%s\n", jsonObj); + + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, "Accept: application/json"); + headers = curl_slist_append(headers, "Content-Type: application/json"); + headers = curl_slist_append(headers, "charset: utf-8"); + + curl_easy_setopt(curl, CURLOPT_URL, conf->DING_WEBHOOK); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj); + curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl/0.1"); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + curl_global_cleanup(); + fclose(fp); + + return res; +} + +// 邮件告警 +int mail_warning(char *illegal_ip, char *public_ip, char *ip, conf *conf) +{ + FILE *fp = NULL; + char buff[BUFFER]; + char text[BUFFER]; + char temp[64]; + + memset(buff, 0, BUFFER); + memset(text, 0, BUFFER); + memset(temp, 0, 64); + + strcpy(temp, public_ip); + temp[_strlen(public_ip) - 1] = '\0'; + snprintf(text, BUFFER, "echo \"主机:%s, 禁止(%s%s)访问\" | mail -s \"System ban IP\" %s", temp, ip, illegal_ip, conf->RECV_MAIL); + + if (NULL == (fp = popen(text, "r"))) { + perror("popen text"); + } + + while (fgets(buff, BUFFER, fp) != NULL) { + buff[_strlen(buff) - 1] = '\0'; + } + + if (NULL != fp) + pclose(fp); + + return 0; +} + +// 第三方邮箱告警 +int QQ_mail_warning(char *illegal_ip, char *public_ip, char *ip, conf *conf) +{ + char string[BUFFER + (sizeof(QQMAIL)) + 1]; + char text[BUFFER]; + char temp[32]; + + memset(string, 0, BUFFER + (sizeof(QQMAIL)) + 1); + memset(text, 0, BUFFER); + memset(temp, 0, 32); + + strcpy(temp, public_ip); + temp[_strlen(public_ip) - 1] = '\0'; + + snprintf(text, BUFFER, "主机:%s, 禁止(%s%s)访问!", temp, ip, illegal_ip); + snprintf(string, BUFFER + (sizeof(QQMAIL)) + 1, QQMAIL, conf->RECV_MAIL, text); + + return system(string); +} + +// 第三方邮箱告警, 感染病毒邮件提醒 +int QQ_mail_warning_Virus_files(char *local_ip, int Virus_number, conf *conf) +{ + char *command; + char *text; + char temp[32]; + + command = (char *)alloca(BUFFER + (sizeof(QQMAIL)) + 1); + text = (char *)alloca(BUFFER); + + memset(command, 0, BUFFER + (sizeof(QQMAIL)) + 1); + memset(text, 0, BUFFER); + memset(temp, 0, 32); + + strcpy(temp, local_ip); + temp[_strlen(local_ip) - 1] = '\0'; + + snprintf(text, BUFFER, "Host:%s, Infected files: %d, Please handle!", temp, Virus_number); + snprintf(command, BUFFER + BUFFER + (sizeof(QQMAIL)) + 1, QQMAIL_Virus, conf->RECV_MAIL, text); + + return system(command); +} + +// 第三方邮箱告警, 磁盘使用率 +int QQ_mail_warning_Disk_Use(char *local_ip, int disk_use, conf *conf) +{ + char *command; + char *text; + char temp[32]; + + command = (char *)alloca(BUFFER + (sizeof(QQMAIL)) + 1); + text = (char *)alloca(BUFFER); + + memset(command, 0, BUFFER + (sizeof(QQMAIL)) + 1); + memset(text, 0, BUFFER); + memset(temp, 0, 32); + + strcpy(temp, local_ip); + temp[_strlen(local_ip) - 1] = '\0'; + + snprintf(text, BUFFER, "Host:%s, Disk usage reaches threshold!, Please handle!", temp); + snprintf(command, BUFFER, QQMAIL_DISK_USE, conf->RECV_MAIL, text); + + return system(command); +} + +// IP段白名单对比 +int whitelist(char *client_ip, char (*whitelist_ip)[WHITELIST_IP_NUM]) +{ + int i; + + for (i = 1; i < WHITELIST_IP_NUM - 1; i++) { + if (strcmp(whitelist_ip[i], "\0") == 0) // 如果字符串为空就跳出循环 + { + break; + } + if ((strncmp(client_ip, whitelist_ip[i], _strlen(whitelist_ip[i]))) == 0) // 对比client_ip长度, + { + return 1; + } + } + + return 0; +} + +// 地域段白名单对比 +int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM]) +{ + int i; + char *p; + + for (i = 1; i < WHITELIST_IP_NUM - 1; i++) { + if (strcmp(region_list[i], "\0") == 0) // 如果字符串为空就跳出循环 + { + break; + } + //printf("%s %s\n", str, region_list[i]); + // 在str中查找region_list[i] + p = strstr(str, region_list[i]); + if (p != NULL) { + return 1; + } + } + + return 0; +} + +// 去除空格 +char *remove_space(char *str) +{ + unsigned int i = 0, j = 0; + unsigned int uLen = _strlen(str); + char *strRet; + + if (0 == uLen) { + return '\0'; + } + + strRet = (char *)malloc(uLen + 2); + memset(strRet, 0, uLen + 2); + + for (i = 0; i < uLen; i++) { + if (str[i] != ' ') { + strRet[j++] = str[i]; + } + } + strRet[j] = '\0'; + + return strRet; +} + +// 磁盘使用率 +int disk_waring(int threshold) +{ + FILE *fp = NULL; + char buffer[BUFFER]; + char command[BUFFER]; + int is = 0; + +#define DF "for u in `df -mh | grep -E -e \".:.\" -e \"^/dev\" | awk '{print $5}' | sed 's|%%||g'`; do if test \"$u\" -ge %d; then echo \"$u\"; fi done" + + memset(buffer, 0, BUFFER); + memset(command, 0, BUFFER); + + snprintf(command, BUFFER, DF, threshold); + + //printf("%s\n", command); + fp = popen(command, "r"); + + while (fgets(buffer, BUFFER, fp) != NULL) { + printf("%s", buffer); + is = 1; + break; + } + pclose(fp); + + return is; +} + +char *_time() +{ + char temp[BUFFER]; + char *wday[] = { "0", "1", "2", "3", "4", "5", "6" }; + time_t t; + struct tm *p; + time(&t); + p = localtime(&t); // 取得当地时间 + + memset(temp, 0, BUFFER); + snprintf(temp, BUFFER, "[%d/%02d/%02d %s %02d:%02d:%02d] ", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec); + + return strdup(temp); +} + +// 封禁非法IP +int rule(conf *conf) +{ + char whitelist_ip[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } }; + char region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } }; + + char REGION_LIST_COPY[conf->REGION_LIST_LEN + 1]; + char IPV4_WHITE_LIST_COPY[conf->IPV4_WHITE_LIST_LEN + 1]; + + char p_two[2], *command, *splice_command, *temp, buffer[BUFFER], awk[BUFFER]; + FILE *fp, *fc; + time_t timep; + struct tm *tp; + long int ip_length = 1; + + fp = NULL; + fc = NULL; + timep = time(NULL); + tp = localtime(&timep); + memset(buffer, 0, BUFFER); + memset(awk, 0, BUFFER); + memset(p_two, 0, 2); + + char *t = NULL; + t = _time(); + + if (DEBISN_SYSTEM == check_system()) // Debian 系统规则 + { + if (tp->tm_mday >= 10) { + if ((fp = popen(GE_10, "r")) == NULL) { + perror("GE_10"); + return -1; + } + } else { + if ((fp = popen(LE_10, "r")) == NULL) { + perror("LE_10"); + return -1; + } + } + } else if (CENTOS_SYSTEM == check_system()) // Centos 7系统规则 + { + if (tp->tm_mday >= 10) { + if ((fp = popen(CENTOS_GE_10, "r")) == NULL) { + perror("CENTOS_GE_10"); + return -1; + } + } else { + if ((fp = popen(CENTOS_LE_10, "r")) == NULL) { + perror("CENTOS_LE_10"); + return -1; + } + } + + } else { + return UNKNOWN_SYSTEM; + } + + splice_command = (char *)malloc(ip_length); + if (splice_command == NULL) { + free(splice_command); + return -1; + } + memset(splice_command, 0, ip_length); + + while (fgets(buffer, BUFFER, fp) != NULL) { + char *new_splice_command; + + temp = strstr(buffer, "rhost"); + sscanf(temp, "rhost=%64s", temp); + if (atoi(strncpy(p_two, temp, 1)) > 0) { + ip_length += _strlen(temp) + 1; + + new_splice_command = (char *)realloc(splice_command, ip_length + 32); + if (new_splice_command == NULL) { + free(splice_command); + return -1; + } + splice_command = new_splice_command; + + //printf(RED"Hello World\n"COLOR_NONE); + printf(RED "%s Illegal IP: %s\n" COLOR_NONE, t, temp); + strcat(splice_command, temp); + strcat(splice_command, "\n"); + } + } + + //printf("%s", splice_command); // 打印所有非法IP + //printf("%ld\n", ip_length); + + command = (char *)malloc(ip_length + BUFFER); + if (command == NULL) { + free(command); + return -1; + } + memset(command, 0, ip_length + BUFFER); + + snprintf(awk, BUFFER, AWK, conf->REFUSE_NUMBER); // 拼接命令 + memcpy(command, "echo \"", 7); + strcat(command, splice_command); + strcat(command, "\""); + strcat(command, awk); + + if ((fc = popen(command, "r")) == NULL) // 执行命令 + { + perror("popen command"); + return -1; + } + + if (splice_command != NULL) { + free(splice_command); + } + if (command != NULL) { + free(command); + } + + while (fgets(buffer, BUFFER, fc) != NULL) // 执行命令后, 为空时就不会 + { + buffer[_strlen(buffer) - 1] = '\0'; // 去除回车 + + memset(REGION_LIST_COPY, 0, conf->REGION_LIST_LEN + 1); + memset(IPV4_WHITE_LIST_COPY, 0, conf->IPV4_WHITE_LIST_LEN + 1); + + memcpy(REGION_LIST_COPY, conf->REGION_LIST, conf->REGION_LIST_LEN); // 复制配置字符串,split_string()会改变原数据 + memcpy(IPV4_WHITE_LIST_COPY, conf->IPV4_WHITE_LIST, conf->IPV4_WHITE_LIST_LEN); // + + split_string(IPV4_WHITE_LIST_COPY, " ", whitelist_ip); + split_string(REGION_LIST_COPY, " ", region_list); + + if (conf->IPV4_RESTRICTION == 1) // 是否启用白名单 + { + if (whitelist(buffer, whitelist_ip) == 1) { + printf("%s 白名单IPV4:%s\n", t, buffer); + continue; + } + } + + if (0 != show_all_rule(buffer)) // libiptc库判断否存在规则 + { + char *location_json = NULL; + char *area = NULL; + char URL[conf->REGION_URL_LEN + 32]; + char *xdb_path = "ip2region.xdb"; + + // 地域白名单 + if (conf->REGION == 1) { + memset(URL, 0, conf->REGION_URL_LEN + 32); + snprintf(URL, conf->REGION_URL_LEN + 32, conf->REGION_URL, buffer); + + if (conf->IP2REGION == 1) { // ip2region 地址定位库 + printf("%s Use ip2region !!!\n", t); + + if (-1 == access(xdb_path, F_OK)) // 判断 ip2region 地址定位库是否存在 + { + xdb_path = "ip2region/ip2region.xdb"; + + if (-1 == access(xdb_path, F_OK)) { + printf("%s ip2region.xdb DOESN'T EXISIT!\n", t); + goto AREA; + } + } + + area = ip2region(xdb_path, buffer); + if (area == NULL) { + printf("%s ip2region解析地域错误\n", t); + goto BLOCKED; + } + } else { +AREA: + location_json = GET_PUBLIC_IP(URL); + if (location_json == NULL) { + printf("%s 获取地域错误\n", t); + goto BLOCKED; + } + + area = process_json(location_json, conf->REGION_URL); + if (area == NULL) { + printf("%s 解析地域错误\n", t); + goto BLOCKED; + } + } + + if (isregion(area, region_list) == 1) { + printf(RED "%s Ip Address: %s, 地域白名单: %s\n" COLOR_NONE, t, buffer, area); + continue; + } + + } + + printf(RED "%s 攻击者IP地址:%s, %s\n" COLOR_NONE, t, buffer, area); + + if (conf->IS_DING_WEBHOOK == 1) // 钉钉告警 + { + dingding_warning(area, public_ip, buffer, conf); + sleep(3); + } + + if (conf->IS_MAIL == 1) // 邮件告警 + { + mail_warning(area, public_ip, buffer, conf); + sleep(3); + } + + if (conf->IS_QQMAIL == 1) // 邮件告警 + { + QQ_mail_warning(area, public_ip, buffer, conf); + sleep(3); + } + +BLOCKED: + // 是否封禁攻击IP + if (conf->IS_BLOCKED == 1) { + // libiptc 库插入规则 + // iptables -t filter -A INPUT -p tcp -m tcp -s 47.110.180.35 -j DROP + // iptables -t filter -D INPUT -p tcp -m tcp -s 47.110.180.35 -j DROP + unsigned int srcIp; + inet_pton(AF_INET, buffer, &srcIp); + iptc_add_rule("filter", "INPUT", IPPROTO_TCP, NULL, NULL, srcIp, 0, NULL, NULL, "DROP", NULL, 1); + } + + if (location_json != NULL) + free(location_json); + if (area != NULL) + free(area); + } + + } + + if (fp != NULL) + pclose(fp); + + if (fc != NULL) + pclose(fc); + if (t) + free(t); + return 0; +} + +static void sig_child(int signo) +{ + pid_t pid; + int stat; + // 处理僵尸进程 + while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) ; + + return; +} + +static int get_executable_path(char *processdir, char *processname, int len) +{ + + char *processname_ptr; + + if (readlink("/proc/self/exe", processdir, len) <= 0) + return -1; + if ((processname_ptr = strrchr(processdir, '/')) == NULL) + return -1; + processname_ptr++; + strcpy(processname, processname_ptr); + *processname_ptr = '\0'; + + return (int)(processname_ptr - processdir); +} + +// 处理参数 +int process_argv(int argc, char *argv[], char **argvs) +{ + argvs[0] = argv[0]; + int i; + int j; + for (i = 0; i <= argc - 1; i++) { + if (i == 1) { + for (j = i; j <= argc - 2; j++) { + argvs[j] = argv[j + 1]; + } + } + } + + return 0; +} + +int _crontab(struct tm **calnext, char *string) +{ + const char *err = NULL; + time_t cur; + time_t datenext; + + time(&cur); + cron_expr parsed; + cron_parse_expr(string, &parsed, &err); + datenext = cron_next(&parsed, cur); + *calnext = localtime(&datenext); + assert(*calnext); + + return 0; +} + +static int get_clamav_log(char *file) +{ + FILE *fp = NULL; + char buffer[BUFFER], *temp = NULL, *command = NULL; + + command = (char *)alloca(BUFFER); + + memset(buffer, 0, BUFFER); + memset(command, 0, BUFFER); + + memcpy(command, "tail -n 12 ", 11); + strcat(command, file); + + fp = popen(command, "r"); + if (fp == NULL) { + perror("popen"); + return -1; + } + + while (fgets(buffer, BUFFER, fp) != NULL) { + //printf("%s", buffer); + temp = strstr(buffer, "Infected"); + if (temp) + sscanf(temp, "Infected files: %32s", temp); + + if (temp != NULL) { + //printf("%s\n", temp); + break; + } + } + + pclose(fp); + + if (temp != NULL) { + printf("%d\n", atoi(temp)); + return atoi(temp); + } else { + return -1; + } + + return 0; +} + +int update_freshclam(int argc, char *argv[]) +{ + if (DEBISN_SYSTEM == check_system() || CENTOS_SYSTEM == check_system()) { + char **fre_argv; + int fre_argc = 0; + char *fre_argvss[ARGS_NUM] = { NULL }; + + fre_argvss[0] = argv[0]; + fre_argvss[1] = "--user=root"; + fre_argvss[2] = "--quiet"; + fre_argvss[3] = "--no-warnings"; + fre_argv = &(fre_argvss[0]); + fre_argc = 2; + + // freshclam配置文件 + if (access("/etc/clamav/freshclam.conf", F_OK) == -1) { + system("mkdir -p /etc/clamav/"); + system("cp freshclam.conf /etc/clamav/"); + } + + // 打印clamav参数 + for (int i = 0; i < fre_argc; i++) { + printf("%s %d\n", fre_argv[i], i); + } + + pid_t pid; + pid = fork(); + if (pid < 0) { + printf("fork error.\n"); + return -1; + } else if (pid == 0) // child process + { + int r = 0; + r = _freshclam(fre_argc, fre_argv); + _exit(r); + } else { + int status = 0; + wait(&status); // wait the end of child process + if (WIFEXITED(status)) { + ; + printf("child process return %d\n", WEXITSTATUS(status)); + } + + sleep(3); + return 0; + } + + } + + return -1; +} + +static char help_information(void) +{ + static const char name[] = "Rhost"; + static const char subject[] = "Reject host&scan for viruses (Rhost 拒绝主机并扫描病毒)"; + static const struct { + const char *email; + const char *version; + } author = { + "AIXIAO@AIXIAO.ME", + "1.0", + }; + + static const char usage[] = "Usage: [-?h] [-d]"; + static const char *s_help[] = { + "", + "Options:", + " -d : Background running", + " -? -h --help : help information", + " The configuration file needs to be in the same directory as the executable file!", + " 配置文件需要与可执行文件位于同一目录中!", + "", + "", + 0 + }; + + fprintf(stderr, " %s %s\n", name, subject); + fprintf(stderr, "Author: %s\n", author.email); + fprintf(stderr, "Version: %s\n", author.version); + fprintf(stderr, "%s\n", usage); + + int l; + for (l = 0; s_help[l]; l++) { + fprintf(stderr, "%s\n", s_help[l]); + } + + BUILD("Compile、link.\n"); + puts(""); + + return 0; +} + +int main(int argc, char *argv[], char **env) +{ + + signal(SIGCHLD, sig_child); // 创建捕捉子进程退出信号 + + int pid; + int i; + char move[BUFFER]; + + // 读取配置 + char path[BUFFER] = { 0 }; + char executable_filename[BUFFER] = { 0 }; + (void)get_executable_path(path, executable_filename, sizeof(path)); + strcat(executable_filename, ".conf"); + strcat(path, executable_filename); + + if (NULL != argv[1]) { + if (0 == strcmp(argv[1], "-v") || 0 == strcmp(argv[1], "--version") || 0 == strcmp(argv[1], "-h") || 0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-?")) { + help_information(); + exit(0); + } + } + + if (1 == access(path, F_OK)) { + printf("配置文件不存在!\n"); + } + conf *conf = (struct CONF *)malloc(sizeof(struct CONF)); + read_conf(path, conf); + //ptintf_conf(conf); + + if (0 >= conf->CLAMAV_ARG_LEN) { + printf("\033[31mError reading configuration file, please check the configuration file!\033[0m\n"); + + exit(-1); + } + // 更新病毒库 + update_freshclam(argc, argv); + + // 创建移除目录 + if (conf->CLAMAV_ARG) { + char temp[BUFFER]; + char *p, *p1; + + memset(temp, 0, BUFFER); + memset(move, 0, BUFFER); + + p = strstr(conf->CLAMAV_ARG, "--move="); + if (p != NULL) { + p1 = strstr(p, " "); + + if ((p1 - p) > 7) { + memcpy(temp, p, p1 - p); + p = strstr(temp, "="); + + strcpy(move, "mkdir -p "); + strcat(move, p + 1); + + //printf("%s %ld \n", move, _strlen(move)); + + system(move); + } + } + } + + // 处理clamav参数 + char **head_argvs; + int head_argc = 0; + char *argvs[ARGS_NUM] = { NULL }; + char args[ARGS_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } }; + //printf("%d\n", argc); + if (argc > 3) // 手动输入参数(如果手动输入参数个数大于3个, 则使用用户输入的参数) + { + process_argv(argc, argv, &(argvs[0])); + head_argvs = &(argvs[0]); // head_argvs指向argvs[0] + head_argc = argc - 1; // 改变argc数 + + } else // 读取配置文件参数 + { + argvs[0] = argv[0]; + split_string(conf->CLAMAV_ARG, " ", args); + for (i = 1; i < ARGS_NUM; i++) { + if (args[i][0] == '\0') { + continue; + } else { + argvs[i] = strdup(args[i]); + head_argc++; + } + } + + head_argvs = &(argvs[0]); + head_argc += 1; + } + + /* + // 打印clamav参数 + for(int i=0; iPUBLIC_IP); + //printf("%s", public_ip); + + if (0 == strcmp(conf->DAEMON, "on")) { + goto goto_daemon; + } + + if (argv[1] != NULL && 0 == strcmp(argv[1], "-d")) { +goto_daemon: + + // 守护进程 + if ((pid = fork()) < 0) { + return 0; + } else if (0 != pid) { + for (i = 1; i < head_argc; i++) { + if (head_argvs[i]) + free(head_argvs[i]); + } + free(t); + free_conf(conf); + free(conf); + free(public_ip); + exit(0); + } + + if (setsid() < 0) { + return 0; + } + + signal(SIGHUP, SIG_IGN); + if ((pid = fork()) < 0) { + return 0; + } else if (0 != pid) { + for (i = 1; i < head_argc; i++) { + if (head_argvs[i]) + free(head_argvs[i]); + } + free(t); + free_conf(conf); + free(conf); + free(public_ip); + exit(0); + } + + if (-1 == (nice(-20))) // 进程优先级 + perror("nice"); + + pid_t pid; + + // 创建一个新进程 + pid = fork(); + + if (pid < 0) { + // fork 失败 + fprintf(stderr, "Fork 失败\n"); + return 1; + } else if (pid == 0) { + // 子进程 + while (1) { + // Cron + struct tm *calnext; //取得Cron规则时间 + calnext = (struct tm *)malloc(sizeof(struct tm)); + memset(calnext, 0, sizeof(struct tm)); + _crontab(&calnext, conf->CLAMAV_TIME); + t->next_year = 1900 + calnext->tm_year; + t->next_mon = 1 + calnext->tm_mon; + t->next_day = calnext->tm_mday; + t->next_hour = calnext->tm_hour; + t->next_min = calnext->tm_min; + t->next_sec = calnext->tm_sec; + + // 取得现在时间 + time_t timep; + struct tm *p; + timep = time(NULL); + p = localtime(&timep); + t->now_year = 1900 + p->tm_year; + t->now_mon = 1 + p->tm_mon; + t->now_day = p->tm_mday; + t->now_hour = p->tm_hour; + t->now_min = p->tm_min; + t->now_sec = p->tm_sec; + + //printf("当前时间 %d%d%d %d:%d:%d\n", t->now_year, t->now_mon, t->now_day, t->now_hour, t->now_min, t->now_sec); + //printf("CRON %d%d%d %d:%d:%d\n", t->next_year, t->next_mon, t->next_day, t->next_hour, t->next_min, t->next_sec); + + // Clamav call + if (1 == conf->CLAMAV) { + if (t->now_year == t->next_year && t->now_mon == t->next_mon && t->now_day == t->next_day && t->now_hour == t->next_hour && t->now_min == t->next_min) { + //printf("%d%d%d %d:%d:%d\n", t->now_year, t->now_mon, t->now_day, t->now_hour, t->now_min, t->now_sec); + //printf("%d%d%d %d:%d:%d\n", t->next_year, t->next_mon, t->next_day, t->next_hour, t->next_min, t->next_sec); + + pid_t pid; + pid = fork(); + if (pid < 0) { + printf("fork error.\n"); + return -1; + } else if (pid == 0) // child process + { + int r = 0; + int virus_files = -1; + + // 扫描病毒前,更新病毒库 + update_freshclam(argc, argv); + + r = _clamscan(head_argc, head_argvs); + virus_files = get_clamav_log("clamscan.log"); + + if (virus_files > 0) { + if (conf->IS_QQMAIL == 1) { + QQ_mail_warning_Virus_files(public_ip, virus_files, conf); + sleep(3); + } + } + + // 磁盘告警 + if (1 == conf->IS_DISK) { + if (disk_waring(conf->DISK_USE) == 1) { + printf("Disk usage reaches threshold!, Please handle!\n"); + if (conf->IS_QQMAIL == 1) { + QQ_mail_warning_Disk_Use(public_ip, 0, conf); + sleep(3); + } + } else { + printf("Disk usage does not reach threshold!\n"); + } + } + + _exit(r); + } else { + int status = 0; + wait(&status); // wait the end of child process + if (WIFEXITED(status)) { + ; + //printf("child process return %d\n", WEXITSTATUS(status)); + } + + sleep(60); // 跳过这一分钟 + } + } + } + + rule(conf); + sleep(conf->TIME); + } + } else { + // 父进程 + + while(1) + { + nginx_read_log("/usr/local/nginx/logs/access.log"); + + sleep(1); + } + } + } else { + ; + } + + free(t); + free_conf(conf); + free(conf); + free(public_ip); + for (i = 1; i < head_argc; i++) { + if (head_argvs[i]) + free(head_argvs[i]); + + } + + return 0; +} diff --git a/rhost.conf b/rhost.conf index 9a8e828..8cc3011 100644 --- a/rhost.conf +++ b/rhost.conf @@ -13,7 +13,7 @@ global { REFUSE_NUMBER = 3; // 拒绝攻击次数 CLAMAV = 1; // clamav 是否扫描病毒(1开启,非1关闭) - CLAMAV_ARG = "-r / --exclude-dir=^/sys|^/dev|^/proc|^/opt/infected --move=/opt/infected --max-filesize 1024M -l clamscan.log"; + CLAMAV_ARG = "-r / --exclude-dir=^/sys|^/dev|^/proc|^/opt/infected|^/root|^/home|^/mnt|^/usr|^/var --move=/opt/infected --max-filesize 1024M -l clamscan.log"; CLAMAV_TIME = "* 7 23 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周) @@ -23,18 +23,17 @@ global { REGION = 1; // 是否启用地域白名单(1开启,非1关闭) IP2REGION = 1; // 是否使用本地 ip2region 地址定位库(1使用,非1不使用) - REGION_URL = "http://opendata.baidu.com/api.php?query=%s&co=&resource_id=6006&oe=utf8"; // 获取IP地域API REGION_LIST = "河南 郑州 上海"; // 地域列表(空格隔开) IS_MAIL = 0; // 开启邮件告警(1开启,非1关闭) - IS_DING_WEBHOOK = 0; // 开启叮叮告警(1开启,非1关闭) + IS_DING_WEBHOOK = 1; // 开启叮叮告警(1开启,非1关闭) PHONE = "15565979082"; // @的人手机号 - DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=7f069c672cb878987aa6772cca336740eece4ce36bde12b51b45e9f440e0565a"; // 钉钉WEBHOOK + DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=396bce0384cded025087cff3c176ea5e9afb9bd8fcaa46d6fa8c51dd172ba513"; // 钉钉WEBHOOK - IS_QQMAIL = 1; // 开启QQ邮箱告警(默认使用gomail:https://git.aixiao.me/aixiao/gomail.git)(1开启,非1关闭) + IS_QQMAIL = 1; // 开启QQ邮箱告警(默认使用gomail: https://git.aixiao.me/aixiao/gomail.git)(1开启,非1关闭) RECV_MAIL = "1605227279@qq.com"; // 接收者邮箱 } diff --git a/rhost.h b/rhost.h index 393db05..950dee2 100644 --- a/rhost.h +++ b/rhost.h @@ -107,9 +107,7 @@ void cron_free(void* p) #define BUILD(fmt...) do { fprintf(stderr,"%s %s ",__DATE__,__TIME__); fprintf(stderr, ##fmt); } while(0) #define AWK " | awk -v num=%d '{a[$1]+=1;} END {for(i in a){if (a[i] >= num) {print i;}}}' " - #define GE_10 "grep -E \"^$(LC_ALL=\"C\" date \"+%h\").$(LC_ALL=\"C\" date \"+%d\")\" /var/log/auth.log | grep failure | grep rhost" -#define GE_12 "grep -E \"^$(LC_ALL=\"C\" date +\"%Y-%m-%d\")\" /var/log/auth.log | grep failure | grep rhost" #define LE_10 "grep -E \"^$(LC_ALL=\"C\" date \"+%h\")..$(LC_ALL=\"C\" date | awk '{print $3}')\" /var/log/auth.log | grep failure | grep rhost" #define CENTOS_GE_10 "grep -E \"^$(LC_ALL=\"C\" date \"+%h\").$(LC_ALL=\"C\" date \"+%d\")\" /var/log/secure | grep failure | grep rhost" From 778c9d5fff7884b8327bf99125e78a375c1d0439 Mon Sep 17 00:00:00 2001 From: aixiao Date: Tue, 21 May 2024 15:28:20 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0Nginx=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 10 +++++ Makefile | 4 +- clamav/libclamav_rust/.rustc_info.json | 2 +- conf.c | 29 ++++++++++++++ conf.h | 7 ++++ nginx.c | 39 ++++++++++++------- nginx.h | 6 ++- rhost.c | 49 +++++++++++++++++++++--- rhost.conf | 8 ++++ rhost.h | 53 ++------------------------ 10 files changed, 135 insertions(+), 72 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..91a46bb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "files.associations": { + "assert.h": "c", + "ip2region.h": "c", + "conf.h": "c", + "ccronexpr.h": "c", + "clamscan.h": "c", + "libiptc.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 1aaca5f..bdf67b6 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ LIBCOMMON__CFLAGS += -DHAVE_CONFIG_H -I./clamav/common -I./clamav/libclamav -I./ LIBCOMMON_LIB += ./clamav/common/cert_util.c.o ./clamav/common/actions.c.o ./clamav/common/clamdcom.c.o ./clamav/common/getopt.c.o ./clamav/common/hostid.c.o ./clamav/common/idmef_logging.c.o ./clamav/common/misc.c.o ./clamav/common/optparser.c.o ./clamav/common/output.c.o ./clamav/common/tar.c.o ./clamav/common/linux/cert_util_linux.c.o -all: libclamav_rust libclamav rhost +all: libclamav_rust libclamav rhost nginx.o rhost: conf.o rhost.o libiptc.o ccronexpr.o nginx.o $(CC) $(ip2region_CFLAGS) ip2region/ip2region.c @@ -69,7 +69,7 @@ libclamav: test: - echo $(CMAKE) $(ARCH) + echo $(CMAKE) $(ARCH) $(CFLAGS) static: conf.o rhost.o libiptc.o $(CC) $(IPTC_CFLAGS) -c libiptc/libip4tc.c -o libiptc/libip4tc.o diff --git a/clamav/libclamav_rust/.rustc_info.json b/clamav/libclamav_rust/.rustc_info.json index c486876..cc7f143 100644 --- a/clamav/libclamav_rust/.rustc_info.json +++ b/clamav/libclamav_rust/.rustc_info.json @@ -1 +1 @@ -{"rustc_fingerprint":537842707314038760,"outputs":{"10376369925670944939":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/usr\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.63.0\nbinary: rustc\ncommit-hash: unknown\ncommit-date: unknown\nhost: x86_64-unknown-linux-gnu\nrelease: 1.63.0\nLLVM version: 14.0.6\n","stderr":""},"15493033989842322569":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/usr\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"15697416045686424142":{"success":false,"status":"exit status: 1","code":1,"stdout":"","stderr":"error: `-Csplit-debuginfo` is unstable on this platform\n\n"},"9218888252049904301":{"success":false,"status":"exit status: 1","code":1,"stdout":"","stderr":"error: `-Csplit-debuginfo` is unstable on this platform\n\n"}},"successes":{}} \ No newline at end of file +{"rustc_fingerprint":5376818386984183904,"outputs":{"14371922958718593042":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/usr\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.71.1\nbinary: rustc\ncommit-hash: unknown\ncommit-date: unknown\nhost: x86_64-unknown-linux-gnu\nrelease: 1.71.1\nLLVM version: 16.0.6\n","stderr":""},"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/usr\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}} \ No newline at end of file diff --git a/conf.c b/conf.c index 7c189bc..03a7178 100644 --- a/conf.c +++ b/conf.c @@ -218,6 +218,24 @@ static void parse_global_module(char *content, conf * conf) val_begin_len = val_end - val_begin; conf->DISK_USE = atoi(val_begin); } + + // NGINX + if (strcasecmp(var, "NGINX") == 0) { + val_begin_len = val_end - val_begin; + conf->NGINX = atoi(val_begin); + } + if (strcasecmp(var, "NGINX_LOG_FILE") == 0) { + val_begin_len = val_end - val_begin; + conf->NGINX_LOG_FILE_LEN = val_begin_len; + if (copy_new_mem(val_begin, val_begin_len, &conf->NGINX_LOG_FILE) != 0) + return; + } + if (strcasecmp(var, "NGINX_REGION_LIST") == 0) { + val_begin_len = val_end - val_begin; + conf->NGINX_REGION_LIST_LEN = val_begin_len; + if (copy_new_mem(val_begin, val_begin_len, &conf->NGINX_REGION_LIST) != 0) + return; + } content = strchr(lineEnd + 1, '\n'); } @@ -313,6 +331,11 @@ void free_conf(conf * conf) if (conf->CLAMAV_ARG) free(conf->CLAMAV_ARG); + // NGINX + if (conf->NGINX_LOG_FILE) + free(conf->NGINX_LOG_FILE); + if (conf->NGINX_REGION_LIST) + free(conf->NGINX_REGION_LIST); return; } @@ -351,6 +374,12 @@ void ptintf_conf(conf * conf) if (conf->CLAMAV_ARG) printf("CLAMAV_ARG %s %d\n", conf->CLAMAV_ARG, conf->CLAMAV_ARG_LEN); + + // Nginx + if (conf->NGINX_LOG_FILE) + printf("CLAMAV_ARG %s %d\n", conf->NGINX_LOG_FILE, conf->NGINX_LOG_FILE_LEN); + if (conf->NGINX_REGION_LIST) + printf("CLAMAV_ARG %s %d\n", conf->NGINX_REGION_LIST, conf->NGINX_REGION_LIST_LEN); } void split_string(char string[], char delims[], char (*whitelist_ip)[WHITELIST_IP_NUM]) diff --git a/conf.h b/conf.h index 62e9309..6a9595b 100644 --- a/conf.h +++ b/conf.h @@ -43,6 +43,13 @@ typedef struct CONF int IPV4_RESTRICTION; char *IPV4_WHITE_LIST; int IPV4_WHITE_LIST_LEN; + + // NGINX + int NGINX; + char *NGINX_LOG_FILE; + int NGINX_LOG_FILE_LEN; + char *NGINX_REGION_LIST; + int NGINX_REGION_LIST_LEN; int IS_MAIL; diff --git a/nginx.c b/nginx.c index d9db137..f87d50a 100644 --- a/nginx.c +++ b/nginx.c @@ -1,11 +1,19 @@ + #include "nginx.h" -#include "ip2region/ip2region.h" + #define EVENT_SIZE (sizeof(struct inotify_event)) #define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16)) #define INITIAL_BUFFER_SIZE 8192 -int IP_location(char *string) { +void nginx_iptc(char *ip) +{ + unsigned int srcIp; + inet_pton(AF_INET, ip, &srcIp); + iptc_add_rule("filter", "INPUT", IPPROTO_TCP, NULL, NULL, srcIp, 0, NULL, NULL, "DROP", NULL, 1); +} + +int IP_location(char *string, conf *config) { char *area = NULL; char *xdb_path = "ip2region.xdb"; char *p = strchr(string, ' '); @@ -34,37 +42,40 @@ int IP_location(char *string) { } printf("IP地址:%s, %s\n", IP, area); + printf("%s, %s\n", config->NGINX_LOG_FILE, config->NGINX_REGION_LIST); + return 0; } -void nginx_read_log(const char *filename) { - int fd = open(filename, O_RDONLY); +int nginx_read_log(const char *filename, conf *p) { + int fd = open(p->NGINX_LOG_FILE, O_RDONLY); if (fd == -1) { perror("open"); - exit(EXIT_FAILURE); + + return -1; } // Move to the end of the file if (lseek(fd, 0, SEEK_END) == -1) { perror("lseek"); close(fd); - exit(EXIT_FAILURE); + return -1; } int inotify_fd = inotify_init(); if (inotify_fd < 0) { perror("inotify_init"); close(fd); - exit(EXIT_FAILURE); + return -1; } - int wd = inotify_add_watch(inotify_fd, filename, IN_MODIFY); + int wd = inotify_add_watch(inotify_fd, p->NGINX_LOG_FILE, IN_MODIFY); if (wd == -1) { perror("inotify_add_watch"); close(inotify_fd); close(fd); - exit(EXIT_FAILURE); + return -1; } char buffer[EVENT_BUF_LEN]; @@ -76,14 +87,14 @@ void nginx_read_log(const char *filename) { inotify_rm_watch(inotify_fd, wd); close(inotify_fd); close(fd); - exit(EXIT_FAILURE); + return -1; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { perror("fcntl F_SETFL"); inotify_rm_watch(inotify_fd, wd); close(inotify_fd); close(fd); - exit(EXIT_FAILURE); + return -1; } // Initial dynamic buffer allocation @@ -94,7 +105,7 @@ void nginx_read_log(const char *filename) { inotify_rm_watch(inotify_fd, wd); close(inotify_fd); close(fd); - exit(EXIT_FAILURE); + return -1; } while (1) { @@ -110,7 +121,7 @@ void nginx_read_log(const char *filename) { int bytes_read; while ((bytes_read = read(fd, read_buf, buffer_size - 1)) > 0) { read_buf[bytes_read] = '\0'; - IP_location(read_buf); + IP_location(read_buf, p); } if (bytes_read == -1 && errno != EAGAIN) { perror("read"); @@ -124,4 +135,6 @@ void nginx_read_log(const char *filename) { inotify_rm_watch(inotify_fd, wd); close(inotify_fd); close(fd); + + return 0; } diff --git a/nginx.h b/nginx.h index c5b0e66..e9f9be9 100644 --- a/nginx.h +++ b/nginx.h @@ -9,7 +9,11 @@ #include #include +#include "rhost.h" +#include "libiptc.h" +#include "ip2region/ip2region.h" -extern void nginx_read_log(const char *filename); + +extern int nginx_read_log(const char *filename, conf * conf); #endif diff --git a/rhost.c b/rhost.c index 47a87c9..94bfa5d 100644 --- a/rhost.c +++ b/rhost.c @@ -1,11 +1,51 @@ -#include "conf.h" #include "rhost.h" + #include "libiptc.h" #include "libclamav.h" #include "clamscan.h" - #include "ccronexpr.h" #include "nginx.h" +#include "./cJSON/cJSON.h" +#include "ip2region/ip2region.h" + +// CRON +#define MAX_SECONDS 60 +#define CRON_MAX_MINUTES 60 +#define CRON_MAX_HOURS 24 +#define CRON_MAX_DAYS_OF_WEEK 8 +#define CRON_MAX_DAYS_OF_MONTH 32 +#define CRON_MAX_MONTHS 12 + +#define INVALID_INSTANT ((time_t) -1) + +#define DATE_FORMAT "%Y-%m-%d_%H:%M:%S" + +#ifndef ARRAY_LEN +#define ARRAY_LEN(x) sizeof(x)/sizeof(x[0]) +#endif + +#ifdef CRON_TEST_MALLOC +static int cronAllocations = 0; +static int cronTotalAllocations = 0; +static int maxAlloc = 0; +void* cron_malloc(size_t n) +{ + cronAllocations++; + cronTotalAllocations++; + if (cronAllocations > maxAlloc) + { + maxAlloc = cronAllocations; + } + return malloc(n); +} + +void cron_free(void* p) +{ + cronAllocations--; + free(p); +} +#endif +// CRON END // 存储公网IP char *public_ip; @@ -1131,10 +1171,10 @@ goto_daemon: } } else { // 父进程 - + printf("The parent process processes Nginx logs!!!"); while(1) { - nginx_read_log("/usr/local/nginx/logs/access.log"); + nginx_read_log(conf->NGINX_LOG_FILE, conf); sleep(1); } @@ -1150,7 +1190,6 @@ goto_daemon: for (i = 1; i < head_argc; i++) { if (head_argvs[i]) free(head_argvs[i]); - } return 0; diff --git a/rhost.conf b/rhost.conf index 8cc3011..21635cd 100644 --- a/rhost.conf +++ b/rhost.conf @@ -3,8 +3,10 @@ global { DAEMON = "off"; // on开启后台运行,off不开启(弃用) TIME = "10"; // 睡眠时间(大于等于1,单位秒) + PUBLIC_IP = "http://inet-ip.info"; // 获取公网IP + IS_DISK = 1; // 磁盘使用率(1开启,非1关闭) DISK_USE = 95; // 任意某块磁盘使用率告警(大于等于1) @@ -12,6 +14,7 @@ global { IS_BLOCKED = 1; // 是否封禁攻击IP(1开启,非1关闭) REFUSE_NUMBER = 3; // 拒绝攻击次数 + CLAMAV = 1; // clamav 是否扫描病毒(1开启,非1关闭) CLAMAV_ARG = "-r / --exclude-dir=^/sys|^/dev|^/proc|^/opt/infected|^/root|^/home|^/mnt|^/usr|^/var --move=/opt/infected --max-filesize 1024M -l clamscan.log"; CLAMAV_TIME = "* 7 23 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周) @@ -24,6 +27,11 @@ global { REGION = 1; // 是否启用地域白名单(1开启,非1关闭) IP2REGION = 1; // 是否使用本地 ip2region 地址定位库(1使用,非1不使用) REGION_LIST = "河南 郑州 上海"; // 地域列表(空格隔开) + + + NGINX = 1; // 是否启用Nginx白名单 + NGINX_LOG_FILE= "/usr/local/nginx/logs/access.log"; // Nginx 日志文件 + NGINX_REGION_LIST = "中国 河南 郑州 上海"; // 地域列表(空格隔开) IS_MAIL = 0; // 开启邮件告警(1开启,非1关闭) diff --git a/rhost.h b/rhost.h index 950dee2..9fbd773 100644 --- a/rhost.h +++ b/rhost.h @@ -12,14 +12,11 @@ #include #include #include -#include -#include -#include #include +#include -#include "./cJSON/cJSON.h" -#include "ip2region/ip2region.h" +#include "conf.h" typedef struct now_next_time { @@ -42,51 +39,6 @@ typedef struct now_next_time -#include -#include -#include -#include -#include - -#include "ccronexpr.h" - -#define MAX_SECONDS 60 -#define CRON_MAX_MINUTES 60 -#define CRON_MAX_HOURS 24 -#define CRON_MAX_DAYS_OF_WEEK 8 -#define CRON_MAX_DAYS_OF_MONTH 32 -#define CRON_MAX_MONTHS 12 - -#define INVALID_INSTANT ((time_t) -1) - -#define DATE_FORMAT "%Y-%m-%d_%H:%M:%S" - -#ifndef ARRAY_LEN -#define ARRAY_LEN(x) sizeof(x)/sizeof(x[0]) -#endif - -#ifdef CRON_TEST_MALLOC -static int cronAllocations = 0; -static int cronTotalAllocations = 0; -static int maxAlloc = 0; -void* cron_malloc(size_t n) -{ - cronAllocations++; - cronTotalAllocations++; - if (cronAllocations > maxAlloc) - { - maxAlloc = cronAllocations; - } - return malloc(n); -} - -void cron_free(void* p) -{ - cronAllocations--; - free(p); -} -#endif - #define COLOR_NONE "\033[0m" //表示清除前面设置的格式 @@ -123,5 +75,6 @@ void cron_free(void* p) extern void read_conf(char *filename, conf * configure); extern void free_conf(conf * conf); extern void ptintf_conf(conf * conf); +extern int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM]); #endif From 00567557ba7513f97fc44e853d71bf0ca3e37d80 Mon Sep 17 00:00:00 2001 From: aixiao Date: Wed, 22 May 2024 11:36:50 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Nginx=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 +- libiptc.c | 11 +- libiptc.h | 3 +- libiptc/iptc_delete_rule.c | 275 +++++++++++++++++++++++++++++++++++++ nginx.c | 38 +++-- rhost.c | 253 +++++++++++++++++++--------------- rhost.conf | 2 +- rhost.h | 5 + 8 files changed, 465 insertions(+), 125 deletions(-) create mode 100644 libiptc/iptc_delete_rule.c diff --git a/.vscode/settings.json b/.vscode/settings.json index 91a46bb..5455103 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,7 @@ "conf.h": "c", "ccronexpr.h": "c", "clamscan.h": "c", - "libiptc.h": "c" + "libiptc.h": "c", + "stdio.h": "c" } } \ No newline at end of file diff --git a/libiptc.c b/libiptc.c index 3a98df9..1ebcb95 100644 --- a/libiptc.c +++ b/libiptc.c @@ -105,7 +105,8 @@ struct ipt_entry_match *get_match(const char *sports, const char *dports, unsign return match; } -int iptc_add_rule(const char *table, const char *chain, int protocol, const char *iniface, const char *outiface, unsigned int src, unsigned int dest, const char *srcports, const char *destports, const char *target, const char *dnat_to, const int append) +int iptc_add_rule(const char *table, const char *chain, int protocol, const char *iniface, const char *outiface, \ + unsigned int src, unsigned int dest, const char *srcports, const char *destports, const char *target, const char *dnat_to, const int append) { struct xtc_handle *handle; struct ipt_entry *chain_entry; @@ -116,6 +117,10 @@ int iptc_add_rule(const char *table, const char *chain, int protocol, const char int result = 0; chain_entry = (struct ipt_entry *)calloc(1, sizeof(*chain_entry)); + if (chain_entry == NULL) { + perror("calloc failed"); + return 1; + } if (src != 0) { chain_entry->ip.src.s_addr = src; @@ -137,7 +142,8 @@ int iptc_add_rule(const char *table, const char *chain, int protocol, const char if (IPPROTO_TCP == protocol) entry_match = get_match(srcports, destports, &chain_entry->nfcache, "tcp"); - if (strcmp(target, "") == 0 || strcmp(target, IPTC_LABEL_ACCEPT) == 0 || strcmp(target, IPTC_LABEL_DROP) == 0 || strcmp(target, IPTC_LABEL_QUEUE) == 0 || strcmp(target, IPTC_LABEL_RETURN) == 0) { + if (strcmp(target, "") == 0 || strcmp(target, IPTC_LABEL_ACCEPT) == 0 || strcmp(target, IPTC_LABEL_DROP) == 0 || \ + strcmp(target, IPTC_LABEL_QUEUE) == 0 || strcmp(target, IPTC_LABEL_RETURN) == 0) { size_t size; size = IPT_ALIGN(sizeof(struct ipt_entry_target)) + IPT_ALIGN(sizeof(int)); entry_target = (struct ipt_entry_target *)calloc(1, size); @@ -192,6 +198,7 @@ int iptc_add_rule(const char *table, const char *chain, int protocol, const char { result = iptc_insert_entry(labelit, chain_entry, 0, handle); } + if (!result) { printf("libiptc error: Can't add, %s\n", iptc_strerror(errno)); diff --git a/libiptc.h b/libiptc.h index 749a83f..6fed12d 100644 --- a/libiptc.h +++ b/libiptc.h @@ -30,6 +30,7 @@ #define IPTC_FULL_SIZE IPTC_ENTRY_SIZE + IPTC_MATCH_SIZE + IPTC_TARGET_SIZE int show_all_rule(char *ipv4); -int iptc_add_rule(const char *table, const char *chain, int protocol, const char *iniface, const char *outiface, unsigned int src, unsigned int dest, const char *srcports, const char *destports, const char *target, const char *dnat_to, const int append); +int iptc_add_rule(const char *table, const char *chain, int protocol, const char *iniface, const char *outiface, \ + unsigned int src, unsigned int dest, const char *srcports, const char *destports, const char *target, const char *dnat_to, const int append); #endif diff --git a/libiptc/iptc_delete_rule.c b/libiptc/iptc_delete_rule.c new file mode 100644 index 0000000..183dcea --- /dev/null +++ b/libiptc/iptc_delete_rule.c @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NFC_IP_SRC_PT 0x0200 +#define NFC_IP_DST_PT 0x0400 + +#ifndef IPT_MIN_ALIGN +#define IPT_MIN_ALIGN (__alignof__(struct ipt_entry)) +#endif + +#define IPT_ALIGN(s) (((s) + ((IPT_MIN_ALIGN)-1)) & ~((IPT_MIN_ALIGN)-1)) + +#define IPTC_ENTRY_SIZE XT_ALIGN(sizeof(struct ipt_entry)) +#define IPTC_MATCH_SIZE XT_ALIGN(sizeof(struct ipt_entry_match) + sizeof(struct ipt_udp)) +#define IPTC_TARGET_SIZE XT_ALIGN(sizeof(struct ipt_entry_target)) +#define IPTC_FULL_SIZE IPTC_ENTRY_SIZE + IPTC_MATCH_SIZE + IPTC_TARGET_SIZE + +#define IPTC_LABEL_ACCEPT "ACCEPT" +#define IPTC_LABEL_DROP "DROP" +#define IPTC_LABEL_QUEUE "QUEUE" +#define IPTC_LABEL_RETURN "RETURN" + +static u_int16_t parse_port(const char *port) +{ + return atoi(port); +} + +static void parse_ports(const char *portstring, u_int16_t *ports) +{ + char *buffer; + char *cp; + + buffer = strdup(portstring); + if ((cp = strchr(buffer, ':')) == NULL) + ports[0] = ports[1] = parse_port(buffer); + else { + *cp = '\0'; + cp++; + + ports[0] = buffer[0] ? parse_port(buffer) : 0; + ports[1] = cp[0] ? parse_port(cp) : 0xFFFF; + } + + free(buffer); +} + +struct ipt_entry_match *get_match(const char *sports, const char *dports, unsigned int *nfcache, const char *protocol) +{ + struct ipt_entry_match *match; + struct ipt_udp *udpinfo; + size_t size; + + size = IPT_ALIGN(sizeof(*match)) + IPT_ALIGN(sizeof(*udpinfo)); + match = (struct ipt_entry_match *)calloc(1, size); + if (!match) { + perror("calloc failed for match"); + return NULL; + } + + match->u.match_size = size; + strncpy(match->u.user.name, protocol, IPT_FUNCTION_MAXNAMELEN - 2); + match->u.user.name[IPT_FUNCTION_MAXNAMELEN - 2] = '\0'; + + udpinfo = (struct ipt_udp *)match->data; + udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF; + + if (sports) { + *nfcache |= NFC_IP_SRC_PT; + parse_ports(sports, udpinfo->spts); + } + if (dports) { + *nfcache |= NFC_IP_DST_PT; + parse_ports(dports, udpinfo->dpts); + } + + return match; +} + +// 打印 IP 地址 +void print_ip_address(const char *label, struct in_addr addr) { + char ip_str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &addr, ip_str, sizeof(ip_str)); + printf("%s: %s\n", label, ip_str); +} + +// 打印规则详细信息 +void print_rule(const char *label, const struct ipt_entry *entry) { + printf("%s:\n", label); + print_ip_address(" src", entry->ip.src); + print_ip_address(" dst", entry->ip.dst); + printf(" proto: %u\n", entry->ip.proto); + printf(" iniface: %s\n", entry->ip.iniface); + printf(" outiface: %s\n", entry->ip.outiface); + printf(" target_offset: %u\n", entry->target_offset); + printf(" next_offset: %u\n", entry->next_offset); + printf(" counters: pkts=%llu, bytes=%llu\n", entry->counters.pcnt, entry->counters.bcnt); +} + +// 打印匹配结构详细信息 +void print_match(const char *label, const struct ipt_entry_match *match) { + printf("%s:\n", label); + printf(" match_size: %u\n", match->u.user.match_size); + printf(" name: %s\n", match->u.user.name); + printf(" revision: %u\n", match->u.user.revision); + // 如果有特定协议的数据,例如 TCP 或 UDP,可以在这里打印具体内容 + // 例如:匹配 TCP 协议时,打印源端口和目标端口 + if (strcmp(match->u.user.name, "tcp") == 0) { + struct ipt_tcp *tcpinfo = (struct ipt_tcp *)match->data; + printf(" TCP source port: %u\n", ntohs(tcpinfo->spts[0])); + printf(" TCP destination port: %u\n", ntohs(tcpinfo->dpts[0])); + } else if (strcmp(match->u.user.name, "udp") == 0) { + struct ipt_udp *udpinfo = (struct ipt_udp *)match->data; + printf(" UDP source port: %u\n", ntohs(udpinfo->spts[0])); + printf(" UDP destination port: %u\n", ntohs(udpinfo->dpts[0])); + } +} + +// 打印目标结构详细信息 +void print_target(const char *label, const struct ipt_entry_target *target) { + printf("%s:\n", label); + printf(" target_size: %u\n", target->u.user.target_size); + printf(" name: %s\n", target->u.user.name); + printf(" revision: %u\n", target->u.user.revision); +} + +int iptc_delete_rule(const char *table, const char *chain, int protocol, const char *iniface, const char *outiface, \ + unsigned int src, unsigned int dest, const char *srcports, const char *destports, const char *target) +{ + struct xtc_handle *handle = NULL; + struct ipt_entry *chain_entry = NULL; + struct ipt_entry_match *entry_match = NULL; + struct ipt_entry_target *entry_target = NULL; + ipt_chainlabel labelit; + long match_size = 0; + int result = 1; // Default to failure + + // Initialize rule entry + chain_entry = (struct ipt_entry *)calloc(1, sizeof(*chain_entry)); + if (!chain_entry) { + perror("calloc failed"); + return 1; + } + + if (src != 0) { + chain_entry->ip.src.s_addr = src; + chain_entry->ip.smsk.s_addr = 0xFFFFFFFF; + } + if (dest != 0) { + chain_entry->ip.dst.s_addr = dest; + chain_entry->ip.dmsk.s_addr = 0xFFFFFFFF; + } + + if (iniface) + strncpy(chain_entry->ip.iniface, iniface, IFNAMSIZ); + if (outiface) + strncpy(chain_entry->ip.outiface, outiface, IFNAMSIZ); + + chain_entry->ip.proto = protocol; + if (IPPROTO_UDP == protocol) + entry_match = get_match(srcports, destports, &chain_entry->nfcache, "udp"); + if (IPPROTO_TCP == protocol) + entry_match = get_match(srcports, destports, &chain_entry->nfcache, "tcp"); + + print_match("entry_match", entry_match); + + if (strcmp(target, "") == 0 || strcmp(target, IPTC_LABEL_ACCEPT) == 0 || strcmp(target, IPTC_LABEL_DROP) == 0 || strcmp(target, IPTC_LABEL_QUEUE) == 0 || strcmp(target, IPTC_LABEL_RETURN) == 0) { + size_t size; + size = IPT_ALIGN(sizeof(struct ipt_entry_target)) + IPT_ALIGN(sizeof(int)); + entry_target = (struct ipt_entry_target *)calloc(1, size); + if (!entry_target) { + perror("calloc failed for target"); + goto cleanup; + } + entry_target->u.user.target_size = size; + strncpy(entry_target->u.user.name, target, XT_EXTENSION_MAXNAMELEN); + entry_target->u.user.name[XT_EXTENSION_MAXNAMELEN - 1] = '\0'; + } + match_size = entry_match ? entry_match->u.match_size : 0; + print_target("entry_target", entry_target); + + + struct ipt_entry *tmp_ipt = chain_entry; + chain_entry = (struct ipt_entry *)realloc(chain_entry, sizeof(*chain_entry) + match_size + entry_target->u.target_size); + if (!chain_entry) { + free(tmp_ipt); + free(entry_target); + if (entry_match) free(entry_match); + perror("realloc failed"); + return 1; + } + + memcpy(chain_entry->elems + match_size, entry_target, entry_target->u.target_size); + chain_entry->target_offset = sizeof(*chain_entry) + match_size; + chain_entry->next_offset = sizeof(*chain_entry) + match_size + entry_target->u.target_size; + if (entry_match) { + memcpy(chain_entry->elems, entry_match, match_size); + } + + handle = iptc_init(table); + if (!handle) { + fprintf(stderr, "libiptc error: Can't initialize table %s, %s\n", table, iptc_strerror(errno)); + goto cleanup; + } + + strncpy(labelit, chain, sizeof(ipt_chainlabel)); + labelit[sizeof(ipt_chainlabel) - 1] = '\0'; + if (0 == iptc_is_chain(labelit, handle)) { + fprintf(stderr, "libiptc error: Chain %s does not exist!\n", labelit); + goto cleanup; + } + + // 打印 chain_entry 详细信息 + print_rule("Chain entry", chain_entry); + + // Find and delete the matching rule + const struct ipt_entry *entry; + unsigned int rule_num = 0; + for (entry = iptc_first_rule(labelit, handle); entry; (entry = iptc_next_rule(entry, handle), ++rule_num)) + { + + if (entry->ip.proto == chain_entry->ip.proto && + entry->ip.src.s_addr == chain_entry->ip.src.s_addr && + entry->ip.dst.s_addr == chain_entry->ip.dst.s_addr && + strncmp(entry->ip.iniface, chain_entry->ip.iniface, IFNAMSIZ) == 0 && + strncmp(entry->ip.outiface, chain_entry->ip.outiface, IFNAMSIZ) == 0) + { + // 打印当前 entry 详细信息 + print_rule("Current entry", entry); + + printf("Matching rule found. Deleting rule number: %u\n", rule_num); + + // 删除规则 + if (!iptc_delete_num_entry(labelit, rule_num, handle)) { + fprintf(stderr, "libiptc error: Can't delete entry, %s\n", iptc_strerror(errno)); + iptc_free(handle); + return result; + } + + // 提交更改 + if (!iptc_commit(handle)) { + fprintf(stderr, "libiptc error: Commit error, %s\n", iptc_strerror(errno)); + } else { + printf("Rule deleted successfully\n"); + result = 0; + break; + } + } + } + +cleanup: + if (entry_match) free(entry_match); + if (entry_target) free(entry_target); + if (chain_entry) free(chain_entry); + if (handle) iptc_free(handle); + + return result; +} + +int main(int argc, char *argv[]) { + // Test deleting rule + unsigned int srcIp; + inet_pton(AF_INET, argv[1], &srcIp); + + int result = iptc_delete_rule("filter", "INPUT", IPPROTO_TCP, NULL, NULL, srcIp, 0, NULL, NULL, IPTC_LABEL_DROP); + + return result; +} diff --git a/nginx.c b/nginx.c index f87d50a..eb687b8 100644 --- a/nginx.c +++ b/nginx.c @@ -1,7 +1,6 @@ #include "nginx.h" - #define EVENT_SIZE (sizeof(struct inotify_event)) #define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16)) #define INITIAL_BUFFER_SIZE 8192 @@ -13,20 +12,30 @@ void nginx_iptc(char *ip) iptc_add_rule("filter", "INPUT", IPPROTO_TCP, NULL, NULL, srcIp, 0, NULL, NULL, "DROP", NULL, 1); } -int IP_location(char *string, conf *config) { +int IP_location(char *string, conf *config) +{ char *area = NULL; char *xdb_path = "ip2region.xdb"; char *p = strchr(string, ' '); char IP[64]; memset(IP, 0, 64); + char *t = _time(); + char nginx_region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } }; + char NGINX_REGION_LIST_COPY[config->NGINX_REGION_LIST_LEN + 1]; + + memset(NGINX_REGION_LIST_COPY, 0, config->NGINX_REGION_LIST_LEN + 1); + memcpy(NGINX_REGION_LIST_COPY, config->NGINX_REGION_LIST, config->NGINX_REGION_LIST_LEN); // 复制配置字符串,split_string()会改变原数据 + + split_string(NGINX_REGION_LIST_COPY, " ", nginx_region_list); + + // IP 地理位置获取 if ((p - string) > 0) { memmove(IP, string, p - string); } else { printf("Invalid IP string format.\n"); return -1; } - if (access(xdb_path, F_OK) == -1) { // 判断 ip2region 地址定位库是否存在 xdb_path = "ip2region/ip2region.xdb"; if (access(xdb_path, F_OK) == -1) { @@ -34,28 +43,36 @@ int IP_location(char *string, conf *config) { return -1; } } - area = ip2region(xdb_path, IP); if (area == NULL) { printf("ip2region解析地域错误\n"); return -1; } - printf("IP地址:%s, %s\n", IP, area); - printf("%s, %s\n", config->NGINX_LOG_FILE, config->NGINX_REGION_LIST); + my_printf("IP地址:%s, %s\n", IP, area); + //printf("%s, %s\n", config->NGINX_LOG_FILE, config->NGINX_REGION_LIST); + if (config->NGINX == 1) // 开启Nginx防御 + { + if (isregion(area, nginx_region_list) == 1) { // 返回1表示在白名单列表 + printf(RED "%s Nginx Ip Address: %s, 属于地域白名单: %s\n" COLOR_NONE, t, IP, area); + } else { + my_printf(RED "%s Nginx 封禁 Ip Address: %s, 地址: %s!!!\n" COLOR_NONE, t, IP, area); + nginx_iptc(IP); + } + } return 0; } -int nginx_read_log(const char *filename, conf *p) { +int nginx_read_log(const char *filename, conf *p) +{ int fd = open(p->NGINX_LOG_FILE, O_RDONLY); if (fd == -1) { perror("open"); - + return -1; } - // Move to the end of the file if (lseek(fd, 0, SEEK_END) == -1) { perror("lseek"); @@ -96,7 +113,6 @@ int nginx_read_log(const char *filename, conf *p) { close(fd); return -1; } - // Initial dynamic buffer allocation size_t buffer_size = INITIAL_BUFFER_SIZE; char *read_buf = alloca(buffer_size); @@ -116,7 +132,7 @@ int nginx_read_log(const char *filename, conf *p) { } for (int i = 0; i < length;) { - struct inotify_event *event = (struct inotify_event *) &buffer[i]; + struct inotify_event *event = (struct inotify_event *)&buffer[i]; if (event->mask & IN_MODIFY) { int bytes_read; while ((bytes_read = read(fd, read_buf, buffer_size - 1)) > 0) { diff --git a/rhost.c b/rhost.c index 94bfa5d..28de681 100644 --- a/rhost.c +++ b/rhost.c @@ -28,18 +28,17 @@ static int cronAllocations = 0; static int cronTotalAllocations = 0; static int maxAlloc = 0; -void* cron_malloc(size_t n) +void *cron_malloc(size_t n) { cronAllocations++; cronTotalAllocations++; - if (cronAllocations > maxAlloc) - { + if (cronAllocations > maxAlloc) { maxAlloc = cronAllocations; } return malloc(n); } -void cron_free(void* p) +void cron_free(void *p) { cronAllocations--; free(p); @@ -47,6 +46,47 @@ void cron_free(void* p) #endif // CRON END + + + + +// 自定义 printf 函数 +void my_printf(const char *format, ...) { + va_list args; + va_start(args, format); + + // 打印到控制台 + vprintf(format, args); + va_end(args); // 结束对变参列表的处理 + + // 重新启动变参列表 + va_start(args, format); + + // 打开日志文件(追加模式) + FILE *log_file = fopen(LOG_FILE, "a"); + if (log_file != NULL) { + // 获取当前时间 + time_t now = time(NULL); + struct tm local_time; + localtime_r(&now, &local_time); + char time_str[20]; // YYYY-MM-DD HH:MM:SS 格式 + strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &local_time); + + // 打印时间戳到日志文件 + fprintf(log_file, "[%s] ", time_str); + + // 打印内容到日志文件 + vfprintf(log_file, format, args); + + // 关闭日志文件 + fclose(log_file); + } else { + perror("Unable to open log file"); + } + + va_end(args); // 结束对变参列表的处理 +} + // 存储公网IP char *public_ip; @@ -698,6 +738,8 @@ BLOCKED: if (conf->IS_BLOCKED == 1) { // libiptc 库插入规则 // iptables -t filter -A INPUT -p tcp -m tcp -s 47.110.180.35 -j DROP + + // libiptc 库删除规则 // iptables -t filter -D INPUT -p tcp -m tcp -s 47.110.180.35 -j DROP unsigned int srcIp; inet_pton(AF_INET, buffer, &srcIp); @@ -843,7 +885,6 @@ int update_freshclam(int argc, char *argv[]) system("mkdir -p /etc/clamav/"); system("cp freshclam.conf /etc/clamav/"); } - // 打印clamav参数 for (int i = 0; i < fre_argc; i++) { printf("%s %d\n", fre_argv[i], i); @@ -1068,119 +1109,113 @@ goto_daemon: exit(0); } - if (-1 == (nice(-20))) // 进程优先级 + // 进程优先级 + if (-1 == (nice(-20))) perror("nice"); - pid_t pid; - // 创建一个新进程 - pid = fork(); - - if (pid < 0) { - // fork 失败 - fprintf(stderr, "Fork 失败\n"); - return 1; - } else if (pid == 0) { - // 子进程 - while (1) { - // Cron - struct tm *calnext; //取得Cron规则时间 - calnext = (struct tm *)malloc(sizeof(struct tm)); - memset(calnext, 0, sizeof(struct tm)); - _crontab(&calnext, conf->CLAMAV_TIME); - t->next_year = 1900 + calnext->tm_year; - t->next_mon = 1 + calnext->tm_mon; - t->next_day = calnext->tm_mday; - t->next_hour = calnext->tm_hour; - t->next_min = calnext->tm_min; - t->next_sec = calnext->tm_sec; - - // 取得现在时间 - time_t timep; - struct tm *p; - timep = time(NULL); - p = localtime(&timep); - t->now_year = 1900 + p->tm_year; - t->now_mon = 1 + p->tm_mon; - t->now_day = p->tm_mday; - t->now_hour = p->tm_hour; - t->now_min = p->tm_min; - t->now_sec = p->tm_sec; - - //printf("当前时间 %d%d%d %d:%d:%d\n", t->now_year, t->now_mon, t->now_day, t->now_hour, t->now_min, t->now_sec); - //printf("CRON %d%d%d %d:%d:%d\n", t->next_year, t->next_mon, t->next_day, t->next_hour, t->next_min, t->next_sec); - - // Clamav call - if (1 == conf->CLAMAV) { - if (t->now_year == t->next_year && t->now_mon == t->next_mon && t->now_day == t->next_day && t->now_hour == t->next_hour && t->now_min == t->next_min) { - //printf("%d%d%d %d:%d:%d\n", t->now_year, t->now_mon, t->now_day, t->now_hour, t->now_min, t->now_sec); - //printf("%d%d%d %d:%d:%d\n", t->next_year, t->next_mon, t->next_day, t->next_hour, t->next_min, t->next_sec); - - pid_t pid; - pid = fork(); - if (pid < 0) { - printf("fork error.\n"); - return -1; - } else if (pid == 0) // child process - { - int r = 0; - int virus_files = -1; - - // 扫描病毒前,更新病毒库 - update_freshclam(argc, argv); - - r = _clamscan(head_argc, head_argvs); - virus_files = get_clamav_log("clamscan.log"); - - if (virus_files > 0) { - if (conf->IS_QQMAIL == 1) { - QQ_mail_warning_Virus_files(public_ip, virus_files, conf); - sleep(3); - } - } - - // 磁盘告警 - if (1 == conf->IS_DISK) { - if (disk_waring(conf->DISK_USE) == 1) { - printf("Disk usage reaches threshold!, Please handle!\n"); - if (conf->IS_QQMAIL == 1) { - QQ_mail_warning_Disk_Use(public_ip, 0, conf); - sleep(3); - } - } else { - printf("Disk usage does not reach threshold!\n"); - } - } - - _exit(r); - } else { - int status = 0; - wait(&status); // wait the end of child process - if (WIFEXITED(status)) { - ; - //printf("child process return %d\n", WEXITSTATUS(status)); - } - - sleep(60); // 跳过这一分钟 - } - } - } - - rule(conf); - sleep(conf->TIME); - } - } else { - // 父进程 - printf("The parent process processes Nginx logs!!!"); - while(1) + // 处理Nginx + pid_t pid = fork(); // 创建子进程 + if (pid == 0) { + printf("The parent process processes Nginx logs!!!\n"); + while (1) { nginx_read_log(conf->NGINX_LOG_FILE, conf); - sleep(1); } } + + while (1) + { + // Cron + struct tm *calnext; //取得Cron规则时间 + calnext = (struct tm *)malloc(sizeof(struct tm)); + memset(calnext, 0, sizeof(struct tm)); + _crontab(&calnext, conf->CLAMAV_TIME); + t->next_year = 1900 + calnext->tm_year; + t->next_mon = 1 + calnext->tm_mon; + t->next_day = calnext->tm_mday; + t->next_hour = calnext->tm_hour; + t->next_min = calnext->tm_min; + t->next_sec = calnext->tm_sec; + + // 取得现在时间 + time_t timep; + struct tm *p; + timep = time(NULL); + p = localtime(&timep); + t->now_year = 1900 + p->tm_year; + t->now_mon = 1 + p->tm_mon; + t->now_day = p->tm_mday; + t->now_hour = p->tm_hour; + t->now_min = p->tm_min; + t->now_sec = p->tm_sec; + + //printf("当前时间 %d%d%d %d:%d:%d\n", t->now_year, t->now_mon, t->now_day, t->now_hour, t->now_min, t->now_sec); + //printf("CRON %d%d%d %d:%d:%d\n", t->next_year, t->next_mon, t->next_day, t->next_hour, t->next_min, t->next_sec); + + // Clamav call + if (1 == conf->CLAMAV) { + if (t->now_year == t->next_year && t->now_mon == t->next_mon && t->now_day == t->next_day && \ + t->now_hour == t->next_hour && t->now_min == t->next_min) { + //printf("%d%d%d %d:%d:%d\n", t->now_year, t->now_mon, t->now_day, t->now_hour, t->now_min, t->now_sec); + //printf("%d%d%d %d:%d:%d\n", t->next_year, t->next_mon, t->next_day, t->next_hour, t->next_min, t->next_sec); + + pid_t pid; + pid = fork(); + if (pid < 0) { + printf("fork error.\n"); + return -1; + } else if (pid == 0) // child process + { + int r = 0; + int virus_files = -1; + + // 扫描病毒前,更新病毒库 + update_freshclam(argc, argv); + + r = _clamscan(head_argc, head_argvs); + virus_files = get_clamav_log("clamscan.log"); + + if (virus_files > 0) { + if (conf->IS_QQMAIL == 1) { + QQ_mail_warning_Virus_files(public_ip, virus_files, conf); + sleep(3); + } + } + + // 磁盘告警 + if (1 == conf->IS_DISK) { + if (disk_waring(conf->DISK_USE) == 1) { + printf("Disk usage reaches threshold!, Please handle!\n"); + if (conf->IS_QQMAIL == 1) { + QQ_mail_warning_Disk_Use(public_ip, 0, conf); + sleep(3); + } + } else { + printf("Disk usage does not reach threshold!\n"); + } + } + + _exit(r); + } else { + int status = 0; + wait(&status); // wait the end of child process + if (WIFEXITED(status)) { + ; + //printf("child process return %d\n", WEXITSTATUS(status)); + } + + sleep(60); // 跳过这一分钟 + } + } + } + + rule(conf); + sleep(conf->TIME); + } } else { - ; + ; } free(t); diff --git a/rhost.conf b/rhost.conf index 21635cd..25d8af3 100644 --- a/rhost.conf +++ b/rhost.conf @@ -3,7 +3,7 @@ global { DAEMON = "off"; // on开启后台运行,off不开启(弃用) TIME = "10"; // 睡眠时间(大于等于1,单位秒) - + PUBLIC_IP = "http://inet-ip.info"; // 获取公网IP diff --git a/rhost.h b/rhost.h index 9fbd773..6949254 100644 --- a/rhost.h +++ b/rhost.h @@ -14,10 +14,12 @@ #include #include #include +#include #include "conf.h" + typedef struct now_next_time { int now_year; @@ -70,11 +72,14 @@ typedef struct now_next_time #define QQMAIL_Virus "gomail -r %s -s \"System Virus Infected\" -t \"%s\"" #define QQMAIL_DISK_USE "gomail -r %s -s \"System Disk Use\" -t \"%s\"" +#define LOG_FILE "nginx.log" extern void read_conf(char *filename, conf * configure); extern void free_conf(conf * conf); extern void ptintf_conf(conf * conf); +extern void my_printf(const char *format, ...); +extern char *_time(); extern int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM]); #endif From f7f7d7136a6c79a7c23d60437129f107312e22b2 Mon Sep 17 00:00:00 2001 From: aixiao Date: Wed, 22 May 2024 15:10:19 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E7=A3=81=E7=9B=98=E4=BD=BF=E7=94=A8=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 ++- Makefile | 2 +- disk.c | 59 +++++++++++++++++++++++++++++++++++++++++++ disk.h | 12 +++++++++ nginx.c | 1 - rhost.c | 31 +++-------------------- rhost.conf | 2 +- 7 files changed, 78 insertions(+), 32 deletions(-) create mode 100644 disk.c create mode 100644 disk.h diff --git a/.vscode/settings.json b/.vscode/settings.json index 5455103..c968ffd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,7 @@ "ccronexpr.h": "c", "clamscan.h": "c", "libiptc.h": "c", - "stdio.h": "c" + "stdio.h": "c", + "nginx.h": "c" } } \ No newline at end of file diff --git a/Makefile b/Makefile index bdf67b6..008976e 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ LIBCOMMON_LIB += ./clamav/common/cert_util.c.o ./clamav/common/actions.c.o ./cla all: libclamav_rust libclamav rhost nginx.o -rhost: conf.o rhost.o libiptc.o ccronexpr.o nginx.o +rhost: conf.o rhost.o libiptc.o ccronexpr.o nginx.o disk.o $(CC) $(ip2region_CFLAGS) ip2region/ip2region.c $(CC) $(ip2region_CFLAGS) ip2region/xdb_searcher.c $(CC) $(cJSON_CFLAGS) cJSON/cJSON.c diff --git a/disk.c b/disk.c new file mode 100644 index 0000000..50da416 --- /dev/null +++ b/disk.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include + +// 获取指定路径的磁盘使用率 +int get_disk_usage(const char *path, double *usage) { + struct statvfs stat; + + if (statvfs(path, &stat) != 0) { + // 处理错误 + perror("statvfs failed"); + return -1; + } + + // 计算磁盘使用率 + unsigned long total_blocks = stat.f_blocks; + unsigned long free_blocks = stat.f_bfree; + unsigned long used_blocks = total_blocks - free_blocks; + + *usage = (double)used_blocks / total_blocks * 100; + return 0; +} + +int disk_usage() { + FILE *mounts; + struct mntent *ent; + + mounts = setmntent("/etc/mtab", "r"); + if (mounts == NULL) { + perror("setmntent failed"); + return 1; + } + + while ((ent = getmntent(mounts)) != NULL) + { + double usage = 0; + if (strstr(ent->mnt_fsname, "/dev/") != NULL) + { + //printf("%s %s %s\n", ent->mnt_fsname, ent->mnt_dir, ent->mnt_type); + + if (get_disk_usage(ent->mnt_dir, &usage) != 0) { + fprintf(stderr, "Failed to get disk usage for %s\n", ent->mnt_dir); + continue; + } + + int threshold = 1; + if (usage > threshold) { + printf("挂载点: %s 使用率: %.2f%% 阀值: %d%%\n", ent->mnt_dir, usage, threshold); + + } + } + + } + + endmntent(mounts); + return 0; +} diff --git a/disk.h b/disk.h new file mode 100644 index 0000000..7593432 --- /dev/null +++ b/disk.h @@ -0,0 +1,12 @@ +#ifndef DISK_H +#define DISK_H + +#include +#include +#include +#include +#include + +extern int disk_usage(); + +#endif diff --git a/nginx.c b/nginx.c index eb687b8..f8dc501 100644 --- a/nginx.c +++ b/nginx.c @@ -1,4 +1,3 @@ - #include "nginx.h" #define EVENT_SIZE (sizeof(struct inotify_event)) diff --git a/rhost.c b/rhost.c index 28de681..9402b9e 100644 --- a/rhost.c +++ b/rhost.c @@ -458,30 +458,6 @@ int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM]) return 0; } -// 去除空格 -char *remove_space(char *str) -{ - unsigned int i = 0, j = 0; - unsigned int uLen = _strlen(str); - char *strRet; - - if (0 == uLen) { - return '\0'; - } - - strRet = (char *)malloc(uLen + 2); - memset(strRet, 0, uLen + 2); - - for (i = 0; i < uLen; i++) { - if (str[i] != ' ') { - strRet[j++] = str[i]; - } - } - strRet[j] = '\0'; - - return strRet; -} - // 磁盘使用率 int disk_waring(int threshold) { @@ -756,7 +732,6 @@ BLOCKED: if (fp != NULL) pclose(fp); - if (fc != NULL) pclose(fc); if (t) @@ -1027,7 +1002,6 @@ int main(int argc, char *argv[], char **env) int head_argc = 0; char *argvs[ARGS_NUM] = { NULL }; char args[ARGS_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } }; - //printf("%d\n", argc); if (argc > 3) // 手动输入参数(如果手动输入参数个数大于3个, 则使用用户输入的参数) { process_argv(argc, argv, &(argvs[0])); @@ -1196,8 +1170,8 @@ goto_daemon: printf("Disk usage does not reach threshold!\n"); } } - _exit(r); + } else { int status = 0; wait(&status); // wait the end of child process @@ -1210,9 +1184,10 @@ goto_daemon: } } } - + // 封禁非法IP rule(conf); sleep(conf->TIME); + } } else { ; diff --git a/rhost.conf b/rhost.conf index 25d8af3..7afeacf 100644 --- a/rhost.conf +++ b/rhost.conf @@ -17,7 +17,7 @@ global { CLAMAV = 1; // clamav 是否扫描病毒(1开启,非1关闭) CLAMAV_ARG = "-r / --exclude-dir=^/sys|^/dev|^/proc|^/opt/infected|^/root|^/home|^/mnt|^/usr|^/var --move=/opt/infected --max-filesize 1024M -l clamscan.log"; - CLAMAV_TIME = "* 7 23 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周) + CLAMAV_TIME = "* 45 11 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周) IPV4_RESTRICTION = 1; // 是否启用IP白名单(1开启,非1关闭) From 2722e9b2e1f944854d49b45b8a2bf40cb21e34c0 Mon Sep 17 00:00:00 2001 From: aixiao Date: Wed, 22 May 2024 15:18:13 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=B8=AE=E5=8A=A9?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 07d19c8..6943869 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Debian freshclam # 更新病毒库(必要) - Debian系统使用libiptc库需要nftables切换到iptables + Debian系统使用libiptc库需要nftables切换到iptables (使用了libip4tc-dev库) Switching to the legacy version:(切换到 iptables) update-alternatives --set iptables /usr/sbin/iptables-legacy update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy @@ -64,10 +64,27 @@ make all ./rhost # 只处理非法攻击 -关闭 +关闭: killall rhost +帮助: +./rhost -h + Rhost Reject host&scan for viruses (Rhost 拒绝主机并扫描病毒) +Author: AIXIAO@AIXIAO.ME +Version: 1.0 +Usage: [-?h] [-d] + +Options: + -d : Background running + -? -h --help : help information + The configuration file needs to be in the same directory as the executable file! + 配置文件需要与可执行文件位于同一目录中! + + +May 22 2024 15:05:59 Compile、link. + + ``` ```text @@ -77,8 +94,10 @@ global { DAEMON = "off"; // on开启后台运行,off不开启(弃用) TIME = "10"; // 睡眠时间(大于等于1,单位秒) + PUBLIC_IP = "http://inet-ip.info"; // 获取公网IP + IS_DISK = 1; // 磁盘使用率(1开启,非1关闭) DISK_USE = 95; // 任意某块磁盘使用率告警(大于等于1) @@ -86,32 +105,36 @@ global { IS_BLOCKED = 1; // 是否封禁攻击IP(1开启,非1关闭) REFUSE_NUMBER = 3; // 拒绝攻击次数 + CLAMAV = 1; // clamav 是否扫描病毒(1开启,非1关闭) CLAMAV_ARG = "-r / --exclude-dir=^/sys|^/dev|^/proc|^/opt/infected|^/root|^/home|^/mnt|^/usr|^/var --move=/opt/infected --max-filesize 1024M -l clamscan.log"; - CLAMAV_TIME = "* 1 4 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周) + CLAMAV_TIME = "* 45 11 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周) IPV4_RESTRICTION = 1; // 是否启用IP白名单(1开启,非1关闭) - IPV4_WHITE_LIST = "1.1.1.1 2.2.2.2 "; // IP白名单(空格隔开) + IPV4_WHITE_LIST = "1.1.1.1 2.2.2.2 "; // IP白名单(空格隔开) REGION = 1; // 是否启用地域白名单(1开启,非1关闭) IP2REGION = 1; // 是否使用本地 ip2region 地址定位库(1使用,非1不使用) - //REGION_URL = "http://opendata.baidu.com/api.php?query=%s&co=&resource_id=6006&oe=utf8"; // 获取IP地域(aliyun付费API, 弃用) - REGION_URL = "https://api01.aliyun.venuscn.com/ip?ip=%s -H Authorization:APPCODE a1d842b8afda418c8ea24271a4e16b1f"; - REGION_LIST = "河南 郑州 上海"; // 地域列表(空格隔开) + REGION_LIST = "河南 郑州 上海"; // 地域列表(空格隔开) + + + NGINX = 1; // 是否启用Nginx白名单 + NGINX_LOG_FILE= "/usr/local/nginx/logs/access.log"; // Nginx 日志文件 + NGINX_REGION_LIST = "中国 河南 郑州 上海"; // 地域列表(空格隔开) IS_MAIL = 0; // 开启邮件告警(1开启,非1关闭) - IS_DING_WEBHOOK = 0; // 开启叮叮告警(1开启,非1关闭) + IS_DING_WEBHOOK = 1; // 开启叮叮告警(1开启,非1关闭) PHONE = "15565979082"; // @的人手机号 - DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=7f069c672cb878987aa6772cca336740eece4ce36bde12b51b45e9f440e0565a"; // 钉钉WEBHOOK + DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=396bce0384cded025087cff3c176ea5e9afb9bd8fcaa46d6fa8c51dd172ba513"; // 钉钉WEBHOOK - IS_QQMAIL = 1; // 开启QQ邮箱告警(默认使用gomail:https://git.aixiao.me/aixiao/gomail.git)(1开启,非1关闭) - RECV_MAIL = "1605227279@qq.com"; // 接收者QQ + IS_QQMAIL = 1; // 开启QQ邮箱告警(默认使用gomail: https://git.aixiao.me/aixiao/gomail.git)(1开启,非1关闭) + RECV_MAIL = "1605227279@qq.com"; // 接收者邮箱 }