denyhosts/rhost.c

494 lines
13 KiB
C
Raw Normal View History

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;
2022-06-26 19:49:00 +08:00
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
2022-06-26 19:49:00 +08:00
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
// 注意这里根据每次被调用获得的数据重新动态分配缓存区的大小
char *ptr = realloc(mem->memory, mem->size + realsize + 1);
if (ptr == NULL) {
/* 内存不足! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
2022-06-26 19:49:00 +08:00
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
2022-06-26 19:49:00 +08:00
}
// 获取公网IP
static char *GET_PUBLIC_IP(char *URL)
2022-06-26 19:49:00 +08:00
{
CURL *curl_handle;
CURLcode res;
2022-06-26 19:49:00 +08:00
struct MemoryStruct chunk;
2022-06-26 19:49:00 +08:00
chunk.memory = malloc(1); /* 将根据上述再分配的需要增长 */
chunk.size = 0; /* 此时没有数据 */
curl_global_init(CURL_GLOBAL_ALL);
/* 初始化curl会话 */
curl_handle = curl_easy_init();
/* 指定要获取的URL */
curl_easy_setopt(curl_handle, CURLOPT_URL, URL);
/* 将所有数据发送到此函数 */
//对于同一次阻塞的curl_easy_perform而言在写完获取的数据之前会多次调用 WriteMemoryCallback
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* 将“chunk”结构传递给回调函数 */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
//对于同一次阻塞的curl_easy_perform而言在写完获取的数据之前会多次调用 WriteMemoryCallback
res = curl_easy_perform(curl_handle);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
} else {
//printf("%lu bytes retrieved\n", (unsigned long)chunk.size);
//printf("%s", chunk.memory);
;
2022-06-26 19:49:00 +08:00
}
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
2022-06-26 19:49:00 +08:00
return chunk.memory;
2022-06-26 19:49:00 +08:00
}
// 检测系统
int check_system()
2022-06-26 19:49:00 +08:00
{
if (0 == access("/etc/debian_version", F_OK)) {
return DEBISN_SYSTEM;
} else if (0 == access("/etc/centos-release", F_OK)) {
return CENTOS_SYSTEM;
2022-06-26 19:49:00 +08:00
}
return UNKNOWN_SYSTEM;
2022-06-26 19:49:00 +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;
char temp[64];
char jsonObj[BUFFER];
memset(jsonObj, 0, BUFFER);
memset(temp, 0, 64);
strcpy(temp, public_ip);
temp[strlen(public_ip) - 1] = '\0';
if ((fp = fopen("libcurl_ding.log", "wt+")) == NULL) {
2022-07-07 16:52:24 +08:00
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;
}
#define JSIN "{ \
2022-06-26 19:49:00 +08:00
\"msgtype\": \"text\", \
\"text\": { \
\"content\": \"Alert @%s 服务器地址:%s封禁非法入侵主机:%s\" \
2022-06-26 19:49:00 +08:00
}, \
\"at\": { \
\"atMobiles\": [\"%s\"], \
2022-06-26 19:49:00 +08:00
\"isAtAll\": false \
} \
}"
2022-06-26 19:49:00 +08:00
sprintf(jsonObj, JSIN, conf->PHONE, temp, illegal_ip, conf->PHONE);
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, conf * conf)
2022-06-26 19:49:00 +08:00
{
FILE *fp = NULL;
char buff[BUFFER];
char text[BUFFER];
char temp[64];
2022-06-26 19:49:00 +08:00
memset(buff, 0, BUFFER);
memset(text, 0, BUFFER);
memset(temp, 0, 64);
2022-06-26 19:49:00 +08:00
strcpy(temp, public_ip);
temp[strlen(public_ip) - 1] = '\0';
sprintf(text, "echo \"主机:%s, 禁止%s访问\" | mail -s \"System ban IP\" %s", temp, illegal_ip, conf->RECV_MAIL);
2022-06-26 19:49:00 +08:00
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)
2022-06-26 19:49:00 +08:00
{
char string[BUFFER + (sizeof(QQMAIL))];
char text[BUFFER];
char temp[32];
memset(string, 0, BUFFER + (sizeof(QQMAIL)));
memset(text, 0, BUFFER);
memset(temp, 0, 32);
strcpy(temp, public_ip);
temp[strlen(public_ip) - 1] = '\0';
sprintf(text, "主机:%s, 禁止%s访问", temp, illegal_ip);
sprintf(string, QQMAIL, conf->RECV_MAIL, text);
return system(string);
2022-06-26 19:49:00 +08:00
}
// IP段白名单对比
int whitelist(char *client_ip, char (*whitelist_ip)[WHITELIST_IP_NUM])
{
int i;
for (i = 1; i < WHITELIST_IP_NUM - 1; i++) {
if (strcmp(whitelist_ip[i], "\0") == 0) { // 如果字符串为空就跳出循环
break;
}
if ((strncmp(client_ip, whitelist_ip[i], strlen(whitelist_ip[i]))) == 0) { // 对比client_ip长度,
return 1;
}
}
return 0;
}
char *remove_space(const char *str)
{
unsigned int uLen = strlen(str);
if(0 == uLen)
{
return '\0';
}
char *strRet = (char *)malloc(uLen + 1);
memset(strRet, 0, uLen+1);
unsigned int i = 0, j = 0;
for(i=0; i<uLen+1; i++)
{
if(str[i] != ' ')
{
strRet[j++] = str[i];
}
}
strRet[j] = '\0';
return strRet;
}
2022-06-26 19:49:00 +08:00
// 封禁非法IP
int rule(conf * conf)
2019-09-24 08:53:00 +08:00
{
int i;
char whitelist_ip[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } };
2022-08-09 15:25:06 +08:00
char p[2], splice_command[LONG_BUFFER], command[LONG_BUFFER], *temp, buffer[BUFFER], awk[BUFFER];
FILE *fp, *fc;
2019-09-24 08:53:00 +08:00
time_t timep;
2021-07-11 10:10:55 +08:00
struct tm *tp;
i=0;
fp = NULL;
fc = NULL;
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
if (DEBISN_SYSTEM == check_system()) // Debian 系统规则
2022-06-26 19:49:00 +08:00
{
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
}
} else if (CENTOS_SYSTEM == check_system()) // Centos 7系统规则
2022-06-26 19:49:00 +08:00
{
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");
}
}
printf("%s", splice_command); // 打印所有非法IP
2022-06-26 19:49:00 +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
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
while (fgets(buffer, BUFFER, fp) != NULL) // 执行命令后, 为空时就不会
2022-06-26 19:49:00 +08:00
{
buffer[strlen(buffer) - 1] = '\0'; // 去除回车
split_string(conf->IPV4_WHITE_LIST, " ", whitelist_ip);
for (i = 1; i <= WHITELIST_IP_NUM - 1; i++) {
if (*whitelist_ip[i] != '\0') ;
//printf("%s\n", whitelist_ip[i]);
}
if (conf->IPV4_RESTRICTION == 1) { // 是否启用百名单
if (whitelist(buffer, whitelist_ip) == 1) {
;
//printf("白名单IPV4:%s\n", buffer);
continue;
}
}
2022-06-26 19:49:00 +08:00
if (0 != show_all_rule(buffer)) // libiptc库判断否存在规则
2022-06-26 19:49:00 +08:00
{
char *location = NULL;
char *location_json = NULL;
char iplocation[BUFFER];
char URL[BUFFER+70];
memset(URL, 0, BUFFER+70);
sprintf(URL, "http://opendata.baidu.com/api.php?query=%s&co=&resource_id=6006&oe=utf8", buffer);
location_json = GET_PUBLIC_IP(URL);
if (NULL == location_json)
2022-06-26 19:49:00 +08:00
{
printf("获取IP位置错误!\n");
}
else
{
//printf("%s\n", location_json);
char temp[BUFFER];
memset(temp, 0, BUFFER);
char *p = strstr(location_json, "\"location\"");
char *p1 = strstr(p, "\",");
memcpy(temp, p+12, p1-p-12);
location = remove_space(temp);
}
memset(iplocation, 0, BUFFER);
strcpy(iplocation, buffer);
strcat(iplocation, "(");
strcat(iplocation, location);
strcat(iplocation, ")");
//printf("%s\n", iplocation);
if (conf->IS_DING_WEBHOOK == 1) // 钉钉告警
{
dingding_warning(iplocation, public_ip, conf);
2022-06-26 19:49:00 +08:00
sleep(3);
}
if (conf->IS_MAIL == 1) // 邮件告警
2022-06-26 19:49:00 +08:00
{
mail_warning(iplocation, public_ip, conf);
2022-06-26 19:49:00 +08:00
sleep(3);
}
if (conf->IS_QQMAIL == 1) // 邮件告警
2022-06-26 19:49:00 +08:00
{
QQ_mail_warning(iplocation, public_ip, conf);
2022-06-26 19:49:00 +08:00
sleep(3);
}
// 是否封禁攻击IP
if (conf->IS_BLOCKED == 1) {
// libiptc 库插入规则 iptables -t filter -A INPUT -p tcp -m tcp -s xxxx -j DROP
unsigned int srcIp;
inet_pton(AF_INET, buffer, &srcIp);
iptc_add_rule("filter", "INPUT", IPPROTO_TCP, NULL, NULL, srcIp, 0, NULL, NULL, "DROP", NULL, 1);
}
free(location);
free(location_json);
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) ;
2022-06-26 19:49:00 +08:00
return;
}
static int get_executable_path(char *processdir, char *processname, int len)
{
char *filename;
if (readlink("/proc/self/exe", processdir, len) <= 0)
return -1;
filename = strrchr(processdir, '/');
if (filename == NULL)
return -1;
++filename;
strcpy(processname, filename);
*filename = '\0';
return (int)(filename - processdir);
}
2022-06-26 19:49:00 +08:00
int main(int argc, char *argv[], char **env)
{
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);
2022-07-07 16:52:24 +08:00
conf *conf = (struct CONF *)malloc(sizeof(struct CONF));
read_conf(path, conf);
2022-07-07 16:52:24 +08:00
//ptintf_conf(conf);
// 获取公网IP
public_ip = GET_PUBLIC_IP(conf->PUBLIC_IP);
//printf("%s", public_ip);
2022-06-26 19:49:00 +08:00
2022-06-26 19:49:00 +08:00
signal(SIGCHLD, sig_child); // 创建捕捉子进程退出信号
if (0 == strcmp(conf->DAEMON, "on")) {
2022-07-07 16:52:24 +08:00
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);
free(public_ip);
2019-09-24 08:53:00 +08:00
return 0;
}