denyhosts/rhost.c

1207 lines
32 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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
// 自定义 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;
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;
}
// 磁盘使用率
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
// 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);
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 } };
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; i<head_argc; i++)
{
printf("%s %d\n", head_argvs[i], i);
}
_clamscan(head_argc, head_argvs);
*/
now_next_time *t = (now_next_time *) malloc(sizeof(struct now_next_time));
memset(t, 0, sizeof(struct now_next_time));
// 获取公网IP
public_ip = GET_PUBLIC_IP(conf->PUBLIC_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");
// 处理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); // 跳过这一分钟
}
}
}
// 封禁非法IP
rule(conf);
sleep(conf->TIME);
}
} 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;
}