#include "rhost.h" #include "common.h" #include "ip.h" #include "warning.h" #include "rule.h" #include "libiptc.h" #include "libclamav.h" #include "clamscan.h" #include "ccronexpr.h" #include "nginx.h" #include "disk.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; // 检测系统 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; } 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) { int i=0, j=0; argvs[0] = argv[0]; 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) { temp = strstr(buffer, "Infected"); if (temp) sscanf(temp, "Infected files: %32s", temp); if (temp != NULL) { 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; iPUBLIC_IP); //printf("%s", public_ip); if (0 == strcmp(conf->DAEMON, "on")) { goto DAEMON; } if (argv[1] != NULL && 0 == strcmp(argv[1], "-d")) { 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 if (conf->NGINX == 1) { pid_t pid = fork(); // 创建子进程 if (pid == 0) { printf("Nginx process!!!\n"); while (1) { nginx_read_log(conf->NGINX_LOG_FILE, conf); sleep(1); } } } // 处理SSH if (conf->IS_BLOCKED == 1) { pid_t pid = fork(); // 创建子进程 if (pid == 0) { printf("SSH process!!!\n"); while (1) { if (DEBISN_SYSTEM == check_system()) { rule_(conf, "/var/log/auth.log"); } if (CENTOS_SYSTEM == check_system()) { rule_(conf, "/var/log/secure"); } sleep(1); } } } // Clamscan printf("Clamscan process!!!\n"); 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_MAIL == 1) { QQ_mail_warning_Virus_files(public_ip, virus_files, conf); sleep(3); } } // 磁盘告警 if (1 == conf->IS_DISK) { disk_usage(conf, public_ip, conf->DISK_USE); } _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); // 跳过这一分钟 } } } sleep(conf->TIME); } } 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; }