denyhosts/rhost.c

540 lines
14 KiB
C
Raw Normal View History

2024-05-21 09:08:14 +08:00
#include "rhost.h"
2024-05-27 16:05:31 +08:00
#include "common.h"
#include "ip.h"
#include "warning.h"
#include "rule.h"
2024-05-21 09:08:14 +08:00
#include "libiptc.h"
#include "libclamav.h"
#include "clamscan.h"
#include "ccronexpr.h"
#include "nginx.h"
2024-05-23 18:12:04 +08:00
#include "disk.h"
2024-05-21 15:28:20 +08:00
#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;
2024-05-22 11:36:50 +08:00
void *cron_malloc(size_t n)
2024-05-21 15:28:20 +08:00
{
cronAllocations++;
cronTotalAllocations++;
2024-05-22 11:36:50 +08:00
if (cronAllocations > maxAlloc) {
2024-05-21 15:28:20 +08:00
maxAlloc = cronAllocations;
}
return malloc(n);
}
2024-05-22 11:36:50 +08:00
void cron_free(void *p)
2024-05-21 15:28:20 +08:00
{
cronAllocations--;
free(p);
}
#endif
// CRON END
2024-05-21 09:08:14 +08:00
2024-05-22 11:36:50 +08:00
2024-05-21 09:08:14 +08:00
// 存储公网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)
{
2024-05-28 11:08:55 +08:00
int i=0, j=0;
2024-05-21 09:08:14 +08:00
argvs[0] = argv[0];
2024-05-28 11:08:55 +08:00
2024-05-21 09:08:14 +08:00
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;
}
2024-05-27 16:05:31 +08:00
/*
// 打印clamav参数
for(int i=0; i<head_argc; i++)
{
printf("%s %d\n", head_argvs[i], i);
}
2024-05-21 09:08:14 +08:00
2024-05-27 16:05:31 +08:00
_clamscan(head_argc, head_argvs);
*/
2024-05-21 09:08:14 +08:00
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")) {
2024-05-27 16:05:31 +08:00
goto DAEMON;
2024-05-21 09:08:14 +08:00
}
if (argv[1] != NULL && 0 == strcmp(argv[1], "-d")) {
2024-05-27 16:05:31 +08:00
DAEMON:
2024-05-21 09:08:14 +08:00
// 守护进程
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);
}
2024-05-22 11:36:50 +08:00
// 进程优先级
if (-1 == (nice(-20)))
2024-05-21 09:08:14 +08:00
perror("nice");
2024-05-22 11:36:50 +08:00
// 处理Nginx
2024-05-27 16:05:31 +08:00
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);
}
2024-05-22 11:36:50 +08:00
}
}
2024-05-21 09:08:14 +08:00
2024-05-27 16:05:31 +08:00
// Clamscan
printf("Clamscan process!!!\n");
2024-05-22 11:36:50 +08:00
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;
2024-05-21 09:08:14 +08:00
2024-05-22 11:36:50 +08:00
// 扫描病毒前,更新病毒库
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);
2024-05-21 09:08:14 +08:00
}
2024-05-22 11:36:50 +08:00
}
2024-05-21 09:08:14 +08:00
2024-05-22 11:36:50 +08:00
// 磁盘告警
if (1 == conf->IS_DISK) {
2024-05-23 18:12:04 +08:00
disk_usage(conf, public_ip, conf->DISK_USE);
2024-05-22 11:36:50 +08:00
}
2024-05-23 18:12:04 +08:00
2024-05-22 11:36:50 +08:00
_exit(r);
} else {
int status = 0;
wait(&status); // wait the end of child process
if (WIFEXITED(status)) {
;
2024-05-27 16:05:31 +08:00
printf("child process return %d\n", WEXITSTATUS(status));
2024-05-21 09:08:14 +08:00
}
2024-05-22 11:36:50 +08:00
sleep(60); // 跳过这一分钟
2024-05-21 09:08:14 +08:00
}
}
}
2024-05-22 15:10:19 +08:00
2024-05-27 16:05:31 +08:00
sleep(conf->TIME);
2024-05-21 09:08:14 +08:00
}
}
2024-05-27 16:05:31 +08:00
2024-05-21 09:08:14 +08:00
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;
}