Compare commits

..

6 Commits

Author SHA1 Message Date
fa2ea1f83c Merge branch 'dev' 2024-05-22 15:26:08 +08:00
2722e9b2e1 修改帮助文件 2024-05-22 15:18:13 +08:00
f7f7d7136a 优化获取磁盘使用率 2024-05-22 15:10:19 +08:00
00567557ba 添加Nginx日志文件 2024-05-22 11:36:50 +08:00
778c9d5fff 增加Nginx规则 2024-05-21 15:28:20 +08:00
b5bd70ec71 增加Ng防护 2024-05-21 09:08:14 +08:00
16 changed files with 931 additions and 523 deletions

12
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,12 @@
{
"files.associations": {
"assert.h": "c",
"ip2region.h": "c",
"conf.h": "c",
"ccronexpr.h": "c",
"clamscan.h": "c",
"libiptc.h": "c",
"stdio.h": "c",
"nginx.h": "c"
}
}

View File

@ -36,9 +36,9 @@ LIBCOMMON__CFLAGS += -DHAVE_CONFIG_H -I./clamav/common -I./clamav/libclamav -I./
LIBCOMMON_LIB += ./clamav/common/cert_util.c.o ./clamav/common/actions.c.o ./clamav/common/clamdcom.c.o ./clamav/common/getopt.c.o ./clamav/common/hostid.c.o ./clamav/common/idmef_logging.c.o ./clamav/common/misc.c.o ./clamav/common/optparser.c.o ./clamav/common/output.c.o ./clamav/common/tar.c.o ./clamav/common/linux/cert_util_linux.c.o LIBCOMMON_LIB += ./clamav/common/cert_util.c.o ./clamav/common/actions.c.o ./clamav/common/clamdcom.c.o ./clamav/common/getopt.c.o ./clamav/common/hostid.c.o ./clamav/common/idmef_logging.c.o ./clamav/common/misc.c.o ./clamav/common/optparser.c.o ./clamav/common/output.c.o ./clamav/common/tar.c.o ./clamav/common/linux/cert_util_linux.c.o
all: libclamav_rust libclamav rhost all: libclamav_rust libclamav rhost nginx.o
rhost: conf.o rhost.o libiptc.o ccronexpr.o rhost: conf.o rhost.o libiptc.o ccronexpr.o nginx.o disk.o
$(CC) $(ip2region_CFLAGS) ip2region/ip2region.c $(CC) $(ip2region_CFLAGS) ip2region/ip2region.c
$(CC) $(ip2region_CFLAGS) ip2region/xdb_searcher.c $(CC) $(ip2region_CFLAGS) ip2region/xdb_searcher.c
$(CC) $(cJSON_CFLAGS) cJSON/cJSON.c $(CC) $(cJSON_CFLAGS) cJSON/cJSON.c
@ -69,7 +69,7 @@ libclamav:
test: test:
echo $(CMAKE) $(ARCH) echo $(CMAKE) $(ARCH) $(CFLAGS)
static: conf.o rhost.o libiptc.o static: conf.o rhost.o libiptc.o
$(CC) $(IPTC_CFLAGS) -c libiptc/libip4tc.c -o libiptc/libip4tc.o $(CC) $(IPTC_CFLAGS) -c libiptc/libip4tc.c -o libiptc/libip4tc.o

View File

