From da8473a3ec21a378b4cf6d21b98b579c3db2da7b Mon Sep 17 00:00:00 2001 From: aixiao Date: Tue, 14 Feb 2023 09:30:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=97=85=E6=AF=92=E6=89=AB?= =?UTF-8?q?=E6=8F=8F=E6=97=B6=E9=97=B4=E4=B8=BA=E5=87=8C=E6=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 23 +- rhost.c | 2509 ++++++++++++++++++++++++++-------------------------- rhost.conf | 2 +- 3 files changed, 1273 insertions(+), 1261 deletions(-) diff --git a/README.md b/README.md index 7a3b7f9..15ba527 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # denyhosts + - 拒绝主机&杀毒 -``` + +```text 适用系统: Debian 11 Centos 7 @@ -9,7 +11,8 @@ 支持钉钉告警和邮件告 支持第三方QQ邮箱告警 ``` -``` + +```text Debian curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh apt -y install libclamav-dev libip4tc-dev libcurl4-openssl-dev #(或者libcurl4-gnutls-dev) @@ -26,7 +29,7 @@ Debian update-alternatives --set ebtables /usr/sbin/ebtables-legacy ``` -``` +```text Centos 7 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh yum install clamav clamav-update clamav-lib clamav-devel json-c-devel pcre2-devel @@ -43,10 +46,7 @@ Centos 7 freshclam # 更新病毒库(必要) ``` - - - -``` +```text 用法 cd /root git clone https://git.aixiao.me/aixiao/denyhosts @@ -72,8 +72,7 @@ killall rhost ``` - -``` +```text 配置文件 global { @@ -91,7 +90,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 = "* 35 16 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周) + CLAMAV_TIME = "* 1 4 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周) IPV4_RESTRICTION = 1; // 是否启用IP白名单(1开启,非1关闭) @@ -99,8 +98,8 @@ 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地域 + 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 = "河南 郑州 上海"; // 地域列表(空格隔开) diff --git a/rhost.c b/rhost.c index 8f7a6dd..233f8ea 100644 --- a/rhost.c +++ b/rhost.c @@ -1,1248 +1,1261 @@ -#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; -}; - -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; - - cJSON *cjson_init = cJSON_Parse(buff); - - if (cjson_init == NULL) { - perror("cJSON_Parse"); - return NULL; - } - - p = strstr(api, "aliyun"); // aliyun Api - if (p) { - cJSON *data = cJSON_GetObjectItem(cjson_init, "data"); - if (data != NULL) { - cJSON *region = cJSON_GetObjectItem(data, "region"); - - if (region) { - cJSON *isp = cJSON_GetObjectItem(data, "isp"); - cJSON *city = cJSON_GetObjectItem(data, "city"); - cJSON *country = cJSON_GetObjectItem(data, "country"); - cJSON *district = cJSON_GetObjectItem(data, "district"); - - area_len = strlen(country->valuestring) + strlen(city->valuestring) + strlen(region->valuestring) + strlen(district->valuestring) + strlen(isp->valuestring); - area = (char *)alloca(area_len + 1); - if (buff == NULL) - perror("out of memory."); - memset(area, 0, area_len + 1); - sprintf(area, "%s%s%s%s%s", isp->valuestring, country->valuestring, city->valuestring, region->valuestring, district->valuestring); - } else { - cJSON *msg = cJSON_GetObjectItem(cjson_init, "msg"); - - area_len = strlen(msg->valuestring); - area = (char *)alloca(area_len + 1); - if (buff == NULL) - perror("out of memory."); - memset(area, 0, area_len + 1); - sprintf(area, "%s", msg->valuestring); - } - } - } else 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 (buff == NULL) - perror("out of memory."); - memset(area, 0, area_len + 1); - sprintf(area, "%s", location->valuestring); - } - - } else { - area = (char *)alloca(270 + 1); - if (buff == NULL) - perror("out of memory."); - memset(area, 0, 270); - - strcpy(area, "获取位置错误!"); - } - } - - 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) - { - return 1; - } -#define JSIN "{ \ - \"msgtype\": \"text\", \ - \"text\": { \ - \"content\": \"Alert @%s 服务器地址:%s,封禁非法入侵主机:(%s%s)\" \ - }, \ - \"at\": { \ - \"atMobiles\": [\"%s\"], \ - \"isAtAll\": false \ - } \ - }" - - sprintf(jsonObj, 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'; - sprintf(text, "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'; - - sprintf(text, "主机:%s, 禁止(%s%s)访问!", temp, ip, illegal_ip); - sprintf(string, 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'; - - sprintf(text, "Host:%s, Infected files: %d, Please handle!", temp, Virus_number); - sprintf(command, 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'; - - sprintf(text, "Host:%s, Disk usage reaches threshold!, Please handle!", temp); - sprintf(command, 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(const 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); - - sprintf(command, 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; -} - -// 封禁非法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); - - - 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=%s", 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; - - 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); - - - sprintf(awk, AWK, conf->REFUSE_NUMBER); // 拼接命令 - strcpy(command, "echo \""); - 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); - - - - //printf("conf->REGION_LIST %s\n", conf->REGION_LIST); - //printf("conf->IPV4_WHITE_LIST %s\n", conf->IPV4_WHITE_LIST); - - - if (conf->IPV4_RESTRICTION == 1) // 是否启用白名单 - { - if (whitelist(buffer, whitelist_ip) == 1) - { - printf("白名单IPV4:%s\n", 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); - sprintf(URL, conf->REGION_URL, buffer); - - location_json = GET_PUBLIC_IP(URL); - if (location_json == NULL) { - printf("获取地域错误\n"); - goto BLOCKED; - } - - if (conf->IP2REGION == 1) { // ip2region 地址定位库 - printf("使用ip2region!!\n"); - - if (-1 == access(xdb_path, F_OK)) // 判断 ip2region 地址定位库是否存在 - { - xdb_path = "ip2region/ip2region.xdb"; - - if (-1 == access(xdb_path, F_OK)) { - printf("ip2region.xdb DOESN'T EXISIT!\n"); - goto AREA; - } - } - - - area = ip2region(xdb_path, buffer); - if (area == NULL) { - printf("ip2region解析地域错误\n"); - goto BLOCKED; - } - } else { -AREA: - area = process_json(location_json, conf->REGION_URL); - if (area == NULL) { - printf("解析地域错误\n"); - goto BLOCKED; - } - } - - - if (isregion(area, region_list) == 1) { - printf("Ip: %s, 地域白名单: %s\n", buffer, area); - continue; - } - - } - - - 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); - - 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 *filename; - - if (readlink("/proc/self/exe", processdir, len) <= 0) - return -1; - filename = strrchr(processdir, '/'); - if (filename == NULL) - return -1; - ++filename; - strcpy(processname, filename); - *filename = '\0'; - return (int)(filename - 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: %s", 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; iCLAMAV_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; - - - // 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; - - 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; + + cJSON *cjson_init = cJSON_Parse(buff); + + if (cjson_init == NULL) { + perror("cJSON_Parse"); + return NULL; + } + + p = strstr(api, "aliyun"); // aliyun Api + if (p) { + cJSON *data = cJSON_GetObjectItem(cjson_init, "data"); + if (data != NULL) { + cJSON *region = cJSON_GetObjectItem(data, "region"); + + if (region) { + cJSON *isp = cJSON_GetObjectItem(data, "isp"); + cJSON *city = cJSON_GetObjectItem(data, "city"); + cJSON *country = cJSON_GetObjectItem(data, "country"); + cJSON *district = cJSON_GetObjectItem(data, "district"); + + area_len = strlen(country->valuestring) + strlen(city->valuestring) + strlen(region->valuestring) + strlen(district->valuestring) + strlen(isp->valuestring); + area = (char *)alloca(area_len + 1); + if (buff == NULL) + perror("out of memory."); + memset(area, 0, area_len + 1); + sprintf(area, "%s%s%s%s%s", isp->valuestring, country->valuestring, city->valuestring, region->valuestring, district->valuestring); + } else { + cJSON *msg = cJSON_GetObjectItem(cjson_init, "msg"); + + area_len = strlen(msg->valuestring); + area = (char *)alloca(area_len + 1); + if (buff == NULL) + perror("out of memory."); + memset(area, 0, area_len + 1); + sprintf(area, "%s", msg->valuestring); + } + } + } else 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 (buff == NULL) + perror("out of memory."); + memset(area, 0, area_len + 1); + sprintf(area, "%s", location->valuestring); + } + + } else { + area = (char *)alloca(270 + 1); + if (buff == NULL) + perror("out of memory."); + memset(area, 0, 270); + + strcpy(area, "获取位置错误!"); + } + } + + 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) + { + 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'; + + //sprintf(text, "主机:%s, 禁止(%s%s)访问!", temp, ip, illegal_ip); + //sprintf(string, QQMAIL, conf->RECV_MAIL, text); + 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'; + + //sprintf(text, "Host:%s, Infected files: %d, Please handle!", temp, Virus_number); + //sprintf(command, QQMAIL_Virus, conf->RECV_MAIL, text); + 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'; + + //sprintf(text, "Host:%s, Disk usage reaches threshold!, Please handle!", temp); + //sprintf(command, QQMAIL_DISK_USE, conf->RECV_MAIL, text); + + 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(const 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); + + //sprintf(command, DF, threshold); + 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; +} + +// 封禁非法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); + + + 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=%s", 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; + + 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); + + + sprintf(awk, AWK, conf->REFUSE_NUMBER); // 拼接命令 + strcpy(command, "echo \""); + 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); + + + + //printf("conf->REGION_LIST %s\n", conf->REGION_LIST); + //printf("conf->IPV4_WHITE_LIST %s\n", conf->IPV4_WHITE_LIST); + + + if (conf->IPV4_RESTRICTION == 1) // 是否启用白名单 + { + if (whitelist(buffer, whitelist_ip) == 1) + { + printf("白名单IPV4:%s\n", 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); + sprintf(URL, conf->REGION_URL, buffer); + + location_json = GET_PUBLIC_IP(URL); + if (location_json == NULL) { + printf("获取地域错误\n"); + goto BLOCKED; + } + + if (conf->IP2REGION == 1) { // ip2region 地址定位库 + printf("使用ip2region!!\n"); + + if (-1 == access(xdb_path, F_OK)) // 判断 ip2region 地址定位库是否存在 + { + xdb_path = "ip2region/ip2region.xdb"; + + if (-1 == access(xdb_path, F_OK)) { + printf("ip2region.xdb DOESN'T EXISIT!\n"); + goto AREA; + } + } + + + area = ip2region(xdb_path, buffer); + if (area == NULL) { + printf("ip2region解析地域错误\n"); + goto BLOCKED; + } + } else { +AREA: + area = process_json(location_json, conf->REGION_URL); + if (area == NULL) { + printf("解析地域错误\n"); + goto BLOCKED; + } + } + + + if (isregion(area, region_list) == 1) { + printf("Ip: %s, 地域白名单: %s\n", buffer, area); + continue; + } + + } + + + 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); + + 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: %s", 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; iCLAMAV_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; + + + // 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; i