2019-09-24 08:53:00 +08:00
|
|
|
|
|
2022-07-07 16:52:24 +08:00
|
|
|
|
#include "conf.h"
|
|
|
|
|
#include "rhost.h"
|
|
|
|
|
#include "libiptc.h"
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 存储公网IP
|
|
|
|
|
char public_ip[BUFFER];
|
|
|
|
|
|
|
|
|
|
// 检测系统
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取公网IP
|
|
|
|
|
char *get_public_ip(char *ip)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp;
|
|
|
|
|
char buff[BUFFER];
|
|
|
|
|
|
|
|
|
|
memset(buff, 0, BUFFER);
|
|
|
|
|
if (NULL == (fp = popen("curl members.3322.org/dyndns/getip --silent", "r"))) {
|
|
|
|
|
perror("popen curl");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (fgets(buff, BUFFER, fp) != NULL) {
|
|
|
|
|
buff[strlen(buff) - 1] = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NULL != fp)
|
|
|
|
|
pclose(fp);
|
|
|
|
|
|
|
|
|
|
return strcpy(ip, buff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 替换字符串
|
|
|
|
|
int strReplaceAll(char *str, char *sub, char *replace)
|
|
|
|
|
{
|
|
|
|
|
if (NULL == str || NULL == sub || NULL == replace) {
|
|
|
|
|
printf("strReplaceAll param error\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *p = NULL;
|
|
|
|
|
char *t = NULL;
|
|
|
|
|
char *q = NULL;
|
|
|
|
|
char *dst = NULL;
|
|
|
|
|
char *src = NULL;
|
|
|
|
|
|
|
|
|
|
int str_len = strlen(str);
|
|
|
|
|
int sub_len = strlen(sub);
|
|
|
|
|
int replace_len = strlen(replace);
|
|
|
|
|
|
|
|
|
|
p = str;
|
|
|
|
|
while ('\0' != *p) {
|
|
|
|
|
t = str + str_len;
|
|
|
|
|
q = strstr(str, sub);
|
|
|
|
|
if (NULL == q) /* 没有子串了,那么直接返回吧 */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
src = q + sub_len; /* 源头, 原有sub后的一个字符 */
|
|
|
|
|
dst = q + replace_len; /* 目的,放完replace后的一个字符 */
|
|
|
|
|
memcpy(dst, src, t - src); /* 原有字符串后移,放出空间 */
|
|
|
|
|
memcpy(q, replace, replace_len); /* 将replace字符拷贝进来 */
|
|
|
|
|
str_len = str_len + replace_len - sub_len;
|
|
|
|
|
|
|
|
|
|
p = q + replace_len; /* p 下一轮replace后的一个字符 */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
str[str_len] = '\0'; /* 通过'\0'表示结尾 */
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 钉钉告警
|
2022-07-07 16:52:24 +08:00
|
|
|
|
int dingding_warning(char *illegal_ip, char *public_ip, conf *conf)
|
2022-06-26 19:49:00 +08:00
|
|
|
|
{
|
2022-07-07 16:52:24 +08:00
|
|
|
|
FILE *fp;
|
|
|
|
|
if ((fp = fopen("libcurl_ding.log", "wt+")) == NULL){
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-26 19:49:00 +08:00
|
|
|
|
CURL *curl;
|
|
|
|
|
CURLcode res;
|
|
|
|
|
|
|
|
|
|
curl_global_init(CURL_GLOBAL_ALL);
|
|
|
|
|
curl = curl_easy_init();
|
|
|
|
|
if (curl == NULL) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char jsonObj[BUFFER] = "{ \
|
|
|
|
|
\"msgtype\": \"text\", \
|
|
|
|
|
\"text\": { \
|
|
|
|
|
\"content\": \"Alert @PHONE 主机PUBLIC 非法主机IP被封禁! Warning!\" \
|
|
|
|
|
}, \
|
|
|
|
|
\"at\": { \
|
|
|
|
|
\"atMobiles\": [\"PHONE\"], \
|
|
|
|
|
\"isAtAll\": false \
|
|
|
|
|
} \
|
|
|
|
|
}";
|
|
|
|
|
|
|
|
|
|
strReplaceAll(jsonObj, "IP", illegal_ip);
|
2022-07-07 16:52:24 +08:00
|
|
|
|
strReplaceAll(jsonObj, "PHONE", conf->PHONE);
|
2022-06-26 19:49:00 +08:00
|
|
|
|
strReplaceAll(jsonObj, "PUBLIC", public_ip);
|
2022-07-07 16:52:24 +08:00
|
|
|
|
//printf("%s\n", jsonObj);
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
|
2022-07-07 16:52:24 +08:00
|
|
|
|
curl_easy_setopt(curl, CURLOPT_URL, conf->DING_WEBHOOK);
|
2022-06-26 19:49:00 +08:00
|
|
|
|
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");
|
2022-07-07 16:52:24 +08:00
|
|
|
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
|
|
|
|
|
2022-06-26 19:49:00 +08:00
|
|
|
|
res = curl_easy_perform(curl);
|
|
|
|
|
|
|
|
|
|
curl_easy_cleanup(curl);
|
|
|
|
|
curl_global_cleanup();
|
2022-07-07 16:52:24 +08:00
|
|
|
|
fclose(fp);
|
|
|
|
|
|
2022-06-26 19:49:00 +08:00
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 邮件告警
|
|
|
|
|
int mail_warning(char *illegal_ip, char *public_ip)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp = NULL;
|
|
|
|
|
char buff[BUFFER];
|
|
|
|
|
char text[BUFFER] = "echo \"主机:HOST, 禁止IP访问!\" |";
|
|
|
|
|
|
|
|
|
|
memset(buff, 0, BUFFER);
|
|
|
|
|
strReplaceAll(text, "IP", illegal_ip);
|
|
|
|
|
strReplaceAll(text, "HOST", public_ip);
|
|
|
|
|
|
|
|
|
|
strcat(text, " mail -s \"System ban IP\" 1605227279@qq.com");
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 第三方邮箱告警
|
2022-07-07 16:52:24 +08:00
|
|
|
|
int QQ_mail_warning(char *illegal_ip, char *public_ip, conf *conf)
|
2022-06-26 19:49:00 +08:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
char string[BUFFER+(sizeof(QQMAIL))];
|
2022-07-07 16:52:24 +08:00
|
|
|
|
char text[BUFFER] = "主机:HOST, 禁止IP访问";
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|
|
|
|
|
strReplaceAll(text, "IP", illegal_ip);
|
|
|
|
|
strReplaceAll(text, "HOST", public_ip);
|
|
|
|
|
|
|
|
|
|
memset(string, 0, BUFFER+(sizeof(QQMAIL)));
|
2022-07-07 16:52:24 +08:00
|
|
|
|
|
|
|
|
|
sprintf(string, QQMAIL, conf->SEND_QQ, conf->QQMAIL_KEY, conf->RECV_MAIL, text);
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|
|
|
|
|
system(string);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 封禁非法IP
|
2022-07-07 16:52:24 +08:00
|
|
|
|
int rule(conf *conf)
|
2019-09-24 08:53:00 +08:00
|
|
|
|
{
|
2021-07-11 10:10:55 +08:00
|
|
|
|
FILE *fp, *fc;
|
2022-07-07 16:52:24 +08:00
|
|
|
|
char p[2], splice_command[LONG_BUFFER], command[LONG_BUFFER], *temp, buffer[BUFFER], awk[BUFFER], iptables[BUFFER + (sizeof(IPTABLES))], iptables_check[BUFFER + (sizeof(IPTABLES_CHECK))];
|
2021-07-11 10:10:55 +08:00
|
|
|
|
|
2019-09-24 08:53:00 +08:00
|
|
|
|
time_t timep;
|
2021-07-11 10:10:55 +08:00
|
|
|
|
struct tm *tp;
|
2019-09-24 08:53:00 +08:00
|
|
|
|
time(&timep);
|
2021-07-11 10:10:55 +08:00
|
|
|
|
tp = localtime(&timep);
|
|
|
|
|
memset(splice_command, 0, LONG_BUFFER);
|
|
|
|
|
memset(command, 0, LONG_BUFFER);
|
|
|
|
|
memset(buffer, 0, BUFFER);
|
|
|
|
|
memset(awk, 0, BUFFER);
|
2022-06-26 19:49:00 +08:00
|
|
|
|
memset(iptables, 0, BUFFER+(sizeof(IPTABLES)));
|
2022-07-07 16:52:24 +08:00
|
|
|
|
memset(iptables_check, 0, BUFFER+(sizeof(IPTABLES_CHECK)));
|
2021-07-11 10:10:55 +08:00
|
|
|
|
fp = NULL;
|
|
|
|
|
fc = NULL;
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
2019-09-24 08:53:00 +08:00
|
|
|
|
}
|
2022-06-26 19:49:00 +08:00
|
|
|
|
} 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;
|
|
|
|
|
}
|
2019-09-24 08:53:00 +08:00
|
|
|
|
}
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
return UNKNOWN_SYSTEM;
|
2019-09-24 08:53:00 +08:00
|
|
|
|
}
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|
2019-09-24 08:53:00 +08:00
|
|
|
|
while (fgets(buffer, BUFFER, fp) != NULL) {
|
|
|
|
|
temp = strstr(buffer, "rhost");
|
|
|
|
|
sscanf(temp, "rhost=%s", temp);
|
2021-07-11 10:10:55 +08:00
|
|
|
|
if (atoi(strncpy(p, temp, 1)) > 0) {
|
|
|
|
|
strcat(splice_command, temp);
|
|
|
|
|
strcat(splice_command, "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-07 16:52:24 +08:00
|
|
|
|
printf("%s", splice_command); // 打印所有非法IP
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|
2021-07-11 10:10:55 +08:00
|
|
|
|
// 拼接命令
|
2022-07-07 16:52:24 +08:00
|
|
|
|
sprintf(awk, AWK, conf->REFUSE_NUMBER);
|
2021-07-11 10:10:55 +08:00
|
|
|
|
strcpy(command, "echo \"");
|
|
|
|
|
strcat(command, splice_command);
|
|
|
|
|
strcat(command, "\"");
|
|
|
|
|
strcat(command, awk);
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|
|
|
|
|
|
2022-07-07 16:52:24 +08:00
|
|
|
|
if ((fp = popen(command, "r")) == NULL) // 执行命令
|
2022-06-26 19:49:00 +08:00
|
|
|
|
{
|
|
|
|
|
perror("popen command");
|
2021-07-11 10:10:55 +08:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|
2022-07-07 16:52:24 +08:00
|
|
|
|
while (fgets(buffer, BUFFER, fp) != NULL) // 执行命令后, 为空时就不会
|
2022-06-26 19:49:00 +08:00
|
|
|
|
{
|
|
|
|
|
|
2022-07-07 16:52:24 +08:00
|
|
|
|
buffer[strlen(buffer) - 1] = '\0'; // 去除回车
|
2021-07-11 10:10:55 +08:00
|
|
|
|
sprintf(iptables, IPTABLES, buffer);
|
2022-06-26 19:49:00 +08:00
|
|
|
|
sprintf(iptables_check, IPTABLES_CHECK, buffer);
|
|
|
|
|
|
2022-07-08 09:16:58 +08:00
|
|
|
|
//if (0 != system(iptables_check)) // 调用iptables命令判断是否存在规则, 不存在时再添加规则
|
|
|
|
|
if (0 != show_all_rule(buffer)) // libiptc库判断
|
2022-06-26 19:49:00 +08:00
|
|
|
|
{
|
2022-07-07 16:52:24 +08:00
|
|
|
|
if (conf->IS_DING_WEBHOOK == 1) // 钉钉告警
|
2022-06-26 19:49:00 +08:00
|
|
|
|
{
|
2022-07-07 16:52:24 +08:00
|
|
|
|
dingding_warning(buffer, public_ip, conf);
|
2022-06-26 19:49:00 +08:00
|
|
|
|
sleep(3);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-07 16:52:24 +08:00
|
|
|
|
if (conf->IS_MAIL == 1) // 邮件告警
|
2022-06-26 19:49:00 +08:00
|
|
|
|
{
|
|
|
|
|
mail_warning(buffer, public_ip);
|
|
|
|
|
sleep(3);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-07 16:52:24 +08:00
|
|
|
|
if (conf->IS_QQMAIL == 1) // 邮件告警
|
2022-06-26 19:49:00 +08:00
|
|
|
|
{
|
2022-07-07 16:52:24 +08:00
|
|
|
|
QQ_mail_warning(buffer, public_ip, conf);
|
2022-06-26 19:49:00 +08:00
|
|
|
|
sleep(3);
|
|
|
|
|
}
|
2022-07-07 16:52:24 +08:00
|
|
|
|
|
|
|
|
|
/*
|
2022-07-08 09:16:58 +08:00
|
|
|
|
// 调用命令下发规则
|
2022-06-26 19:49:00 +08:00
|
|
|
|
if ((fc = popen(iptables, "r")) == NULL) {
|
|
|
|
|
perror("popen iptables");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-07-07 16:52:24 +08:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
2022-07-13 11:27:22 +08:00
|
|
|
|
// libiptc 库插入规则 iptables -t filter -A INPUT -p tcp -s xxxx -j DROP
|
2022-07-07 16:52:24 +08:00
|
|
|
|
unsigned int destIp;
|
|
|
|
|
inet_pton(AF_INET, buffer, &destIp);
|
|
|
|
|
iptc_add_rule("filter", "INPUT", IPPROTO_TCP, NULL, NULL, 0, destIp, NULL, NULL, "DROP", NULL, 1);
|
|
|
|
|
|
2021-07-11 10:10:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 08:53:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-26 19:49:00 +08:00
|
|
|
|
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) ;
|
2021-07-11 10:10:55 +08:00
|
|
|
|
|
2022-06-26 19:49:00 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[], char **env)
|
|
|
|
|
{
|
2022-07-07 16:52:24 +08:00
|
|
|
|
conf *conf = (struct CONF *)malloc(sizeof(struct CONF));
|
|
|
|
|
read_conf("rhost.conf", conf);
|
|
|
|
|
//ptintf_conf(conf);
|
|
|
|
|
|
2022-06-26 19:49:00 +08:00
|
|
|
|
memset(public_ip, 0, BUFFER);
|
|
|
|
|
get_public_ip(public_ip);
|
|
|
|
|
|
|
|
|
|
signal(SIGCHLD, sig_child); // 创建捕捉子进程退出信号
|
|
|
|
|
|
2022-07-07 16:52:24 +08:00
|
|
|
|
if (0 == strcmp(conf->DAEMON, "on"))
|
|
|
|
|
{
|
|
|
|
|
goto goto_daemon;
|
|
|
|
|
}
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|
|
|
|
|
if (argv[1] != NULL && 0 == strcmp(argv[1], "-d"))
|
|
|
|
|
{
|
2022-07-07 16:52:24 +08:00
|
|
|
|
goto_daemon:
|
2022-06-26 19:49:00 +08:00
|
|
|
|
if (daemon(1, 1)) // 守护进程
|
|
|
|
|
{
|
|
|
|
|
perror("daemon");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (1) {
|
2022-07-07 16:52:24 +08:00
|
|
|
|
rule(conf);
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|
2022-07-07 16:52:24 +08:00
|
|
|
|
sleep(conf->TIME);
|
2022-06-26 19:49:00 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-07-07 16:52:24 +08:00
|
|
|
|
rule(conf);
|
2022-06-26 19:49:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-07-07 16:52:24 +08:00
|
|
|
|
free_conf(conf);
|
|
|
|
|
free(conf);
|
|
|
|
|
|
2019-09-24 08:53:00 +08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2022-06-26 19:49:00 +08:00
|
|
|
|
|