denyhosts/rhost.c
2022-06-26 19:49:00 +08:00

370 lines
9.6 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 <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <curl/curl.h>
#define CENTOS_SYSTEM 1
#define DEBISN_SYSTEM 2
#define UNKNOWN_SYSTEM 3
#define BUFFER 1024
#define LONG_BUFFER 1024*100
#define TOP_IP 10
#define AWK " | awk -v num=%d '{a[$1]+=1;} END {for(i in a){if (a[i] >= num) {print i;}}}' "
#define GE_10 "grep -E \"^$(LC_ALL=\"C\" date \"+%h\").$(LC_ALL=\"C\" date \"+%d\")\" /var/log/auth.log | grep failure | grep rhost"
#define LE_10 "grep -E \"^$(LC_ALL=\"C\" date \"+%h\")..$(LC_ALL=\"C\" date | awk '{print $3}')\" /var/log/auth.log | grep failure | grep rhost"
#define CENTOS_GE_10 "grep -E \"^$(LC_ALL=\"C\" date \"+%h\").$(LC_ALL=\"C\" date \"+%d\")\" /var/log/secure | grep failure | grep rhost"
#define CENTOS_LE_10 "grep -E \"^$(LC_ALL=\"C\" date \"+%h\")..$(LC_ALL=\"C\" date | awk '{print $3}')\" /var/log/secure | grep failure | grep rhost"
#define IPTABLES "iptables -I INPUT -s %s -j DROP"
#define IPTABLES_CHECK "iptables -C INPUT -s %s -j DROP"
#define TIME 60
#define IS_DIND 1
#define PHONE "155659790"
#define DING_CURL "https://oapi.dingtalk.com/robot/send?access_token=7f069c672cb878987aa6772cca336740eece4ce36bde12b51b45e9f440e"
#define IS_MAIL 0
#define IS_QQMAIL 0
#define QQMAIL "qqMail -l smtp.qq.com -p 25 -f 1605227279 -e caczsjchvyibi -q NIUYULING -r 1605227279@QQ.COM -n NIUYULING -s \"System ban IP\" -t \"%s\""
// 存储公网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)
{
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", 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, DING_CURL);
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");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_global_cleanup();
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)
{
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, text);
system(string);
return 0;
}
// 封禁非法IP
int rule()
{
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))];
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)));
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, TOP_IP);
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)) // 判断是否存在规则, 不存在时再添加规则
{
if (IS_DIND == 1) // 钉钉告警
{
dingding_warning(buffer, public_ip);
sleep(3);
}
if (IS_MAIL == 1) // 邮件告警
{
mail_warning(buffer, public_ip);
sleep(3);
}
if (IS_QQMAIL == 1) // 邮件告警
{
QQ_mail_warning(buffer, public_ip);
sleep(3);
}
if ((fc = popen(iptables, "r")) == NULL) {
perror("popen iptables");
return 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)
{
memset(public_ip, 0, BUFFER);
get_public_ip(public_ip);
signal(SIGCHLD, sig_child); // 创建捕捉子进程退出信号
if (argv[1] != NULL && 0 == strcmp(argv[1], "-d"))
{
if (daemon(1, 1)) // 守护进程
{
perror("daemon");
return -1;
}
while (1) {
rule();
sleep(TIME);
}
}
else
{
rule();
}
return 0;
}