@ -21,7 +21,7 @@ Debian
freshclam # 更新病毒库(必要) freshclam # 更新病毒库(必要)
Debian系统使用libiptc库需要nftables切换到iptables Debian系统使用libiptc库需要nftables切换到iptables (使用了libip4tc-dev库)
Switching to the legacy version:(切换到 iptables) Switching to the legacy version:(切换到 iptables)
update-alternatives --set iptables /usr/sbin/iptables-legacy update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
@ -65,10 +65,27 @@ make all
./rhost # 只处理非法攻击 ./rhost # 只处理非法攻击
关闭 关闭:
killall rhost killall rhost
帮助:
./rhost -h
Rhost Reject host&scan for viruses (Rhost 拒绝主机并扫描病毒)
Author: AIXIAO@AIXIAO.ME
Version: 1.0
Usage: [-?h] [-d]
Options:
-d : Background running
-? -h --help : help information
The configuration file needs to be in the same directory as the executable file!
配置文件需要与可执行文件位于同一目录中!
May 22 2024 15:05:59 Compile、link.
``` ```
```text ```text
@ -78,8 +95,10 @@ global {
DAEMON = "off"; // on开启后台运行,off不开启(弃用) DAEMON = "off"; // on开启后台运行,off不开启(弃用)
TIME = "10"; // 睡眠时间(大于等于1,单位秒) TIME = "10"; // 睡眠时间(大于等于1,单位秒)
PUBLIC_IP = "http://inet-ip.info"; // 获取公网IP PUBLIC_IP = "http://inet-ip.info"; // 获取公网IP
IS_DISK = 1; // 磁盘使用率(1开启,非1关闭) IS_DISK = 1; // 磁盘使用率(1开启,非1关闭)
DISK_USE = 95; // 任意某块磁盘使用率告警(大于等于1) DISK_USE = 95; // 任意某块磁盘使用率告警(大于等于1)
@ -87,32 +106,36 @@ global {
IS_BLOCKED = 1; // 是否封禁攻击IP(1开启,非1关闭) IS_BLOCKED = 1; // 是否封禁攻击IP(1开启,非1关闭)
REFUSE_NUMBER = 3; // 拒绝攻击次数 REFUSE_NUMBER = 3; // 拒绝攻击次数
CLAMAV = 1; // clamav 是否扫描病毒(1开启,非1关闭) CLAMAV = 1; // clamav 是否扫描病毒(1开启,非1关闭)
CLAMAV_ARG = "-r / --exclude-dir=^/sys|^/dev|^/proc|^/opt/infected|^/root|^/home|^/mnt|^/usr|^/var --move=/opt/infected --max-filesize 1024M -l clamscan.log"; CLAMAV_ARG = "-r / --exclude-dir=^/sys|^/dev|^/proc|^/opt/infected|^/root|^/home|^/mnt|^/usr|^/var --move=/opt/infected --max-filesize 1024M -l clamscan.log";
CLAMAV_TIME = "* 1 4 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周) CLAMAV_TIME = "* 45 11 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周)
IPV4_RESTRICTION = 1; // 是否启用IP白名单(1开启,非1关闭) IPV4_RESTRICTION = 1; // 是否启用IP白名单(1开启,非1关闭)
IPV4_WHITE_LIST = "1.1.1.1 2.2.2.2 "; // IP白名单(空格隔开) IPV4_WHITE_LIST = "1.1.1.1 2.2.2.2 "; // IP白名单(空格隔开)
REGION = 1; // 是否启用地域白名单(1开启,非1关闭) REGION = 1; // 是否启用地域白名单(1开启,非1关闭)
IP2REGION = 1; // 是否使用本地 ip2region 地址定位库(1使用,非1不使用) IP2REGION = 1; // 是否使用本地 ip2region 地址定位库(1使用,非1不使用)
//REGION_URL = "http://opendata.baidu.com/api.php?query=%s&co=&resource_id=6006&oe=utf8"; // 获取IP地域(aliyun付费API, 弃用) REGION_LIST = "河南 郑州 上海"; // 地域列表(空格隔开)
REGION_URL = "https://api01.aliyun.venuscn.com/ip?ip=%s -H Authorization:APPCODE a1d842b8afda418c8ea24271a4e16b1f";
REGION_LIST = "河南 郑州 上海"; // 地域列表(空格隔开)
NGINX = 1; // 是否启用Nginx白名单
NGINX_LOG_FILE= "/usr/local/nginx/logs/access.log"; // Nginx 日志文件
NGINX_REGION_LIST = "中国 河南 郑州 上海"; // 地域列表(空格隔开)
IS_MAIL = 0; // 开启邮件告警(1开启,非1关闭) IS_MAIL = 0; // 开启邮件告警(1开启,非1关闭)
IS_DING_WEBHOOK = 0; // 开启叮叮告警(1开启,非1关闭) IS_DING_WEBHOOK = 1; // 开启叮叮告警(1开启,非1关闭)
PHONE = "15565979082"; // @的人手机号 PHONE = "15565979082"; // @的人手机号
DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=7f069c672cb878987aa6772cca336740eece4ce36bde12b51b45e9f440e0565a"; // 钉钉WEBHOOK DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=396bce0384cded025087cff3c176ea5e9afb9bd8fcaa46d6fa8c51dd172ba513"; // 钉钉WEBHOOK
IS_QQMAIL = 1; // 开启QQ邮箱告警(默认使用gomailhttps://git.aixiao.me/aixiao/gomail.git)(1开启,非1关闭) IS_QQMAIL = 1; // 开启QQ邮箱告警(默认使用gomail: https://git.aixiao.me/aixiao/gomail.git)(1开启,非1关闭)
RECV_MAIL = "1605227279@qq.com"; // 接收者QQ RECV_MAIL = "1605227279@qq.com"; // 接收者邮箱
} }

View File

