修改获取公网IP方法,优化配置打印

修改:     Makefile
	修改:     README.md
	修改:     conf.c
	修改:     conf.h
	修改:     denyhosts.sh
	修改:     libiptc.c
	修改:     libiptc.h
	修改:     rhost.c
	修改:     rhost.conf
	修改:     rhost.h
This commit is contained in:
aixiao 2022-10-08 14:28:05 +08:00
parent a7ff1174c0
commit 9421d1f1eb
10 changed files with 268 additions and 214 deletions

View File

@ -1,6 +1,6 @@
CROSS_COMPILE ?=
CC := $(CROSS_COMPILE)gcc
CFLAGS += -O2 -g -Wall
CFLAGS += -Os -g -Wall
LIB += -lcurl -lip4tc
OBG = rhost

View File

@ -3,8 +3,16 @@ ssh防止暴力破解,适用Debian 8、9、11 Centos 7
支持钉钉告警和邮件告警
支持第三方QQ邮箱告警
支持一次运行检测、后台运行检测
```
Debian系统请安装libcurl库和libiptc库
Centos 7系统请安装libcurl库和iptables-devel库yum install iptables-devel libcurl-devel
apt install libip4tc-dev libcurl4-openssl-dev (或者libcurl4-gnutls-dev)
```
```
Centos 7系统请安装libcurl库和iptables-devel库
yum install iptables-devel libcurl-devel
```
```
@ -45,8 +53,6 @@ global {
DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=7f069c672cb878987aa6772cca336740eece4ce36bde12b51b45e9f440e0565a"; // 钉钉WEBHOOK
IS_QQMAIL = 0; // 开启QQ邮箱告警0关闭1开启
SEND_QQ = "1605227279"; // 发送者QQ
QQMAIL_KEY = "caczsjchvyibiabe"; // 发送者QQ密钥
RECV_MAIL = "1605227279"; // 接收者QQ
}
```

22
conf.c
View File

@ -145,6 +145,12 @@ static void parse_global_module(char *content, conf * conf)
return;
}
if (strcasecmp(var, "PUBLIC_IP") == 0) {
val_begin_len = val_end - val_begin;
if (copy_new_mem(val_begin, val_begin_len, &conf->PUBLIC_IP) != 0)
return;
}
content = strchr(lineEnd + 1, '\n');
}
}
@ -206,27 +212,43 @@ void read_conf(char *filename, conf * configure)
void free_conf(conf * conf)
{
if (conf->DAEMON)
free(conf->DAEMON);
if (conf->PHONE)
free(conf->PHONE);
if (conf->DING_WEBHOOK)
free(conf->DING_WEBHOOK);
if (conf->SEND_QQ)
free(conf->SEND_QQ);
if (conf->QQMAIL_KEY)
free(conf->QQMAIL_KEY);
if (conf->RECV_MAIL)
free(conf->RECV_MAIL);
if (conf->PUBLIC_IP)
free(conf->PUBLIC_IP);
return;
}
void ptintf_conf(conf * conf)
{
if (conf->DAEMON)
printf("%s\n", conf->DAEMON);
printf("%d\n", conf->TIME);
printf("%d\n", conf->REFUSE_NUMBER);
printf("%d\n", conf->IS_MAIL);
printf("%d\n", conf->IS_DING_WEBHOOK);
if (conf->PHONE)
printf("%s\n", conf->PHONE);
if (conf->DING_WEBHOOK)
printf("%s\n", conf->DING_WEBHOOK);
printf("%d\n", conf->IS_QQMAIL);
if (conf->SEND_QQ)
printf("%s\n", conf->SEND_QQ);
if (conf->QQMAIL_KEY)
printf("%s\n", conf->QQMAIL_KEY);
if (conf->RECV_MAIL)
printf("%s\n", conf->RECV_MAIL);
if (conf->PUBLIC_IP)
printf("%s\n", conf->PUBLIC_IP);
}

3
conf.h
View File

