#include "conf.h" #include "rhost.h" #include "libiptc.h" // 存储公网IP char *public_ip; struct MemoryStruct { char *memory; size_t size; }; static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { 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; } mem->memory = ptr; memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize; } // 获取公网IP static char *GET_PUBLIC_IP(char *URL) { CURL *curl_handle; CURLcode res; struct MemoryStruct chunk; 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); } curl_easy_cleanup(curl_handle); curl_global_cleanup(); return chunk.memory; } // 检测系统 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; } // 钉钉告警 int dingding_warning(char *illegal_ip, char *public_ip, conf *conf) { 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){ return 1; } CURL *curl; CURLcode res; curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); if (curl == NULL) { return 1; } #define JSIN "{ \ \"msgtype\": \"text\", \ \"text\": { \ \"content\": \"Alert @%s 服务器地址:%s,封禁非法入侵主机:%s\" \ }, \ \"at\": { \ \"atMobiles\": [\"%s\"], \ \"isAtAll\": false \ } \ }" sprintf(jsonObj, JSIN, conf->PHONE, temp, illegal_ip, conf->PHONE); 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]; char temp[64]; memset(buff, 0, BUFFER); memset(text, 0, BUFFER); memset(temp, 0, 64); strcpy(temp, public_ip); temp[strlen(public_ip)-1] = '\0'; sprintf(text, "主机:%s, 禁止%s访问", temp, illegal_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]; 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); printf("%s\n", string); 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))]; char p[2], splice_command[LONG_BUFFER], command[LONG_BUFFER], *temp, buffer[BUFFER], awk[BUFFER]; 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 库插入规则 iptables -t filter -A INPUT -p tcp -s xxxx -j DROP 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); // 新版本获取公网IP public_ip = GET_PUBLIC_IP("http://ip.sb"); //printf("%s", 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); free(public_ip); return 0; }