@ -1 +1 @@
{"rustc_fingerprint":537842707314038760,"outputs":{"10376369925670944939":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/usr\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.63.0\nbinary: rustc\ncommit-hash: unknown\ncommit-date: unknown\nhost: x86_64-unknown-linux-gnu\nrelease: 1.63.0\nLLVM version: 14.0.6\n","stderr":""},"15493033989842322569":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/usr\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"15697416045686424142":{"success":false,"status":"exit status: 1","code":1,"stdout":"","stderr":"error: `-Csplit-debuginfo` is unstable on this platform\n\n"},"9218888252049904301":{"success":false,"status":"exit status: 1","code":1,"stdout":"","stderr":"error: `-Csplit-debuginfo` is unstable on this platform\n\n"}},"successes":{}} {"rustc_fingerprint":5376818386984183904,"outputs":{"14371922958718593042":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/usr\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.71.1\nbinary: rustc\ncommit-hash: unknown\ncommit-date: unknown\nhost: x86_64-unknown-linux-gnu\nrelease: 1.71.1\nLLVM version: 16.0.6\n","stderr":""},"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/usr\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}

29
conf.c
View File

@ -219,6 +219,24 @@ static void parse_global_module(char *content, conf * conf)
conf->DISK_USE = atoi(val_begin); conf->DISK_USE = atoi(val_begin);
} }
// NGINX
if (strcasecmp(var, "NGINX") == 0) {
val_begin_len = val_end - val_begin;
conf->NGINX = atoi(val_begin);
}
if (strcasecmp(var, "NGINX_LOG_FILE") == 0) {
val_begin_len = val_end - val_begin;
conf->NGINX_LOG_FILE_LEN = val_begin_len;
if (copy_new_mem(val_begin, val_begin_len, &conf->NGINX_LOG_FILE) != 0)
return;
}
if (strcasecmp(var, "NGINX_REGION_LIST") == 0) {
val_begin_len = val_end - val_begin;
conf->NGINX_REGION_LIST_LEN = val_begin_len;
if (copy_new_mem(val_begin, val_begin_len, &conf->NGINX_REGION_LIST) != 0)
return;
}
content = strchr(lineEnd + 1, '\n'); content = strchr(lineEnd + 1, '\n');
} }
} }
@ -313,6 +331,11 @@ void free_conf(conf * conf)
if (conf->CLAMAV_ARG) if (conf->CLAMAV_ARG)
free(conf->CLAMAV_ARG); free(conf->CLAMAV_ARG);
// NGINX
if (conf->NGINX_LOG_FILE)
free(conf->NGINX_LOG_FILE);
if (conf->NGINX_REGION_LIST)
free(conf->NGINX_REGION_LIST);
return; return;
} }
@ -351,6 +374,12 @@ void ptintf_conf(conf * conf)
if (conf->CLAMAV_ARG) if (conf->CLAMAV_ARG)
printf("CLAMAV_ARG %s %d\n", conf->CLAMAV_ARG, conf->CLAMAV_ARG_LEN); printf("CLAMAV_ARG %s %d\n", conf->CLAMAV_ARG, conf->CLAMAV_ARG_LEN);
// Nginx
if (conf->NGINX_LOG_FILE)
printf("CLAMAV_ARG %s %d\n", conf->NGINX_LOG_FILE, conf->NGINX_LOG_FILE_LEN);
if (conf->NGINX_REGION_LIST)
printf("CLAMAV_ARG %s %d\n", conf->NGINX_REGION_LIST, conf->NGINX_REGION_LIST_LEN);
} }
void split_string(char string[], char delims[], char (*whitelist_ip)[WHITELIST_IP_NUM]) void split_string(char string[], char delims[], char (*whitelist_ip)[WHITELIST_IP_NUM])

7
conf.h
View File

@ -44,6 +44,13 @@ typedef struct CONF
char *IPV4_WHITE_LIST; char *IPV4_WHITE_LIST;
int IPV4_WHITE_LIST_LEN; int IPV4_WHITE_LIST_LEN;
// NGINX
int NGINX;
char *NGINX_LOG_FILE;
int NGINX_LOG_FILE_LEN;
char *NGINX_REGION_LIST;
int NGINX_REGION_LIST_LEN;
int IS_MAIL; int IS_MAIL;
// 钉钉 // 钉钉

59
disk.c Normal file
View File

@ -0,0 +1,59 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mntent.h>
#include <sys/statvfs.h>
// 获取指定路径的磁盘使用率
int get_disk_usage(const char *path, double *usage) {
struct statvfs stat;
if (statvfs(path, &stat) != 0) {
// 处理错误
perror("statvfs failed");
return -1;
}
// 计算磁盘使用率
unsigned long total_blocks = stat.f_blocks;
unsigned long free_blocks = stat.f_bfree;
unsigned long used_blocks = total_blocks - free_blocks;
*usage = (double)used_blocks / total_blocks * 100;
return 0;
}
int disk_usage() {
FILE *mounts;
struct mntent *ent;
mounts = setmntent("/etc/mtab", "r");
if (mounts == NULL) {
perror("setmntent failed");
return 1;
}
while ((ent = getmntent(mounts)) != NULL)
{
double usage = 0;
if (strstr(ent->mnt_fsname, "/dev/") != NULL)
{
//printf("%s %s %s\n", ent->mnt_fsname, ent->mnt_dir, ent->mnt_type);
if (get_disk_usage(ent->mnt_dir, &usage) != 0) {
fprintf(stderr, "Failed to get disk usage for %s\n", ent->mnt_dir);
continue;
}
int threshold = 1;
if (usage > threshold) {
printf("挂载点: %s 使用率: %.2f%% 阀值: %d%%\n", ent->mnt_dir, usage, threshold);
}
}
}
endmntent(mounts);
return 0;
}

12
disk.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef DISK_H
#define DISK_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mntent.h>
#include <sys/statvfs.h>
extern int disk_usage();
#endif

View File