@ -13,6 +13,9 @@ typedef struct CONF {
int REFUSE_NUMBER;
// 获取公网IP Url地址
char *PUBLIC_IP;
int IS_MAIL;
int IS_DING_WEBHOOK;

View File

@ -9,7 +9,7 @@
source /etc/profile
function init() {
SEND_MAIL=0
SEND_MAIL=1
PWD_PATH="/root";
TIME=`date +"%Y%m%d%H%M"`;
LOG_FILE="${PWD_PATH}/${TIME}.log";
@ -28,7 +28,7 @@ function run()
free -hl &>> ${LOG_FILE}
echo "System process:" &>> ${LOG_FILE}
ps -auxwwjf &>> ${LOG_FILE}
ps -auxwwf &>> ${LOG_FILE}
echo "Network Connections" &>> ${LOG_FILE}
netstat -tnulp &>> ${LOG_FILE}

View File

@ -10,13 +10,12 @@ int x_get_rule(const char *chain, struct xtc_handle *handle, char *ipv4)
const char *t = iptc_get_target(entry, handle);
entry_match = (struct ipt_entry_match *)entry->elems;
//printf("u.user.name: %s\n", entry_match->u.user.name);
char addr[33];
memset(addr, 0, 33);
inet_ntop(AF_INET, &(entry->ip.dst), addr, sizeof(addr));
char addr[64];
memset(addr, 0, 64);
inet_ntop(AF_INET, &(entry->ip.src), addr, sizeof(addr));
//printf("%s\n", addr);
//printf("%s\n", t);
if (0 == strcmp(ipv4, addr) && 0 == strcmp(t, "DROP") && 0 == strcmp(entry_match->u.user.name, "tcp"))
{
if (0 == strcmp(ipv4, addr) && 0 == strcmp(t, "DROP") && 0 == strcmp(entry_match->u.user.name, "tcp")) {
r = 0;
break;
}
@ -35,8 +34,7 @@ int show_all_rule(char *ipv4)
handle = iptc_init("filter");
for (chain = iptc_first_chain(handle); chain; chain = iptc_next_chain(handle))
{
for (chain = iptc_first_chain(handle); chain; chain = iptc_next_chain(handle)) {
if (chain != NULL && handle != NULL) {
iptc_get_policy(chain, &counter, handle);
}
@ -70,6 +68,7 @@ static void parse_ports(const char *portstring, u_int16_t * ports)
ports[0] = buffer[0] ? parse_port(buffer) : 0;
ports[1] = cp[0] ? parse_port(cp) : 0xFFFF;
}
free(buffer);
}
@ -99,8 +98,7 @@ struct ipt_entry_match *get_match(const char *sports, const char *dports, unsign
return match;
}
int iptc_add_rule(const char *table, const char *chain, int protocol, const char *iniface, const char *outiface, unsigned int src,
unsigned int dest, const char *srcports, const char *destports, const char *target, const char *dnat_to, const int append)
int iptc_add_rule(const char *table, const char *chain, int protocol, const char *iniface, const char *outiface, unsigned int src, unsigned int dest, const char *srcports, const char *destports, const char *target, const char *dnat_to, const int append)
{
struct xtc_handle *handle;
struct ipt_entry *chain_entry;
@ -137,7 +135,7 @@ int iptc_add_rule(const char *table, const char *chain, int protocol, const char
size = IPT_ALIGN(sizeof(struct ipt_entry_target)) + IPT_ALIGN(sizeof(int));
entry_target = (struct ipt_entry_target *)calloc(1, size);
entry_target->u.user.target_size = size;
strncpy(entry_target->u.user.name, target, IPT_FUNCTION_MAXNAMELEN);
strncpy(entry_target->u.user.name, target, XT_EXTENSION_MAXNAMELEN);
}
if (entry_match) {
match_size = entry_match->u.match_size;
@ -200,7 +198,6 @@ int iptc_add_rule(const char *table, const char *chain, int protocol, const char
return 1;
}
if (entry_match)
free(entry_match);
free(entry_target);

View File

@ -18,7 +18,6 @@
/* Dest port. */
#define NFC_IP_DST_PT 0x0400
#ifndef IPT_MIN_ALIGN
#define IPT_MIN_ALIGN (__alignof__(struct ipt_entry))
#endif
@ -30,9 +29,7 @@
#define IPTC_TARGET_SIZE XT_ALIGN(sizeof(struct ipt_entry_target))
#define IPTC_FULL_SIZE IPTC_ENTRY_SIZE + IPTC_MATCH_SIZE + IPTC_TARGET_SIZE
int show_all_rule(char *ipv4);
int iptc_add_rule(const char *table, const char *chain, int protocol, const char *iniface, const char *outiface, unsigned int src,
unsigned int dest, const char *srcports, const char *destports, const char *target, const char *dnat_to, const int append);
int iptc_add_rule(const char *table, const char *chain, int protocol, const char *iniface, const char *outiface, unsigned int src, unsigned int dest, const char *srcports, const char *destports, const char *target, const char *dnat_to, const int append);
#endif

234
rhost.c
View File

@ -1,11 +1,76 @@
#include "conf.h"
#include "rhost.h"
#include "libiptc.h"
// 存储公网IP
char public_ip[BUFFER];
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()
@ -19,70 +84,18 @@ int check_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\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;
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;
}
@ -96,21 +109,19 @@ int dingding_warning(char *illegal_ip, char *public_ip, conf *conf)
return 1;
}
char jsonObj[BUFFER] = "{ \
#define JSIN "{ \
\"msgtype\": \"text\", \
\"text\": { \
\"content\": \"Alert @PHONE 主机PUBLIC 非法主机IP被封禁 Warning!\" \
\"content\": \"Alert @%s 服务器地址:%s封禁非法入侵主机:%s\" \
}, \
\"at\": { \
\"atMobiles\": [\"PHONE\"], \
\"atMobiles\": [\"%s\"], \
\"isAtAll\": false \
} \
}";
}"
strReplaceAll(jsonObj, "IP", illegal_ip);
strReplaceAll(jsonObj, "PHONE", conf->PHONE);
strReplaceAll(jsonObj, "PUBLIC", public_ip);
//printf("%s\n", jsonObj);
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");
@ -136,17 +147,20 @@ int dingding_warning(char *illegal_ip, char *public_ip, conf *conf)
}
// 邮件告警
int mail_warning(char *illegal_ip, char *public_ip)
int mail_warning(char *illegal_ip, char *public_ip, conf * conf)
{
FILE *fp = NULL;
char buff[BUFFER];
char text[BUFFER] = "echo \"主机:HOST, 禁止IP访问!\" |";
char text[BUFFER];
char temp[64];
memset(buff, 0, BUFFER);
strReplaceAll(text, "IP", illegal_ip);
strReplaceAll(text, "HOST", public_ip);
memset(text, 0, BUFFER);
memset(temp, 0, 64);
strcat(text, " mail -s \"System ban IP\" 1605227279@qq.com");
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);
if (NULL == (fp = popen(text, "r"))) {
perror("popen text");
@ -165,20 +179,21 @@ int mail_warning(char *illegal_ip, char *public_ip)
// 第三方邮箱告警
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);
char text[BUFFER];
char temp[32];
memset(string, 0, BUFFER + (sizeof(QQMAIL)));
memset(text, 0, BUFFER);
memset(temp, 0, 32);
sprintf(string, QQMAIL, conf->SEND_QQ, conf->QQMAIL_KEY, conf->RECV_MAIL, text);
strcpy(temp, public_ip);
temp[strlen(public_ip) - 1] = '\0';
system(string);
sprintf(text, "主机:%s, 禁止%s访问", temp, illegal_ip);
sprintf(string, QQMAIL, conf->RECV_MAIL, text);
return 0;
return system(string);
}
// 封禁非法IP
@ -250,7 +265,6 @@ int rule(conf *conf)
strcat(command, "\"");
strcat(command, awk);
if ((fp = popen(command, "r")) == NULL) // 执行命令
{
perror("popen command");
@ -275,7 +289,7 @@ int rule(conf *conf)
if (conf->IS_MAIL == 1) // 邮件告警
{
mail_warning(buffer, public_ip);
mail_warning(buffer, public_ip, conf);
sleep(3);
}
@ -294,9 +308,9 @@ int rule(conf *conf)
*/
// 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);
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);
}
@ -321,24 +335,45 @@ static void sig_child(int signo)
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);
}
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);
conf *conf = (struct CONF *)malloc(sizeof(struct CONF));
read_conf("rhost.conf", conf);
read_conf(path, conf);
//ptintf_conf(conf);
memset(public_ip, 0, BUFFER);
get_public_ip(public_ip);
// 新版本获取公网IP
public_ip = GET_PUBLIC_IP(conf->PUBLIC_IP);
//printf("%s", public_ip);
signal(SIGCHLD, sig_child); // 创建捕捉子进程退出信号
if (0 == strcmp(conf->DAEMON, "on"))
{
if (0 == strcmp(conf->DAEMON, "on")) {
goto goto_daemon;
}
if (argv[1] != NULL && 0 == strcmp(argv[1], "-d"))
{
if (argv[1] != NULL && 0 == strcmp(argv[1], "-d")) {
goto_daemon:
if (daemon(1, 1)) // 守护进程
{
@ -351,16 +386,13 @@ goto_daemon:
sleep(conf->TIME);
}
}
else
{
} else {
rule(conf);
}
free_conf(conf);
free(conf);
free(public_ip);
return 0;
}

View File

@ -2,7 +2,9 @@ global {
DAEMON = "off"; // on开启后台运行off不开启
TIME = "60"; // 睡眠时间
REFUSE_NUMBER = 5; // 拒绝攻击次数
PUBLIC_IP = "http://inet-ip.info"; // 获取公网IP
REFUSE_NUMBER = 3; // 拒绝攻击次数
IS_MAIL = 0; // 开启邮件告警
@ -11,7 +13,5 @@ global {
DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=7f069c672cb878987aa6772cca336740eece4ce36bde12b51b45e9f440e0565a"; // 钉钉WEBHOOK
IS_QQMAIL = 0; // 开启QQ邮箱告警
SEND_QQ = "1605227279"; // 发送者QQ
QQMAIL_KEY = "caczsjchvyibiabe"; // 发送者QQ密钥
RECV_MAIL = "1605227279"; // 接收者QQ
RECV_MAIL = "1605227279@qq.com"; // 接收者QQ
}

View File

@ -13,7 +13,6 @@
#include <sys/types.h>
#include <arpa/inet.h>
#define CENTOS_SYSTEM 1
#define DEBISN_SYSTEM 2
#define UNKNOWN_SYSTEM 3
@ -31,12 +30,10 @@
#define IPTABLES "`which iptables` -t filter -I INPUT -s %s -j DROP"
#define IPTABLES_CHECK "`which iptables` -t filter -C INPUT -s %s -j DROP 2> /dev/null"
#define QQMAIL "qqMail -l smtp.qq.com -p 25 -f %s -e %s -q NIUYULING -r %s@QQ.COM -n NIUYULING -s \"System ban IP\" -t \"%s\""
#define QQMAIL "email -r %s -s \"System ban IP\" -t \"%s\""
extern void read_conf(char *filename, conf * configure);
extern void free_conf(conf * conf);
extern void ptintf_conf(conf * conf);
#endif