denyhosts/rhost.c
2022-07-08 09:16:58 +08:00

367 lines
9.3 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 "conf.h"
#include "rhost.h"
#include "libiptc.h"
// 存储公网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;
}
// 钉钉告警
int dingding_warning(char *illegal_ip, char *public_ip, conf *conf)
{
FILE *fp;
if ((fp = fopen("libcurl_ding.log", "wt+")) == NULL){
return 1;
}
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);
strReplaceAll(jsonObj, "PHONE", conf->PHONE);
strReplaceAll(jsonObj, "PUBLIC", public_ip);
//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)
{
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;
}
// 第三方邮箱告警
int QQ_mail_warning(char *illegal_ip, char *public_ip, conf *conf)
{
char string[BUFFER+(sizeof(QQMAIL))];
char text[BUFFER] = "主机:HOST, 禁止IP访问";
strReplaceAll(text, "IP", illegal_ip);
strReplaceAll(text, "HOST", public_ip);
memset(string, 0, BUFFER+(sizeof(QQMAIL)));
sprintf(string, QQMAIL, conf->SEND_QQ, conf->QQMAIL_KEY, conf->RECV_MAIL, text);
system(string);
return 0;
}
// 封禁非法IP
int rule(conf *conf)
{
FILE *fp, *fc;
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))];
time_t timep;
struct tm *tp;
time(&timep);
tp = localtime(&timep);
memset(splice_command, 0, LONG_BUFFER);
memset(command, 0, LONG_BUFFER);
memset(buffer, 0, BUFFER);
memset(awk, 0, BUFFER);
memset(iptables, 0, BUFFER+(sizeof(IPTABLES)));
memset(iptables_check, 0, BUFFER+(sizeof(IPTABLES_CHECK)));
fp = NULL;
fc = NULL;
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;
}
while (fgets(buffer, BUFFER, fp) != NULL) {
temp = strstr(buffer, "rhost");
sscanf(temp, "rhost=%s", temp);
if (atoi(strncpy(p, temp, 1)) > 0) {
strcat(splice_command, temp);
strcat(splice_command, "\n");
}
}
printf("%s", splice_command); // 打印所有非法IP
// 拼接命令
sprintf(awk, AWK, conf->REFUSE_NUMBER);
strcpy(command, "echo \"");
strcat(command, splice_command);
strcat(command, "\"");
strcat(command, awk);
if ((fp = popen(command, "r")) == NULL) // 执行命令
{
perror("popen command");
return 1;
}
while (fgets(buffer, BUFFER, fp) != NULL) // 执行命令后, 为空时就不会
{
buffer[strlen(buffer) - 1] = '\0'; // 去除回车
sprintf(iptables, IPTABLES, buffer);
sprintf(iptables_check, IPTABLES_CHECK, buffer);
//if (0 != system(iptables_check)) // 调用iptables命令判断是否存在规则, 不存在时再添加规则
if (0 != show_all_rule(buffer)) // libiptc库判断
{
if (conf->IS_DING_WEBHOOK == 1) // 钉钉告警
{
dingding_warning(buffer, public_ip, conf);
sleep(3);
}
if (conf->IS_MAIL == 1) // 邮件告警
{
mail_warning(buffer, public_ip);
sleep(3);
}
if (conf->IS_QQMAIL == 1) // 邮件告警
{
QQ_mail_warning(buffer, public_ip, conf);
sleep(3);
}
/*
// 调用命令下发规则
if ((fc = popen(iptables, "r")) == NULL) {
perror("popen iptables");
return 1;
}
*/
// libiptc 库插入规则
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);
}
}
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;
}
int main(int argc, char *argv[], char **env)
{
conf *conf = (struct CONF *)malloc(sizeof(struct CONF));
read_conf("rhost.conf", conf);
//ptintf_conf(conf);
memset(public_ip, 0, BUFFER);
get_public_ip(public_ip);
signal(SIGCHLD, sig_child); // 创建捕捉子进程退出信号
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;
}
while (1) {
rule(conf);
sleep(conf->TIME);
}
}
else
{
rule(conf);
}
free_conf(conf);
free(conf);
return 0;
}