@ -105,7 +105,8 @@ struct ipt_entry_match *get_match(const char *sports, const char *dports, unsign
return match; 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 xtc_handle *handle;
struct ipt_entry *chain_entry; struct ipt_entry *chain_entry;
@ -116,6 +117,10 @@ int iptc_add_rule(const char *table, const char *chain, int protocol, const char
int result = 0; int result = 0;
chain_entry = (struct ipt_entry *)calloc(1, sizeof(*chain_entry)); chain_entry = (struct ipt_entry *)calloc(1, sizeof(*chain_entry));
if (chain_entry == NULL) {
perror("calloc failed");
return 1;
}
if (src != 0) { if (src != 0) {
chain_entry->ip.src.s_addr = src; chain_entry->ip.src.s_addr = src;
@ -137,7 +142,8 @@ int iptc_add_rule(const char *table, const char *chain, int protocol, const char
if (IPPROTO_TCP == protocol) if (IPPROTO_TCP == protocol)
entry_match = get_match(srcports, destports, &chain_entry->nfcache, "tcp"); entry_match = get_match(srcports, destports, &chain_entry->nfcache, "tcp");
if (strcmp(target, "") == 0 || strcmp(target, IPTC_LABEL_ACCEPT) == 0 || strcmp(target, IPTC_LABEL_DROP) == 0 || strcmp(target, IPTC_LABEL_QUEUE) == 0 || strcmp(target, IPTC_LABEL_RETURN) == 0) { if (strcmp(target, "") == 0 || strcmp(target, IPTC_LABEL_ACCEPT) == 0 || strcmp(target, IPTC_LABEL_DROP) == 0 || \
strcmp(target, IPTC_LABEL_QUEUE) == 0 || strcmp(target, IPTC_LABEL_RETURN) == 0) {
size_t size; size_t size;
size = IPT_ALIGN(sizeof(struct ipt_entry_target)) + IPT_ALIGN(sizeof(int)); size = IPT_ALIGN(sizeof(struct ipt_entry_target)) + IPT_ALIGN(sizeof(int));
entry_target = (struct ipt_entry_target *)calloc(1, size); entry_target = (struct ipt_entry_target *)calloc(1, size);
@ -193,6 +199,7 @@ int iptc_add_rule(const char *table, const char *chain, int protocol, const char
result = iptc_insert_entry(labelit, chain_entry, 0, handle); result = iptc_insert_entry(labelit, chain_entry, 0, handle);
} }
if (!result) { if (!result) {
printf("libiptc error: Can't add, %s\n", iptc_strerror(errno)); printf("libiptc error: Can't add, %s\n", iptc_strerror(errno));
free(chain_entry); free(chain_entry);

View File

@ -30,6 +30,7 @@
#define IPTC_FULL_SIZE IPTC_ENTRY_SIZE + IPTC_MATCH_SIZE + IPTC_TARGET_SIZE #define IPTC_FULL_SIZE IPTC_ENTRY_SIZE + IPTC_MATCH_SIZE + IPTC_TARGET_SIZE
int show_all_rule(char *ipv4); 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 #endif

275
libiptc/iptc_delete_rule.c Normal file
View File

@ -0,0 +1,275 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <libiptc/libiptc.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define NFC_IP_SRC_PT 0x0200
#define NFC_IP_DST_PT 0x0400
#ifndef IPT_MIN_ALIGN
#define IPT_MIN_ALIGN (__alignof__(struct ipt_entry))
#endif
#define IPT_ALIGN(s) (((s) + ((IPT_MIN_ALIGN)-1)) & ~((IPT_MIN_ALIGN)-1))
#define IPTC_ENTRY_SIZE XT_ALIGN(sizeof(struct ipt_entry))
#define IPTC_MATCH_SIZE XT_ALIGN(sizeof(struct ipt_entry_match) + sizeof(struct ipt_udp))
#define IPTC_TARGET_SIZE XT_ALIGN(sizeof(struct ipt_entry_target))
#define IPTC_FULL_SIZE IPTC_ENTRY_SIZE + IPTC_MATCH_SIZE + IPTC_TARGET_SIZE
#define IPTC_LABEL_ACCEPT "ACCEPT"
#define IPTC_LABEL_DROP "DROP"
#define IPTC_LABEL_QUEUE "QUEUE"
#define IPTC_LABEL_RETURN "RETURN"
static u_int16_t parse_port(const char *port)
{
return atoi(port);
}
static void parse_ports(const char *portstring, u_int16_t *ports)
{
char *buffer;
char *cp;
buffer = strdup(portstring);
if ((cp = strchr(buffer, ':')) == NULL)
ports[0] = ports[1] = parse_port(buffer);
else {
*cp = '\0';
cp++;
ports[0] = buffer[0] ? parse_port(buffer) : 0;
ports[1] = cp[0] ? parse_port(cp) : 0xFFFF;
}
free(buffer);
}
struct ipt_entry_match *get_match(const char *sports, const char *dports, unsigned int *nfcache, const char *protocol)
{
struct ipt_entry_match *match;
struct ipt_udp *udpinfo;
size_t size;
size = IPT_ALIGN(sizeof(*match)) + IPT_ALIGN(sizeof(*udpinfo));
match = (struct ipt_entry_match *)calloc(1, size);
if (!match) {
perror("calloc failed for match");
return NULL;
}
match->u.match_size = size;
strncpy(match->u.user.name, protocol, IPT_FUNCTION_MAXNAMELEN - 2);
match->u.user.name[IPT_FUNCTION_MAXNAMELEN - 2] = '\0';
udpinfo = (struct ipt_udp *)match->data;
udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF;
if (sports) {
*nfcache |= NFC_IP_SRC_PT;
parse_ports(sports, udpinfo->spts);
}
if (dports) {
*nfcache |= NFC_IP_DST_PT;
parse_ports(dports, udpinfo->dpts);
}
return match;
}
// 打印 IP 地址
void print_ip_address(const char *label, struct in_addr addr) {
char ip_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &addr, ip_str, sizeof(ip_str));
printf("%s: %s\n", label, ip_str);
}
// 打印规则详细信息
void print_rule(const char *label, const struct ipt_entry *entry) {
printf("%s:\n", label);
print_ip_address(" src", entry->ip.src);
print_ip_address(" dst", entry->ip.dst);
printf(" proto: %u\n", entry->ip.proto);
printf(" iniface: %s\n", entry->ip.iniface);
printf(" outiface: %s\n", entry->ip.outiface);
printf(" target_offset: %u\n", entry->target_offset);
printf(" next_offset: %u\n", entry->next_offset);
printf(" counters: pkts=%llu, bytes=%llu\n", entry->counters.pcnt, entry->counters.bcnt);
}
// 打印匹配结构详细信息
void print_match(const char *label, const struct ipt_entry_match *match) {
printf("%s:\n", label);
printf(" match_size: %u\n", match->u.user.match_size);
printf(" name: %s\n", match->u.user.name);
printf(" revision: %u\n", match->u.user.revision);
// 如果有特定协议的数据,例如 TCP 或 UDP可以在这里打印具体内容
// 例如:匹配 TCP 协议时,打印源端口和目标端口
if (strcmp(match->u.user.name, "tcp") == 0) {
struct ipt_tcp *tcpinfo = (struct ipt_tcp *)match->data;
printf(" TCP source port: %u\n", ntohs(tcpinfo->spts[0]));
printf(" TCP destination port: %u\n", ntohs(tcpinfo->dpts[0]));
} else if (strcmp(match->u.user.name, "udp") == 0) {
struct ipt_udp *udpinfo = (struct ipt_udp *)match->data;
printf(" UDP source port: %u\n", ntohs(udpinfo->spts[0]));
printf(" UDP destination port: %u\n", ntohs(udpinfo->dpts[0]));
}
}
// 打印目标结构详细信息
void print_target(const char *label, const struct ipt_entry_target *target) {
printf("%s:\n", label);
printf(" target_size: %u\n", target->u.user.target_size);
printf(" name: %s\n", target->u.user.name);
printf(" revision: %u\n", target->u.user.revision);
}
int iptc_delete_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)
{
struct xtc_handle *handle = NULL;
struct ipt_entry *chain_entry = NULL;
struct ipt_entry_match *entry_match = NULL;
struct ipt_entry_target *entry_target = NULL;
ipt_chainlabel labelit;
long match_size = 0;
int result = 1; // Default to failure
// Initialize rule entry
chain_entry = (struct ipt_entry *)calloc(1, sizeof(*chain_entry));
if (!chain_entry) {
perror("calloc failed");
return 1;
}
if (src != 0) {
chain_entry->ip.src.s_addr = src;
chain_entry->ip.smsk.s_addr = 0xFFFFFFFF;
}
if (dest != 0) {
chain_entry->ip.dst.s_addr = dest;
chain_entry->ip.dmsk.s_addr = 0xFFFFFFFF;
}
if (iniface)
strncpy(chain_entry->ip.iniface, iniface, IFNAMSIZ);
if (outiface)
strncpy(chain_entry->ip.outiface, outiface, IFNAMSIZ);
chain_entry->ip.proto = protocol;
if (IPPROTO_UDP == protocol)
entry_match = get_match(srcports, destports, &chain_entry->nfcache, "udp");
if (IPPROTO_TCP == protocol)
entry_match = get_match(srcports, destports, &chain_entry->nfcache, "tcp");
print_match("entry_match", entry_match);
if (strcmp(target, "") == 0 || strcmp(target, IPTC_LABEL_ACCEPT) == 0 || strcmp(target, IPTC_LABEL_DROP) == 0 || strcmp(target, IPTC_LABEL_QUEUE) == 0 || strcmp(target, IPTC_LABEL_RETURN) == 0) {
size_t size;
size = IPT_ALIGN(sizeof(struct ipt_entry_target)) + IPT_ALIGN(sizeof(int));
entry_target = (struct ipt_entry_target *)calloc(1, size);
if (!entry_target) {
perror("calloc failed for target");
goto cleanup;
}
entry_target->u.user.target_size = size;
strncpy(entry_target->u.user.name, target, XT_EXTENSION_MAXNAMELEN);
entry_target->u.user.name[XT_EXTENSION_MAXNAMELEN - 1] = '\0';
}
match_size = entry_match ? entry_match->u.match_size : 0;
print_target("entry_target", entry_target);
struct ipt_entry *tmp_ipt = chain_entry;
chain_entry = (struct ipt_entry *)realloc(chain_entry, sizeof(*chain_entry) + match_size + entry_target->u.target_size);
if (!chain_entry) {
free(tmp_ipt);
free(entry_target);
if (entry_match) free(entry_match);
perror("realloc failed");
return 1;
}
memcpy(chain_entry->elems + match_size, entry_target, entry_target->u.target_size);
chain_entry->target_offset = sizeof(*chain_entry) + match_size;
chain_entry->next_offset = sizeof(*chain_entry) + match_size + entry_target->u.target_size;
if (entry_match) {
memcpy(chain_entry->elems, entry_match, match_size);
}
handle = iptc_init(table);
if (!handle) {
fprintf(stderr, "libiptc error: Can't initialize table %s, %s\n", table, iptc_strerror(errno));
goto cleanup;
}
strncpy(labelit, chain, sizeof(ipt_chainlabel));
labelit[sizeof(ipt_chainlabel) - 1] = '\0';
if (0 == iptc_is_chain(labelit, handle)) {
fprintf(stderr, "libiptc error: Chain %s does not exist!\n", labelit);
goto cleanup;
}
// 打印 chain_entry 详细信息
print_rule("Chain entry", chain_entry);
// Find and delete the matching rule
const struct ipt_entry *entry;
unsigned int rule_num = 0;
for (entry = iptc_first_rule(labelit, handle); entry; (entry = iptc_next_rule(entry, handle), ++rule_num))
{
if (entry->ip.proto == chain_entry->ip.proto &&
entry->ip.src.s_addr == chain_entry->ip.src.s_addr &&
entry->ip.dst.s_addr == chain_entry->ip.dst.s_addr &&
strncmp(entry->ip.iniface, chain_entry->ip.iniface, IFNAMSIZ) == 0 &&
strncmp(entry->ip.outiface, chain_entry->ip.outiface, IFNAMSIZ) == 0)
{
// 打印当前 entry 详细信息
print_rule("Current entry", entry);
printf("Matching rule found. Deleting rule number: %u\n", rule_num);
// 删除规则
if (!iptc_delete_num_entry(labelit, rule_num, handle)) {
fprintf(stderr, "libiptc error: Can't delete entry, %s\n", iptc_strerror(errno));
iptc_free(handle);
return result;
}
// 提交更改
if (!iptc_commit(handle)) {
fprintf(stderr, "libiptc error: Commit error, %s\n", iptc_strerror(errno));
} else {
printf("Rule deleted successfully\n");
result = 0;
break;
}
}
}
cleanup:
if (entry_match) free(entry_match);
if (entry_target) free(entry_target);
if (chain_entry) free(chain_entry);
if (handle) iptc_free(handle);
return result;
}
int main(int argc, char *argv[]) {
// Test deleting rule
unsigned int srcIp;
inet_pton(AF_INET, argv[1], &srcIp);
int result = iptc_delete_rule("filter", "INPUT", IPPROTO_TCP, NULL, NULL, srcIp, 0, NULL, NULL, IPTC_LABEL_DROP);
return result;
}

155
nginx.c Normal file
View File

@ -0,0 +1,155 @@
#include "nginx.h"
#define EVENT_SIZE (sizeof(struct inotify_event))
#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
#define INITIAL_BUFFER_SIZE 8192
void nginx_iptc(char *ip)
{
unsigned int srcIp;
inet_pton(AF_INET, ip, &srcIp);
iptc_add_rule("filter", "INPUT", IPPROTO_TCP, NULL, NULL, srcIp, 0, NULL, NULL, "DROP", NULL, 1);
}
int IP_location(char *string, conf *config)
{
char *area = NULL;
char *xdb_path = "ip2region.xdb";
char *p = strchr(string, ' ');
char IP[64];
memset(IP, 0, 64);
char *t = _time();
char nginx_region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } };
char NGINX_REGION_LIST_COPY[config->NGINX_REGION_LIST_LEN + 1];
memset(NGINX_REGION_LIST_COPY, 0, config->NGINX_REGION_LIST_LEN + 1);
memcpy(NGINX_REGION_LIST_COPY, config->NGINX_REGION_LIST, config->NGINX_REGION_LIST_LEN); // 复制配置字符串split_string()会改变原数据
split_string(NGINX_REGION_LIST_COPY, " ", nginx_region_list);
// IP 地理位置获取
if ((p - string) > 0) {
memmove(IP, string, p - string);
} else {
printf("Invalid IP string format.\n");
return -1;
}
if (access(xdb_path, F_OK) == -1) { // 判断 ip2region 地址定位库是否存在
xdb_path = "ip2region/ip2region.xdb";
if (access(xdb_path, F_OK) == -1) {
printf("ip2region.xdb DOESN'T EXIST!\n");
return -1;
}
}
area = ip2region(xdb_path, IP);
if (area == NULL) {
printf("ip2region解析地域错误\n");
return -1;
}
my_printf("IP地址:%s, %s\n", IP, area);
//printf("%s, %s\n", config->NGINX_LOG_FILE, config->NGINX_REGION_LIST);
if (config->NGINX == 1) // 开启Nginx防御
{
if (isregion(area, nginx_region_list) == 1) { // 返回1表示在白名单列表
printf(RED "%s Nginx Ip Address: %s, 属于地域白名单: %s\n" COLOR_NONE, t, IP, area);
} else {
my_printf(RED "%s Nginx 封禁 Ip Address: %s, 地址: %s!!!\n" COLOR_NONE, t, IP, area);
nginx_iptc(IP);
}
}
return 0;
}
int nginx_read_log(const char *filename, conf *p)
{
int fd = open(p->NGINX_LOG_FILE, O_RDONLY);
if (fd == -1) {
perror("open");
return -1;
}
// Move to the end of the file
if (lseek(fd, 0, SEEK_END) == -1) {
perror("lseek");
close(fd);
return -1;
}
int inotify_fd = inotify_init();
if (inotify_fd < 0) {
perror("inotify_init");
close(fd);
return -1;
}
int wd = inotify_add_watch(inotify_fd, p->NGINX_LOG_FILE, IN_MODIFY);
if (wd == -1) {
perror("inotify_add_watch");
close(inotify_fd);
close(fd);
return -1;
}
char buffer[EVENT_BUF_LEN];
// Set the file descriptor to non-blocking mode
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
perror("fcntl F_GETFL");
inotify_rm_watch(inotify_fd, wd);
close(inotify_fd);
close(fd);
return -1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
perror("fcntl F_SETFL");
inotify_rm_watch(inotify_fd, wd);
close(inotify_fd);
close(fd);
return -1;
}
// Initial dynamic buffer allocation
size_t buffer_size = INITIAL_BUFFER_SIZE;
char *read_buf = alloca(buffer_size);
if (!read_buf) {
perror("alloca");
inotify_rm_watch(inotify_fd, wd);
close(inotify_fd);
close(fd);
return -1;
}
while (1) {
int length = read(inotify_fd, buffer, EVENT_BUF_LEN);
if (length < 0) {
perror("read");
break;
}
for (int i = 0; i < length;) {
struct inotify_event *event = (struct inotify_event *)&buffer[i];
if (event->mask & IN_MODIFY) {
int bytes_read;
while ((bytes_read = read(fd, read_buf, buffer_size - 1)) > 0) {
read_buf[bytes_read] = '\0';
IP_location(read_buf, p);
}
if (bytes_read == -1 && errno != EAGAIN) {
perror("read");
break;
}
}
i += EVENT_SIZE + event->len;
}
}
inotify_rm_watch(inotify_fd, wd);
close(inotify_fd);
close(fd);
return 0;
}

19
nginx.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef NGINX_H
#define NGINX_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/inotify.h>
#include <errno.h>
#include <fcntl.h>
#include "rhost.h"
#include "libiptc.h"
#include "ip2region/ip2region.h"
extern int nginx_read_log(const char *filename, conf * conf);
#endif

596
rhost.c

File diff suppressed because it is too large Load Diff

View File

@ -3,8 +3,10 @@ global {
DAEMON = "off"; // on开启后台运行,off不开启(弃用) DAEMON = "off"; // on开启后台运行,off不开启(弃用)
TIME = "10"; // 睡眠时间(大于等于1,单位秒) TIME = "10"; // 睡眠时间(大于等于1,单位秒)
PUBLIC_IP = "http://inet-ip.info"; // 获取公网IP PUBLIC_IP = "http://inet-ip.info"; // 获取公网IP
IS_DISK = 1; // 磁盘使用率(1开启,非1关闭) IS_DISK = 1; // 磁盘使用率(1开启,非1关闭)
DISK_USE = 95; // 任意某块磁盘使用率告警(大于等于1) DISK_USE = 95; // 任意某块磁盘使用率告警(大于等于1)
@ -12,9 +14,10 @@ global {
IS_BLOCKED = 1; // 是否封禁攻击IP(1开启,非1关闭) IS_BLOCKED = 1; // 是否封禁攻击IP(1开启,非1关闭)
REFUSE_NUMBER = 3; // 拒绝攻击次数 REFUSE_NUMBER = 3; // 拒绝攻击次数
CLAMAV = 1; // clamav 是否扫描病毒(1开启,非1关闭) CLAMAV = 1; // clamav 是否扫描病毒(1开启,非1关闭)
CLAMAV_ARG = "-r / --exclude-dir=^/sys|^/dev|^/proc|^/opt/infected --move=/opt/infected --max-filesize 1024M -l clamscan.log"; CLAMAV_ARG = "-r / --exclude-dir=^/sys|^/dev|^/proc|^/opt/infected|^/root|^/home|^/mnt|^/usr|^/var --move=/opt/infected --max-filesize 1024M -l clamscan.log";
CLAMAV_TIME = "* 7 23 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周) CLAMAV_TIME = "* 45 11 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周)
IPV4_RESTRICTION = 1; // 是否启用IP白名单(1开启,非1关闭) IPV4_RESTRICTION = 1; // 是否启用IP白名单(1开启,非1关闭)
@ -23,18 +26,22 @@ global {
REGION = 1; // 是否启用地域白名单(1开启,非1关闭) REGION = 1; // 是否启用地域白名单(1开启,非1关闭)
IP2REGION = 1; // 是否使用本地 ip2region 地址定位库(1使用,非1不使用) IP2REGION = 1; // 是否使用本地 ip2region 地址定位库(1使用,非1不使用)
REGION_URL = "http://opendata.baidu.com/api.php?query=%s&co=&resource_id=6006&oe=utf8"; // 获取IP地域API
REGION_LIST = "河南 郑州 上海"; // 地域列表(空格隔开) REGION_LIST = "河南 郑州 上海"; // 地域列表(空格隔开)
NGINX = 1; // 是否启用Nginx白名单
NGINX_LOG_FILE= "/usr/local/nginx/logs/access.log"; // Nginx 日志文件
NGINX_REGION_LIST = "中国 河南 郑州 上海"; // 地域列表(空格隔开)
IS_MAIL = 0; // 开启邮件告警(1开启,非1关闭) IS_MAIL = 0; // 开启邮件告警(1开启,非1关闭)
IS_DING_WEBHOOK = 0; // 开启叮叮告警(1开启,非1关闭) IS_DING_WEBHOOK = 1; // 开启叮叮告警(1开启,非1关闭)
PHONE = "15565979082"; // @的人手机号 PHONE = "15565979082"; // @的人手机号
DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=7f069c672cb878987aa6772cca336740eece4ce36bde12b51b45e9f440e0565a"; // 钉钉WEBHOOK DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=396bce0384cded025087cff3c176ea5e9afb9bd8fcaa46d6fa8c51dd172ba513"; // 钉钉WEBHOOK
IS_QQMAIL = 1; // 开启QQ邮箱告警(默认使用gomailhttps://git.aixiao.me/aixiao/gomail.git)(1开启,非1关闭) IS_QQMAIL = 1; // 开启QQ邮箱告警(默认使用gomail: https://git.aixiao.me/aixiao/gomail.git)(1开启,非1关闭)
RECV_MAIL = "1605227279@qq.com"; // 接收者邮箱 RECV_MAIL = "1605227279@qq.com"; // 接收者邮箱
} }

60
rhost.h
View File

@ -12,13 +12,12 @@
#include <curl/curl.h> #include <curl/curl.h>
#include <sys/types.h> #include <sys/types.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h> #include <assert.h>
#include <limits.h>
#include <stdarg.h>
#include "./cJSON/cJSON.h"
#include "ip2region/ip2region.h" #include "conf.h"
typedef struct now_next_time typedef struct now_next_time
@ -42,51 +41,6 @@ typedef struct now_next_time
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include "ccronexpr.h"
#define MAX_SECONDS 60
#define CRON_MAX_MINUTES 60
#define CRON_MAX_HOURS 24
#define CRON_MAX_DAYS_OF_WEEK 8
#define CRON_MAX_DAYS_OF_MONTH 32
#define CRON_MAX_MONTHS 12
#define INVALID_INSTANT ((time_t) -1)
#define DATE_FORMAT "%Y-%m-%d_%H:%M:%S"
#ifndef ARRAY_LEN
#define ARRAY_LEN(x) sizeof(x)/sizeof(x[0])
#endif
#ifdef CRON_TEST_MALLOC
static int cronAllocations = 0;
static int cronTotalAllocations = 0;
static int maxAlloc = 0;
void* cron_malloc(size_t n)
{
cronAllocations++;
cronTotalAllocations++;
if (cronAllocations > maxAlloc)
{
maxAlloc = cronAllocations;
}
return malloc(n);
}
void cron_free(void* p)
{
cronAllocations--;
free(p);
}
#endif
#define COLOR_NONE "\033[0m" //表示清除前面设置的格式 #define COLOR_NONE "\033[0m" //表示清除前面设置的格式
@ -107,9 +61,7 @@ void cron_free(void* p)
#define BUILD(fmt...) do { fprintf(stderr,"%s %s ",__DATE__,__TIME__); fprintf(stderr, ##fmt); } while(0) #define BUILD(fmt...) do { fprintf(stderr,"%s %s ",__DATE__,__TIME__); fprintf(stderr, ##fmt); } while(0)
#define AWK " | awk -v num=%d '{a[$1]+=1;} END {for(i in a){if (a[i] >= num) {print i;}}}' " #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 GE_10 "grep -E \"^$(LC_ALL=\"C\" date \"+%h\").$(LC_ALL=\"C\" date \"+%d\")\" /var/log/auth.log | grep failure | grep rhost"
#define GE_12 "grep -E \"^$(LC_ALL=\"C\" date +\"%Y-%m-%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 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_GE_10 "grep -E \"^$(LC_ALL=\"C\" date \"+%h\").$(LC_ALL=\"C\" date \"+%d\")\" /var/log/secure | grep failure | grep rhost"
@ -120,10 +72,14 @@ void cron_free(void* p)
#define QQMAIL_Virus "gomail -r %s -s \"System Virus Infected\" -t \"%s\"" #define QQMAIL_Virus "gomail -r %s -s \"System Virus Infected\" -t \"%s\""
#define QQMAIL_DISK_USE "gomail -r %s -s \"System Disk Use\" -t \"%s\"" #define QQMAIL_DISK_USE "gomail -r %s -s \"System Disk Use\" -t \"%s\""
#define LOG_FILE "nginx.log"
extern void read_conf(char *filename, conf * configure); extern void read_conf(char *filename, conf * configure);
extern void free_conf(conf * conf); extern void free_conf(conf * conf);
extern void ptintf_conf(conf * conf); extern void ptintf_conf(conf * conf);
extern void my_printf(const char *format, ...);
extern char *_time();
extern int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM]);
#endif #endif