Compare commits
No commits in common. "4aa0d3eac7060e157a8f3d6ec796d896e5f4f879" and "130dad7ffafbd2b3d6b9bde29b32c64cd764cb81" have entirely different histories.
4aa0d3eac7
...
130dad7ffa
11
.vscode/launch.json
vendored
11
.vscode/launch.json
vendored
@ -1,11 +0,0 @@
|
||||
{
|
||||
// 使用 IntelliSense 了解相关属性。
|
||||
// 悬停以查看现有属性的描述。
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
|
||||
|
||||
]
|
||||
}
|
11
.vscode/settings.json
vendored
11
.vscode/settings.json
vendored
@ -7,15 +7,6 @@
|
||||
"clamscan.h": "c",
|
||||
"libiptc.h": "c",
|
||||
"stdio.h": "c",
|
||||
"nginx.h": "c",
|
||||
"cjson.h": "c",
|
||||
"stdlib.h": "c",
|
||||
"stddef.h": "c",
|
||||
"signal.h": "c",
|
||||
"time.h": "c",
|
||||
"stdarg.h": "c",
|
||||
"libclamav.h": "c",
|
||||
"rhost.h": "c",
|
||||
"warning.h": "c"
|
||||
"nginx.h": "c"
|
||||
}
|
||||
}
|
8
Makefile
8
Makefile
@ -20,6 +20,9 @@ ARCH := $(shell bash get_architecture.sh)
|
||||
IPTC_CFLAGS += -DHAVE_CONFIG_H -I./libiptc -D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 -D_REENTRANT
|
||||
IPTC_LIB += -lip4tc
|
||||
|
||||
cJSON_CFLAGS += -std=c89 -c -fPIC -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat -Wundef -Wswitch-default -Wconversion -fstack-protector
|
||||
cJSON_LIB += cJSON.o
|
||||
|
||||
ip2region_CFLAGS += -Os -g -Wall -I/ip2region -c
|
||||
ip2region_LIB += ip2region.o xdb_searcher.o
|
||||
|
||||
@ -35,9 +38,10 @@ LIBCOMMON_LIB += ./clamav/common/cert_util.c.o ./clamav/common/actions.c.o ./cla
|
||||
|
||||
all: libclamav_rust libclamav rhost nginx.o
|
||||
|
||||
rhost: conf.o common.o rhost.o libiptc.o ccronexpr.o rule.o nginx.o disk.o ip.o warning.o
|
||||
rhost: conf.o rhost.o libiptc.o ccronexpr.o nginx.o disk.o
|
||||
$(CC) $(ip2region_CFLAGS) ip2region/ip2region.c
|
||||
$(CC) $(ip2region_CFLAGS) ip2region/xdb_searcher.c
|
||||
$(CC) $(cJSON_CFLAGS) cJSON/cJSON.c
|
||||
|
||||
$(CC) $(CLAMAV_CFLAGS) -o ./clamav/clamscan/clamscan.c.o -c ./clamav/clamscan/clamscan.c
|
||||
$(CC) $(CLAMAV_CFLAGS) -o ./clamav/clamscan/manager.c.o -c ./clamav/clamscan/manager.c
|
||||
@ -46,7 +50,7 @@ rhost: conf.o common.o rhost.o libiptc.o ccronexpr.o rule.o nginx.o disk.o ip.o
|
||||
$(CC) $(FRESHCLAM_CFLAGS) -o ./clamav/freshclam/execute.c.o -c ./clamav/freshclam/execute.c
|
||||
$(CC) $(FRESHCLAM_CFLAGS) -o ./clamav/freshclam/notify.c.o -c ./clamav/freshclam/notify.c
|
||||
|
||||
$(CC) $(CFLAGS) $^ -o $(OBG) $(ip2region_LIB) $(CLAMAV_LIB) $(IPTC_LIB) $(FRESHCLAM_LIB)
|
||||
$(CC) $(CFLAGS) $^ -o $(OBG) $(cJSON_LIB) $(ip2region_LIB) $(CLAMAV_LIB) $(IPTC_LIB) $(FRESHCLAM_LIB)
|
||||
|
||||
chmod +x $(OBG)
|
||||
|
||||
|
30
README.md
30
README.md
@ -84,6 +84,8 @@ Options:
|
||||
|
||||
|
||||
May 22 2024 15:05:59 Compile、link.
|
||||
|
||||
|
||||
```
|
||||
|
||||
```text
|
||||
@ -91,40 +93,54 @@ May 22 2024 15:05:59 Compile、link.
|
||||
global {
|
||||
|
||||
DAEMON = "off"; // on开启后台运行,off不开启(弃用)
|
||||
TIME = "1"; // 睡眠时间(大于等于1,单位秒)
|
||||
TIME = "10"; // 睡眠时间(大于等于1,单位秒)
|
||||
|
||||
|
||||
PUBLIC_IP = "http://inet-ip.info"; // 获取公网IP
|
||||
|
||||
|
||||
IS_DISK = 1; // 磁盘使用率(1开启,非1关闭)
|
||||
DISK_USE = 50; // 任意某块磁盘使用率告警(大于等于1)
|
||||
DISK_USE = 95; // 任意某块磁盘使用率告警(大于等于1)
|
||||
|
||||
|
||||
IS_BLOCKED = 1; // 是否封禁攻击IP(1开启,非1关闭)
|
||||
REFUSE_NUMBER = 3; // 拒绝攻击次数
|
||||
|
||||
IS_MAIL = 0; // 开启邮件告警(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_TIME = "* 45 11 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周)
|
||||
|
||||
|
||||
IPV4_RESTRICTION = 1; // 是否启用IP白名单(1开启,非1关闭)
|
||||
IPV4_WHITE_LIST = "1.1.1.1 2.2.2.2 "; // IP白名单(空格隔开)
|
||||
|
||||
|
||||
REGION = 1; // 是否启用地域白名单(1开启,非1关闭)
|
||||
IP2REGION = 1; // 是否使用本地 ip2region 地址定位库(1使用,非1不使用)
|
||||
REGION_LIST = "河南 郑州 上海"; // 地域列表(空格隔开)
|
||||
|
||||
|
||||
NGINX = 1; // 是否启用Nginx白名单
|
||||
#NGINX_LOG_FILE= "/var/log/nginx/access.log"; // Nginx 日志文件
|
||||
NGINX_LOG_FILE= "/opt/nginx/logs/access.log"; // Nginx 日志文件
|
||||
NGINX_REGION_LIST = "中国 河南 郑州 上海 内网"; // 地域列表(空格隔开)
|
||||
NGINX_LOG_FILE= "/usr/local/nginx/logs/access.log"; // Nginx 日志文件
|
||||
NGINX_REGION_LIST = "中国 河南 郑州 上海"; // 地域列表(空格隔开)
|
||||
|
||||
|
||||
IS_MAIL = 0; // 开启邮件告警(1开启,非1关闭)
|
||||
|
||||
|
||||
IS_DING_WEBHOOK = 1; // 开启叮叮告警(1开启,非1关闭)
|
||||
PHONE = "15565979082"; // @的人手机号
|
||||
DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=396bce0384cded025087cff3c176ea5e9afb9bd8fcaa46d6fa8c51dd172ba513"; // 钉钉WEBHOOK
|
||||
|
||||
|
||||
IS_QQMAIL = 1; // 开启QQ邮箱告警(默认使用gomail: https://git.aixiao.me/aixiao/gomail.git)(1开启,非1关闭)
|
||||
RECV_MAIL = "1605227279@qq.com"; // 接收者邮箱
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
3110
cJSON/cJSON.c
Normal file
3110
cJSON/cJSON.c
Normal file
File diff suppressed because it is too large
Load Diff
293
cJSON/cJSON.h
Normal file
293
cJSON/cJSON.h
Normal file
@ -0,0 +1,293 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 15
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
125
common.c
125
common.c
@ -1,125 +0,0 @@
|
||||
#include "common.h"
|
||||
|
||||
|
||||
// 计算字符串长度
|
||||
int _strlen(char *str)
|
||||
{
|
||||
char *_p = NULL;
|
||||
|
||||
if (str == NULL)
|
||||
return 0;
|
||||
|
||||
_p = strchr(str, '\0');
|
||||
|
||||
if (_p == NULL)
|
||||
return 0;
|
||||
|
||||
return _p - str;
|
||||
}
|
||||
|
||||
// 自定义 printf 函数
|
||||
void my_printf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
// 打印到控制台
|
||||
vprintf(format, args);
|
||||
va_end(args); // 结束对变参列表的处理
|
||||
|
||||
// 重新启动变参列表
|
||||
va_start(args, format);
|
||||
|
||||
// 打开日志文件(追加模式)
|
||||
FILE *log_file = fopen(PRINT_LOG_FILE, "a");
|
||||
if (log_file != NULL) {
|
||||
// 获取当前时间
|
||||
time_t now = time(NULL);
|
||||
struct tm local_time;
|
||||
localtime_r(&now, &local_time);
|
||||
char time_str[20]; // YYYY-MM-DD HH:MM:SS 格式
|
||||
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &local_time);
|
||||
|
||||
// 打印时间戳到日志文件
|
||||
fprintf(log_file, "[%s] ", time_str);
|
||||
|
||||
// 打印内容到日志文件
|
||||
vfprintf(log_file, format, args);
|
||||
|
||||
// 关闭日志文件
|
||||
fclose(log_file);
|
||||
} else {
|
||||
perror("Unable to open log file");
|
||||
}
|
||||
|
||||
va_end(args); // 结束对变参列表的处理
|
||||
}
|
||||
|
||||
void split_string(char string[], char delims[], char (*whitelist_ip)[WHITELIST_IP_NUM])
|
||||
{
|
||||
int i = 0;
|
||||
char *result = NULL;
|
||||
|
||||
result = strtok(string, delims);
|
||||
while (result != NULL)
|
||||
{
|
||||
i++;
|
||||
strcpy(whitelist_ip[i], result);
|
||||
result = strtok(NULL, delims);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 地域段白名单对比
|
||||
int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM])
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
for (i = 1; i < WHITELIST_IP_NUM - 1; i++) {
|
||||
if (strcmp(region_list[i], "\0") == 0) // 如果字符串为空就跳出循环
|
||||
{
|
||||
break;
|
||||
}
|
||||
//printf("%s %s\n", str, region_list[i]);
|
||||
// 在str中查找region_list[i]
|
||||
p = strstr(str, region_list[i]);
|
||||
if (p != NULL) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *_time()
|
||||
{
|
||||
char temp[BUFFER];
|
||||
char *wday[] = { "0", "1", "2", "3", "4", "5", "6" };
|
||||
time_t t;
|
||||
struct tm *p;
|
||||
time(&t);
|
||||
p = localtime(&t); // 取得当地时间
|
||||
|
||||
memset(temp, 0, BUFFER);
|
||||
snprintf(temp, BUFFER, "[%d/%02d/%02d %s %02d:%02d:%02d] ", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);
|
||||
|
||||
return strdup(temp);
|
||||
}
|
36
common.h
36
common.h
@ -1,36 +0,0 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
#define PRINT_LOG_FILE "nginx.log"
|
||||
#define BUFFER 1024
|
||||
#define WHITELIST_IP_NUM 1024
|
||||
|
||||
extern int _strlen(char *str);
|
||||
extern void my_printf(const char *format, ...);
|
||||
extern void split_string(char string[], char delims[], char (*whitelist_ip)[WHITELIST_IP_NUM]);
|
||||
extern int whitelist(char *client_ip, char (*whitelist_ip)[WHITELIST_IP_NUM]);
|
||||
extern char *_time();
|
||||
extern int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM]);
|
||||
|
||||
|
||||
#endif
|
58
conf.c
58
conf.c
@ -14,7 +14,9 @@ int8_t copy_new_mem(char *src, int src_len, char **dest)
|
||||
/* 在content中,设置变量(var)的首地址,值(val)的位置首地址和末地址,返回下一行指针 */
|
||||
static char *set_var_val_lineEnd(char *content, char **var, char **val_begin, char **val_end)
|
||||
{
|
||||
|
||||
char *p, *pn, *lineEnd;
|
||||
;
|
||||
int val_len;
|
||||
|
||||
while (1) {
|
||||
@ -96,6 +98,12 @@ static void parse_global_module(char *content, conf * conf)
|
||||
|
||||
}
|
||||
|
||||
if (strcasecmp(var, "REFUSE_NUMBER") == 0) {
|
||||
val_begin_len = val_end - val_begin;
|
||||
conf->REFUSE_NUMBER = atoi(val_begin);
|
||||
|
||||
}
|
||||
|
||||
if (strcasecmp(var, "IS_MAIL") == 0) {
|
||||
val_begin_len = val_end - val_begin;
|
||||
conf->IS_MAIL = atoi(val_begin);
|
||||
@ -124,7 +132,19 @@ static void parse_global_module(char *content, conf * conf)
|
||||
val_begin_len = val_end - val_begin;
|
||||
conf->IS_QQMAIL = atoi(val_begin);
|
||||
}
|
||||
/*
|
||||
if (strcasecmp(var, "SEND_QQ") == 0) {
|
||||
val_begin_len = val_end - val_begin;
|
||||
if (copy_new_mem(val_begin, val_begin_len, &conf->SEND_QQ) != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcasecmp(var, "QQMAIL_KEY") == 0) {
|
||||
val_begin_len = val_end - val_begin;
|
||||
if (copy_new_mem(val_begin, val_begin_len, &conf->QQMAIL_KEY) != 0)
|
||||
return;
|
||||
}
|
||||
*/
|
||||
if (strcasecmp(var, "RECV_MAIL") == 0) {
|
||||
val_begin_len = val_end - val_begin;
|
||||
if (copy_new_mem(val_begin, val_begin_len, &conf->RECV_MAIL) != 0)
|
||||
@ -158,7 +178,12 @@ static void parse_global_module(char *content, conf * conf)
|
||||
val_begin_len = val_end - val_begin;
|
||||
conf->IP2REGION = atoi(val_begin);
|
||||
}
|
||||
|
||||
if (strcasecmp(var, "REGION_URL") == 0) {
|
||||
val_begin_len = val_end - val_begin;
|
||||
conf->REGION_URL_LEN = val_begin_len;
|
||||
if (copy_new_mem(val_begin, val_begin_len, &conf->REGION_URL) != 0)
|
||||
return;
|
||||
}
|
||||
if (strcasecmp(var, "REGION_LIST") == 0) {
|
||||
val_begin_len = val_end - val_begin;
|
||||
|
||||
@ -283,6 +308,12 @@ void free_conf(conf * conf)
|
||||
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)
|
||||
@ -292,6 +323,8 @@ void free_conf(conf * conf)
|
||||
|
||||
if (conf->REGION_LIST)
|
||||
free(conf->REGION_LIST);
|
||||
if (conf->REGION_URL)
|
||||
free(conf->REGION_URL);
|
||||
|
||||
if (conf->CLAMAV_TIME)
|
||||
free(conf->CLAMAV_TIME);
|
||||
@ -312,7 +345,7 @@ void ptintf_conf(conf * conf)
|
||||
if (conf->DAEMON)
|
||||
printf("DAEMON %s\n", conf->DAEMON);
|
||||
printf("TIME %d\n", conf->TIME);
|
||||
|
||||
printf("REFUSE_NUMBER %d\n", conf->REFUSE_NUMBER);
|
||||
printf("IS_MAIL %d\n", conf->IS_MAIL);
|
||||
printf("IS_DING_WEBHOOK %d\n", conf->IS_DING_WEBHOOK);
|
||||
if (conf->PHONE)
|
||||
@ -320,7 +353,12 @@ void ptintf_conf(conf * conf)
|
||||
if (conf->DING_WEBHOOK)
|
||||
printf("DING_WEBHOOK %s\n", conf->DING_WEBHOOK);
|
||||
printf("IS_QQMAIL %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("RECV_MAIL %s\n", conf->RECV_MAIL);
|
||||
if (conf->PUBLIC_IP)
|
||||
@ -343,3 +381,17 @@ void ptintf_conf(conf * conf)
|
||||
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])
|
||||
{
|
||||
int i = 0;
|
||||
char *result = NULL;
|
||||
|
||||
result = strtok(string, delims);
|
||||
while (result != NULL)
|
||||
{
|
||||
i++;
|
||||
strcpy(whitelist_ip[i], result);
|
||||
result = strtok(NULL, delims);
|
||||
}
|
||||
}
|
||||
|
13
conf.h
13
conf.h
@ -7,6 +7,8 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WHITELIST_IP_NUM 1024
|
||||
|
||||
typedef struct CONF
|
||||
{
|
||||
char *DAEMON;
|
||||
@ -24,6 +26,7 @@ typedef struct CONF
|
||||
int CLAMAV_ARG_LEN;
|
||||
|
||||
int IS_BLOCKED;
|
||||
int REFUSE_NUMBER;
|
||||
|
||||
// 获取公网IP Url地址
|
||||
char *PUBLIC_IP;
|
||||
@ -31,6 +34,8 @@ typedef struct CONF
|
||||
// 地域白名单
|
||||
int REGION;
|
||||
int IP2REGION;
|
||||
char *REGION_URL;
|
||||
int REGION_URL_LEN;
|
||||
char *REGION_LIST;
|
||||
int REGION_LIST_LEN;
|
||||
|
||||
@ -60,9 +65,9 @@ typedef struct CONF
|
||||
char *RECV_MAIL;
|
||||
} conf;
|
||||
|
||||
extern void read_conf(char *filename, conf * configure);
|
||||
extern void free_conf(conf * conf);
|
||||
extern void ptintf_conf(conf * conf);
|
||||
|
||||
void read_conf(char *filename, conf * configure);
|
||||
void free_conf(conf * conf);
|
||||
void ptintf_conf(conf * conf);
|
||||
void split_string(char string[], char delims[], char (*whitelist_ip)[WHITELIST_IP_NUM]);
|
||||
|
||||
#endif
|
||||
|
93
disk.c
93
disk.c
@ -1,11 +1,15 @@
|
||||
#include "disk.h"
|
||||
|
||||
#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;
|
||||
}
|
||||
@ -19,100 +23,37 @@ int get_disk_usage(const char *path, double *usage) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 第三方邮箱告警, 磁盘使用率
|
||||
int QQ_mail_warning_Disk_Use(const char *recv_mail, const char *local_ip, const char *text, int current_length) {
|
||||
|
||||
int command_len = current_length + sizeof(QQMAIL_DISK_USE) + strlen(recv_mail) + strlen(local_ip) + 256;
|
||||
char command[command_len];
|
||||
|
||||
// 生成邮件正文
|
||||
char mail_text[command_len];
|
||||
snprintf(mail_text, command_len, "Host:%s\n%s", local_ip, text);
|
||||
|
||||
// 生成命令字符串
|
||||
snprintf(command, command_len, QQMAIL_DISK_USE, recv_mail, mail_text);
|
||||
|
||||
// 打印命令用于调试
|
||||
printf("Command: %s %d\n", command, current_length);
|
||||
|
||||
// 执行命令
|
||||
int ret = system(command);
|
||||
if (ret == -1) {
|
||||
perror("system command failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_usage(conf *conf, char *local_ip, int threshold) {
|
||||
int disk_usage() {
|
||||
FILE *mounts;
|
||||
struct mntent *ent;
|
||||
char *result;
|
||||
size_t result_size = INITIAL_SIZE;
|
||||
size_t current_length = 0;
|
||||
|
||||
result = (char *)malloc(result_size);
|
||||
if (result == NULL) {
|
||||
perror("内存分配失败");
|
||||
return 1;
|
||||
}
|
||||
result[0] = '\0'; // 初始化为空字符串
|
||||
|
||||
// 打开挂载表
|
||||
mounts = setmntent("/etc/mtab", "r");
|
||||
if (mounts == NULL) {
|
||||
perror("打开挂载表失败");
|
||||
free(result);
|
||||
perror("setmntent failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 遍历每个挂载的文件系统
|
||||
while ((ent = getmntent(mounts)) != NULL) {
|
||||
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 (strstr(ent->mnt_fsname, "/dev/") != NULL) {
|
||||
// 获取挂载点的磁盘使用率
|
||||
if (get_disk_usage(ent->mnt_dir, &usage) != 0) {
|
||||
fprintf(stderr, "获取 %s 的磁盘使用率失败\n", ent->mnt_dir);
|
||||
fprintf(stderr, "Failed to get disk usage for %s\n", ent->mnt_dir);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果使用率超过阈值则拼接字符串
|
||||
int threshold = 1;
|
||||
if (usage > threshold) {
|
||||
char buffer[BUFFER_INCREMENT];
|
||||
int len = snprintf(buffer, BUFFER_INCREMENT, "挂载点:%s 使用率:%.2f%% 阀值:%d%%\n", ent->mnt_dir, usage, threshold);
|
||||
printf("挂载点: %s 使用率: %.2f%% 阀值: %d%%\n", ent->mnt_dir, usage, threshold);
|
||||
|
||||
// 检查缓冲区大小是否足够
|
||||
if (current_length + len >= result_size) {
|
||||
result_size += BUFFER_INCREMENT;
|
||||
result = (char *)realloc(result, result_size);
|
||||
if (result == NULL) {
|
||||
perror("内存重新分配失败");
|
||||
endmntent(mounts);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
strcat(result, buffer);
|
||||
current_length += len;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 发送邮件警告
|
||||
if (current_length > 0) {
|
||||
if (QQ_mail_warning_Disk_Use(conf->RECV_MAIL, local_ip, result, current_length) != 0) {
|
||||
fprintf(stderr, "发送邮件失败\n");
|
||||
}
|
||||
}
|
||||
|
||||
// 清理
|
||||
free(result);
|
||||
endmntent(mounts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
9
disk.h
9
disk.h
@ -7,13 +7,6 @@
|
||||
#include <mntent.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#include "rhost.h"
|
||||
#include "common.h"
|
||||
#include "warning.h"
|
||||
|
||||
#define INITIAL_SIZE 1024
|
||||
#define BUFFER_INCREMENT 512
|
||||
|
||||
int disk_usage(conf *conf, char *local_ip, int threshold);
|
||||
extern int disk_usage();
|
||||
|
||||
#endif
|
||||
|
98
ip.c
98
ip.c
@ -1,98 +0,0 @@
|
||||
#include "ip.h"
|
||||
|
||||
|
||||
|
||||
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
|
||||
char *GET_PUBLIC_IP(char *URL)
|
||||
{
|
||||
CURL *curl_handle;
|
||||
CURLcode res;
|
||||
|
||||
struct curl_slist *headers = NULL;
|
||||
struct MemoryStruct chunk;
|
||||
|
||||
chunk.memory = malloc(1); /* 将根据上述再分配的需要增长 */
|
||||
chunk.size = 0; /* 此时没有数据 */
|
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
|
||||
/* 初始化curl会话 */
|
||||
curl_handle = curl_easy_init();
|
||||
|
||||
char *p = NULL;
|
||||
char *buff;
|
||||
|
||||
p = strstr(URL, "-H");
|
||||
if (p) {
|
||||
|
||||
buff = (char *)alloca(p - URL + 1);
|
||||
if (buff == NULL)
|
||||
perror("out of memory.");
|
||||
|
||||
memset(buff, 0, p - URL + 1);
|
||||
memcpy(buff, URL, (int)(p - URL - 1));
|
||||
|
||||
// 赋值header值
|
||||
headers = curl_slist_append(headers, p + 3);
|
||||
|
||||
// 设置header
|
||||
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_URL, buff);
|
||||
|
||||
} else {
|
||||
/* 指定要获取的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;
|
||||
}
|
22
ip.h
22
ip.h
@ -1,22 +0,0 @@
|
||||
#ifndef IP_H
|
||||
#define IP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#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>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
extern char *GET_PUBLIC_IP(char *URL);
|
||||
|
||||
#endif
|
7
nginx.c
7
nginx.c
@ -11,7 +11,7 @@ void nginx_iptc(char *ip)
|
||||
iptc_add_rule("filter", "INPUT", IPPROTO_TCP, NULL, NULL, srcIp, 0, NULL, NULL, "DROP", NULL, 1);
|
||||
}
|
||||
|
||||
static int Handle_IP(char *string, conf *config)
|
||||
int IP_location(char *string, conf *config)
|
||||
{
|
||||
char *area = NULL;
|
||||
char *xdb_path = "ip2region.xdb";
|
||||
@ -54,8 +54,7 @@ static int Handle_IP(char *string, conf *config)
|
||||
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);
|
||||
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);
|
||||
@ -137,7 +136,7 @@ int nginx_read_log(const char *filename, conf *p)
|
||||
int bytes_read;
|
||||
while ((bytes_read = read(fd, read_buf, buffer_size - 1)) > 0) {
|
||||
read_buf[bytes_read] = '\0';
|
||||
Handle_IP(read_buf, p);
|
||||
IP_location(read_buf, p);
|
||||
}
|
||||
if (bytes_read == -1 && errno != EAGAIN) {
|
||||
perror("read");
|
||||
|
1
nginx.h
1
nginx.h
@ -10,7 +10,6 @@
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "rhost.h"
|
||||
#include "common.h"
|
||||
#include "libiptc.h"
|
||||
#include "ip2region/ip2region.h"
|
||||
|
||||
|
791
rhost.c
791
rhost.c
@ -1,14 +1,11 @@
|
||||
#include "rhost.h"
|
||||
#include "common.h"
|
||||
#include "ip.h"
|
||||
#include "warning.h"
|
||||
#include "rule.h"
|
||||
|
||||
#include "libiptc.h"
|
||||
#include "libclamav.h"
|
||||
#include "clamscan.h"
|
||||
#include "ccronexpr.h"
|
||||
#include "nginx.h"
|
||||
#include "disk.h"
|
||||
#include "./cJSON/cJSON.h"
|
||||
#include "ip2region/ip2region.h"
|
||||
|
||||
// CRON
|
||||
@ -50,9 +47,206 @@ void cron_free(void *p)
|
||||
// CRON END
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 自定义 printf 函数
|
||||
void my_printf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
// 打印到控制台
|
||||
vprintf(format, args);
|
||||
va_end(args); // 结束对变参列表的处理
|
||||
|
||||
// 重新启动变参列表
|
||||
va_start(args, format);
|
||||
|
||||
// 打开日志文件(追加模式)
|
||||
FILE *log_file = fopen(LOG_FILE, "a");
|
||||
if (log_file != NULL) {
|
||||
// 获取当前时间
|
||||
time_t now = time(NULL);
|
||||
struct tm local_time;
|
||||
localtime_r(&now, &local_time);
|
||||
char time_str[20]; // YYYY-MM-DD HH:MM:SS 格式
|
||||
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &local_time);
|
||||
|
||||
// 打印时间戳到日志文件
|
||||
fprintf(log_file, "[%s] ", time_str);
|
||||
|
||||
// 打印内容到日志文件
|
||||
vfprintf(log_file, format, args);
|
||||
|
||||
// 关闭日志文件
|
||||
fclose(log_file);
|
||||
} else {
|
||||
perror("Unable to open log file");
|
||||
}
|
||||
|
||||
va_end(args); // 结束对变参列表的处理
|
||||
}
|
||||
|
||||
// 存储公网IP
|
||||
char *public_ip;
|
||||
|
||||
struct MemoryStruct {
|
||||
char *memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
// 计算字符串长度
|
||||
int _strlen(char *str)
|
||||
{
|
||||
char *_p = NULL;
|
||||
|
||||
if (str == NULL)
|
||||
return 0;
|
||||
|
||||
_p = strchr(str, '\0');
|
||||
|
||||
if (_p == NULL)
|
||||
return 0;
|
||||
|
||||
return _p - str;
|
||||
}
|
||||
|
||||
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 curl_slist *headers = NULL;
|
||||
struct MemoryStruct chunk;
|
||||
|
||||
chunk.memory = malloc(1); /* 将根据上述再分配的需要增长 */
|
||||
chunk.size = 0; /* 此时没有数据 */
|
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
|
||||
/* 初始化curl会话 */
|
||||
curl_handle = curl_easy_init();
|
||||
|
||||
char *p = NULL;
|
||||
char *buff;
|
||||
|
||||
p = strstr(URL, "-H");
|
||||
if (p) {
|
||||
|
||||
buff = (char *)alloca(p - URL + 1);
|
||||
if (buff == NULL)
|
||||
perror("out of memory.");
|
||||
|
||||
memset(buff, 0, p - URL + 1);
|
||||
memcpy(buff, URL, (int)(p - URL - 1));
|
||||
|
||||
// 赋值header值
|
||||
headers = curl_slist_append(headers, p + 3);
|
||||
|
||||
// 设置header
|
||||
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_URL, buff);
|
||||
|
||||
} else {
|
||||
/* 指定要获取的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;
|
||||
}
|
||||
|
||||
// 解析Json
|
||||
char *process_json(char *buff, char *api)
|
||||
{
|
||||
char *area = NULL;
|
||||
int area_len = 0;
|
||||
char *p = NULL;
|
||||
|
||||
if (buff == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cJSON *cjson_init = cJSON_Parse(buff);
|
||||
if (cjson_init == NULL) {
|
||||
perror("cJSON_Parse");
|
||||
return NULL;
|
||||
}
|
||||
if ((p = strstr(api, "baidu")) != NULL) { // baidu Api
|
||||
int i;
|
||||
|
||||
cJSON *data = cJSON_GetObjectItem(cjson_init, "data");
|
||||
if (data != NULL) {
|
||||
for (i = 0; i < cJSON_GetArraySize(data); i++) {
|
||||
cJSON *svalue = cJSON_GetArrayItem(data, i);
|
||||
cJSON *location = cJSON_GetObjectItem(svalue, "location");
|
||||
area_len = _strlen(location->valuestring);
|
||||
|
||||
area = (char *)alloca(area_len + 1);
|
||||
if (area == NULL)
|
||||
perror("out of memory.");
|
||||
memset(area, 0, area_len + 1);
|
||||
|
||||
snprintf(area, area_len + 1, "%s", location->valuestring);
|
||||
}
|
||||
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
cJSON_Delete(cjson_init);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cJSON_Delete(cjson_init);
|
||||
return strdup(area);
|
||||
}
|
||||
|
||||
// 检测系统
|
||||
int check_system()
|
||||
{
|
||||
@ -65,6 +259,504 @@ int check_system()
|
||||
return UNKNOWN_SYSTEM;
|
||||
}
|
||||
|
||||
// 钉钉告警
|
||||
int dingding_warning(char *illegal_ip, char *public_ip, char *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.log", "wt+")) == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
curl = curl_easy_init();
|
||||
if (curl == NULL) {
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
#define JSIN "{ \
|
||||
\"msgtype\": \"text\", \
|
||||
\"text\": { \
|
||||
\"content\": \"Alert @%s 服务器地址:%s,封禁非法入侵主机:(%s%s)\" \
|
||||
}, \
|
||||
\"at\": { \
|
||||
\"atMobiles\": [\"%s\"], \
|
||||
\"isAtAll\": false \
|
||||
} \
|
||||
}"
|
||||
|
||||
snprintf(jsonObj, BUFFER, JSIN, conf->PHONE, temp, ip, 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, char *ip, conf *conf)
|
||||
{
|
||||
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';
|
||||
snprintf(text, BUFFER, "echo \"主机:%s, 禁止(%s%s)访问\" | mail -s \"System ban IP\" %s", temp, ip, illegal_ip, conf->RECV_MAIL);
|
||||
|
||||
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 *ip, conf *conf)
|
||||
{
|
||||
char string[BUFFER + (sizeof(QQMAIL)) + 1];
|
||||
char text[BUFFER];
|
||||
char temp[32];
|
||||
|
||||
memset(string, 0, BUFFER + (sizeof(QQMAIL)) + 1);
|
||||
memset(text, 0, BUFFER);
|
||||
memset(temp, 0, 32);
|
||||
|
||||
strcpy(temp, public_ip);
|
||||
temp[_strlen(public_ip) - 1] = '\0';
|
||||
|
||||
snprintf(text, BUFFER, "主机:%s, 禁止(%s%s)访问!", temp, ip, illegal_ip);
|
||||
snprintf(string, BUFFER + (sizeof(QQMAIL)) + 1, QQMAIL, conf->RECV_MAIL, text);
|
||||
|
||||
return system(string);
|
||||
}
|
||||
|
||||
// 第三方邮箱告警, 感染病毒邮件提醒
|
||||
int QQ_mail_warning_Virus_files(char *local_ip, int Virus_number, conf *conf)
|
||||
{
|
||||
char *command;
|
||||
char *text;
|
||||
char temp[32];
|
||||
|
||||
command = (char *)alloca(BUFFER + (sizeof(QQMAIL)) + 1);
|
||||
text = (char *)alloca(BUFFER);
|
||||
|
||||
memset(command, 0, BUFFER + (sizeof(QQMAIL)) + 1);
|
||||
memset(text, 0, BUFFER);
|
||||
memset(temp, 0, 32);
|
||||
|
||||
strcpy(temp, local_ip);
|
||||
temp[_strlen(local_ip) - 1] = '\0';
|
||||
|
||||
snprintf(text, BUFFER, "Host:%s, Infected files: %d, Please handle!", temp, Virus_number);
|
||||
snprintf(command, BUFFER + BUFFER + (sizeof(QQMAIL)) + 1, QQMAIL_Virus, conf->RECV_MAIL, text);
|
||||
|
||||
return system(command);
|
||||
}
|
||||
|
||||
// 第三方邮箱告警, 磁盘使用率
|
||||
int QQ_mail_warning_Disk_Use(char *local_ip, int disk_use, conf *conf)
|
||||
{
|
||||
char *command;
|
||||
char *text;
|
||||
char temp[32];
|
||||
|
||||
command = (char *)alloca(BUFFER + (sizeof(QQMAIL)) + 1);
|
||||
text = (char *)alloca(BUFFER);
|
||||
|
||||
memset(command, 0, BUFFER + (sizeof(QQMAIL)) + 1);
|
||||
memset(text, 0, BUFFER);
|
||||
memset(temp, 0, 32);
|
||||
|
||||
strcpy(temp, local_ip);
|
||||
temp[_strlen(local_ip) - 1] = '\0';
|
||||
|
||||
snprintf(text, BUFFER, "Host:%s, Disk usage reaches threshold!, Please handle!", temp);
|
||||
snprintf(command, BUFFER, QQMAIL_DISK_USE, conf->RECV_MAIL, text);
|
||||
|
||||
return system(command);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 地域段白名单对比
|
||||
int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM])
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
for (i = 1; i < WHITELIST_IP_NUM - 1; i++) {
|
||||
if (strcmp(region_list[i], "\0") == 0) // 如果字符串为空就跳出循环
|
||||
{
|
||||
break;
|
||||
}
|
||||
//printf("%s %s\n", str, region_list[i]);
|
||||
// 在str中查找region_list[i]
|
||||
p = strstr(str, region_list[i]);
|
||||
if (p != NULL) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 磁盘使用率
|
||||
int disk_waring(int threshold)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char buffer[BUFFER];
|
||||
char command[BUFFER];
|
||||
int is = 0;
|
||||
|
||||
#define DF "for u in `df -mh | grep -E -e \".:.\" -e \"^/dev\" | awk '{print $5}' | sed 's|%%||g'`; do if test \"$u\" -ge %d; then echo \"$u\"; fi done"
|
||||
|
||||
memset(buffer, 0, BUFFER);
|
||||
memset(command, 0, BUFFER);
|
||||
|
||||
snprintf(command, BUFFER, DF, threshold);
|
||||
|
||||
//printf("%s\n", command);
|
||||
fp = popen(command, "r");
|
||||
|
||||
while (fgets(buffer, BUFFER, fp) != NULL) {
|
||||
printf("%s", buffer);
|
||||
is = 1;
|
||||
break;
|
||||
}
|
||||
pclose(fp);
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
char *_time()
|
||||
{
|
||||
char temp[BUFFER];
|
||||
char *wday[] = { "0", "1", "2", "3", "4", "5", "6" };
|
||||
time_t t;
|
||||
struct tm *p;
|
||||
time(&t);
|
||||
p = localtime(&t); // 取得当地时间
|
||||
|
||||
memset(temp, 0, BUFFER);
|
||||
snprintf(temp, BUFFER, "[%d/%02d/%02d %s %02d:%02d:%02d] ", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);
|
||||
|
||||
return strdup(temp);
|
||||
}
|
||||
|
||||
// 封禁非法IP
|
||||
int rule(conf *conf)
|
||||
{
|
||||
char whitelist_ip[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } };
|
||||
char region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } };
|
||||
|
||||
char REGION_LIST_COPY[conf->REGION_LIST_LEN + 1];
|
||||
char IPV4_WHITE_LIST_COPY[conf->IPV4_WHITE_LIST_LEN + 1];
|
||||
|
||||
char p_two[2], *command, *splice_command, *temp, buffer[BUFFER], awk[BUFFER];
|
||||
FILE *fp, *fc;
|
||||
time_t timep;
|
||||
struct tm *tp;
|
||||
long int ip_length = 1;
|
||||
|
||||
fp = NULL;
|
||||
fc = NULL;
|
||||
timep = time(NULL);
|
||||
tp = localtime(&timep);
|
||||
memset(buffer, 0, BUFFER);
|
||||
memset(awk, 0, BUFFER);
|
||||
memset(p_two, 0, 2);
|
||||
|
||||
char *t = NULL;
|
||||
t = _time();
|
||||
|
||||
if (DEBISN_SYSTEM == check_system()) // Debian 系统规则
|
||||
{
|
||||
if (system_version() >= 12)
|
||||
{
|
||||
if ((fp = popen(GE_10, "r")) == NULL)
|
||||
{
|
||||
perror("GE_10");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
splice_command = (char *)malloc(ip_length);
|
||||
if (splice_command == NULL) {
|
||||
free(splice_command);
|
||||
return -1;
|
||||
}
|
||||
memset(splice_command, 0, ip_length);
|
||||
|
||||
while (fgets(buffer, BUFFER, fp) != NULL) {
|
||||
char *new_splice_command;
|
||||
|
||||
temp = strstr(buffer, "rhost");
|
||||
sscanf(temp, "rhost=%64s", temp);
|
||||
if (atoi(strncpy(p_two, temp, 1)) > 0) {
|
||||
ip_length += _strlen(temp) + 1;
|
||||
|
||||
new_splice_command = (char *)realloc(splice_command, ip_length + 32);
|
||||
if (new_splice_command == NULL) {
|
||||
free(splice_command);
|
||||
return -1;
|
||||
}
|
||||
splice_command = new_splice_command;
|
||||
|
||||
//printf(RED"Hello World\n"COLOR_NONE);
|
||||
printf(RED "%s Illegal IP: %s\n" COLOR_NONE, t, temp);
|
||||
strcat(splice_command, temp);
|
||||
strcat(splice_command, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
//printf("%s", splice_command); // 打印所有非法IP
|
||||
//printf("%ld\n", ip_length);
|
||||
|
||||
command = (char *)malloc(ip_length + BUFFER);
|
||||
if (command == NULL) {
|
||||
free(command);
|
||||
return -1;
|
||||
}
|
||||
memset(command, 0, ip_length + BUFFER);
|
||||
|
||||
snprintf(awk, BUFFER, AWK, conf->REFUSE_NUMBER); // 拼接命令
|
||||
memcpy(command, "echo \"", 7);
|
||||
strcat(command, splice_command);
|
||||
strcat(command, "\"");
|
||||
strcat(command, awk);
|
||||
|
||||
if ((fc = popen(command, "r")) == NULL) // 执行命令
|
||||
{
|
||||
perror("popen command");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (splice_command != NULL) {
|
||||
free(splice_command);
|
||||
}
|
||||
if (command != NULL) {
|
||||
free(command);
|
||||
}
|
||||
|
||||
while (fgets(buffer, BUFFER, fc) != NULL) // 执行命令后, 为空时就不会
|
||||
{
|
||||
buffer[_strlen(buffer) - 1] = '\0'; // 去除回车
|
||||
|
||||
memset(REGION_LIST_COPY, 0, conf->REGION_LIST_LEN + 1);
|
||||
memset(IPV4_WHITE_LIST_COPY, 0, conf->IPV4_WHITE_LIST_LEN + 1);
|
||||
|
||||
memcpy(REGION_LIST_COPY, conf->REGION_LIST, conf->REGION_LIST_LEN); // 复制配置字符串,split_string()会改变原数据
|
||||
memcpy(IPV4_WHITE_LIST_COPY, conf->IPV4_WHITE_LIST, conf->IPV4_WHITE_LIST_LEN); //
|
||||
|
||||
split_string(IPV4_WHITE_LIST_COPY, " ", whitelist_ip);
|
||||
split_string(REGION_LIST_COPY, " ", region_list);
|
||||
|
||||
if (conf->IPV4_RESTRICTION == 1) // 是否启用白名单
|
||||
{
|
||||
if (whitelist(buffer, whitelist_ip) == 1) {
|
||||
printf("%s 白名单IPV4:%s\n", t, buffer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != show_all_rule(buffer)) // libiptc库判断否存在规则
|
||||
{
|
||||
char *location_json = NULL;
|
||||
char *area = NULL;
|
||||
char URL[conf->REGION_URL_LEN + 32];
|
||||
char *xdb_path = "ip2region.xdb";
|
||||
|
||||
// 地域白名单
|
||||
if (conf->REGION == 1) {
|
||||
memset(URL, 0, conf->REGION_URL_LEN + 32);
|
||||
snprintf(URL, conf->REGION_URL_LEN + 32, conf->REGION_URL, buffer);
|
||||
|
||||
if (conf->IP2REGION == 1) { // ip2region 地址定位库
|
||||
printf("%s Use ip2region !!!\n", t);
|
||||
|
||||
if (-1 == access(xdb_path, F_OK)) // 判断 ip2region 地址定位库是否存在
|
||||
{
|
||||
xdb_path = "ip2region/ip2region.xdb";
|
||||
|
||||
if (-1 == access(xdb_path, F_OK)) {
|
||||
printf("%s ip2region.xdb DOESN'T EXISIT!\n", t);
|
||||
goto AREA;
|
||||
}
|
||||
}
|
||||
|
||||
area = ip2region(xdb_path, buffer);
|
||||
if (area == NULL) {
|
||||
printf("%s ip2region解析地域错误\n", t);
|
||||
goto BLOCKED;
|
||||
}
|
||||
} else {
|
||||
AREA:
|
||||
location_json = GET_PUBLIC_IP(URL);
|
||||
if (location_json == NULL) {
|
||||
printf("%s 获取地域错误\n", t);
|
||||
goto BLOCKED;
|
||||
}
|
||||
|
||||
area = process_json(location_json, conf->REGION_URL);
|
||||
if (area == NULL) {
|
||||
printf("%s 解析地域错误\n", t);
|
||||
goto BLOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
if (isregion(area, region_list) == 1) {
|
||||
printf(RED "%s Ip Address: %s, 地域白名单: %s\n" COLOR_NONE, t, buffer, area);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
printf(RED "%s 攻击者IP地址:%s, %s\n" COLOR_NONE, t, buffer, area);
|
||||
|
||||
if (conf->IS_DING_WEBHOOK == 1) // 钉钉告警
|
||||
{
|
||||
dingding_warning(area, public_ip, buffer, conf);
|
||||
sleep(3);
|
||||
}
|
||||
|
||||
if (conf->IS_MAIL == 1) // 邮件告警
|
||||
{
|
||||
mail_warning(area, public_ip, buffer, conf);
|
||||
sleep(3);
|
||||
}
|
||||
|
||||
if (conf->IS_QQMAIL == 1) // 邮件告警
|
||||
{
|
||||
QQ_mail_warning(area, public_ip, buffer, conf);
|
||||
sleep(3);
|
||||
}
|
||||
|
||||
BLOCKED:
|
||||
// 是否封禁攻击IP
|
||||
if (conf->IS_BLOCKED == 1) {
|
||||
// libiptc 库插入规则
|
||||
// iptables -t filter -A INPUT -p tcp -m tcp -s 47.110.180.35 -j DROP
|
||||
|
||||
// libiptc 库删除规则
|
||||
// iptables -t filter -D INPUT -p tcp -m tcp -s 47.110.180.35 -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);
|
||||
}
|
||||
|
||||
if (location_json != NULL)
|
||||
free(location_json);
|
||||
if (area != NULL)
|
||||
free(area);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (fp != NULL)
|
||||
pclose(fp);
|
||||
if (fc != NULL)
|
||||
pclose(fc);
|
||||
if (t)
|
||||
free(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sig_child(int signo)
|
||||
{
|
||||
pid_t pid;
|
||||
@ -77,6 +769,7 @@ static void sig_child(int signo)
|
||||
|
||||
static int get_executable_path(char *processdir, char *processname, int len)
|
||||
{
|
||||
|
||||
char *processname_ptr;
|
||||
|
||||
if (readlink("/proc/self/exe", processdir, len) <= 0)
|
||||
@ -93,9 +786,9 @@ static int get_executable_path(char *processdir, char *processname, int len)
|
||||
// 处理参数
|
||||
int process_argv(int argc, char *argv[], char **argvs)
|
||||
{
|
||||
int i=0, j=0;
|
||||
argvs[0] = argv[0];
|
||||
|
||||
int i;
|
||||
int j;
|
||||
for (i = 0; i <= argc - 1; i++) {
|
||||
if (i == 1) {
|
||||
for (j = i; j <= argc - 2; j++) {
|
||||
@ -143,11 +836,13 @@ static int get_clamav_log(char *file)
|
||||
}
|
||||
|
||||
while (fgets(buffer, BUFFER, fp) != NULL) {
|
||||
//printf("%s", buffer);
|
||||
temp = strstr(buffer, "Infected");
|
||||
if (temp)
|
||||
sscanf(temp, "Infected files: %32s", temp);
|
||||
|
||||
if (temp != NULL) {
|
||||
//printf("%s\n", temp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -258,6 +953,7 @@ static char help_information(void)
|
||||
|
||||
int main(int argc, char *argv[], char **env)
|
||||
{
|
||||
|
||||
signal(SIGCHLD, sig_child); // 创建捕捉子进程退出信号
|
||||
|
||||
int pid;
|
||||
@ -347,15 +1043,15 @@ int main(int argc, char *argv[], char **env)
|
||||
head_argc += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
// 打印clamav参数
|
||||
for(int i=0; i<head_argc; i++)
|
||||
{
|
||||
printf("%s %d\n", head_argvs[i], i);
|
||||
}
|
||||
/*
|
||||
// 打印clamav参数
|
||||
for(int i=0; i<head_argc; i++)
|
||||
{
|
||||
printf("%s %d\n", head_argvs[i], i);
|
||||
}
|
||||
|
||||
_clamscan(head_argc, head_argvs);
|
||||
*/
|
||||
_clamscan(head_argc, head_argvs);
|
||||
*/
|
||||
|
||||
now_next_time *t = (now_next_time *) malloc(sizeof(struct now_next_time));
|
||||
memset(t, 0, sizeof(struct now_next_time));
|
||||
@ -365,11 +1061,11 @@ int main(int argc, char *argv[], char **env)
|
||||
//printf("%s", public_ip);
|
||||
|
||||
if (0 == strcmp(conf->DAEMON, "on")) {
|
||||
goto DAEMON;
|
||||
goto goto_daemon;
|
||||
}
|
||||
|
||||
if (argv[1] != NULL && 0 == strcmp(argv[1], "-d")) {
|
||||
DAEMON:
|
||||
goto_daemon:
|
||||
|
||||
// 守护进程
|
||||
if ((pid = fork()) < 0) {
|
||||
@ -409,40 +1105,18 @@ DAEMON:
|
||||
if (-1 == (nice(-20)))
|
||||
perror("nice");
|
||||
|
||||
|
||||
// 处理Nginx
|
||||
if (conf->NGINX == 1) {
|
||||
pid_t pid = fork(); // 创建子进程
|
||||
if (pid == 0) {
|
||||
printf("Nginx process!!!\n");
|
||||
while (1)
|
||||
{
|
||||
nginx_read_log(conf->NGINX_LOG_FILE, conf);
|
||||
sleep(1);
|
||||
}
|
||||
pid_t pid = fork(); // 创建子进程
|
||||
if (pid == 0) {
|
||||
printf("The parent process processes Nginx logs!!!\n");
|
||||
while (1)
|
||||
{
|
||||
nginx_read_log(conf->NGINX_LOG_FILE, conf);
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理SSH
|
||||
if (conf->IS_BLOCKED == 1) {
|
||||
pid_t pid = fork(); // 创建子进程
|
||||
if (pid == 0) {
|
||||
printf("SSH process!!!\n");
|
||||
while (1)
|
||||
{
|
||||
if (DEBISN_SYSTEM == check_system()) {
|
||||
rule_(conf, "/var/log/auth.log");
|
||||
}
|
||||
if (CENTOS_SYSTEM == check_system()) {
|
||||
rule_(conf, "/var/log/secure");
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clamscan
|
||||
printf("Clamscan process!!!\n");
|
||||
while (1)
|
||||
{
|
||||
// Cron
|
||||
@ -504,27 +1178,38 @@ DAEMON:
|
||||
|
||||
// 磁盘告警
|
||||
if (1 == conf->IS_DISK) {
|
||||
disk_usage(conf, public_ip, conf->DISK_USE);
|
||||
if (disk_waring(conf->DISK_USE) == 1) {
|
||||
printf("Disk usage reaches threshold!, Please handle!\n");
|
||||
if (conf->IS_QQMAIL == 1) {
|
||||
QQ_mail_warning_Disk_Use(public_ip, 0, conf);
|
||||
sleep(3);
|
||||
}
|
||||
} else {
|
||||
printf("Disk usage does not reach threshold!\n");
|
||||
}
|
||||
}
|
||||
|
||||
_exit(r);
|
||||
|
||||
} else {
|
||||
int status = 0;
|
||||
wait(&status); // wait the end of child process
|
||||
if (WIFEXITED(status)) {
|
||||
;
|
||||
printf("child process return %d\n", WEXITSTATUS(status));
|
||||
//printf("child process return %d\n", WEXITSTATUS(status));
|
||||
}
|
||||
|
||||
sleep(60); // 跳过这一分钟
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 封禁非法IP
|
||||
rule(conf);
|
||||
sleep(conf->TIME);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
;
|
||||
}
|
||||
|
||||
free(t);
|
||||
free_conf(conf);
|
||||
|
24
rhost.conf
24
rhost.conf
@ -1,37 +1,47 @@
|
||||
global {
|
||||
|
||||
DAEMON = "off"; // on开启后台运行,off不开启(弃用)
|
||||
TIME = "1"; // 睡眠时间(大于等于1,单位秒)
|
||||
DAEMON = "off"; // on开启后台运行,off不开启(弃用)
|
||||
TIME = "10"; // 睡眠时间(大于等于1,单位秒)
|
||||
|
||||
|
||||
PUBLIC_IP = "http://inet-ip.info"; // 获取公网IP
|
||||
|
||||
|
||||
IS_DISK = 1; // 磁盘使用率(1开启,非1关闭)
|
||||
DISK_USE = 50; // 任意某块磁盘使用率告警(大于等于1)
|
||||
DISK_USE = 95; // 任意某块磁盘使用率告警(大于等于1)
|
||||
|
||||
|
||||
IS_BLOCKED = 1; // 是否封禁攻击IP(1开启,非1关闭)
|
||||
REFUSE_NUMBER = 3; // 拒绝攻击次数
|
||||
|
||||
IS_MAIL = 0; // 开启邮件告警(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_TIME = "* 45 11 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周)
|
||||
|
||||
|
||||
IPV4_RESTRICTION = 1; // 是否启用IP白名单(1开启,非1关闭)
|
||||
IPV4_WHITE_LIST = "1.1.1.1 2.2.2.2 "; // IP白名单(空格隔开)
|
||||
|
||||
|
||||
REGION = 1; // 是否启用地域白名单(1开启,非1关闭)
|
||||
IP2REGION = 1; // 是否使用本地 ip2region 地址定位库(1使用,非1不使用)
|
||||
REGION_LIST = "河南 郑州 上海"; // 地域列表(空格隔开)
|
||||
|
||||
|
||||
NGINX = 1; // 是否启用Nginx白名单
|
||||
#NGINX_LOG_FILE= "/var/log/nginx/access.log"; // Nginx 日志文件
|
||||
NGINX_LOG_FILE= "/opt/nginx/logs/access.log"; // Nginx 日志文件
|
||||
NGINX_REGION_LIST = "中国 河南 郑州 上海 内网"; // 地域列表(空格隔开)
|
||||
NGINX_LOG_FILE= "/usr/local/nginx/logs/access.log"; // Nginx 日志文件
|
||||
NGINX_REGION_LIST = "中国 河南 郑州 上海"; // 地域列表(空格隔开)
|
||||
|
||||
|
||||
IS_MAIL = 0; // 开启邮件告警(1开启,非1关闭)
|
||||
|
||||
|
||||
IS_DING_WEBHOOK = 1; // 开启叮叮告警(1开启,非1关闭)
|
||||
PHONE = "15565979082"; // @的人手机号
|
||||
DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=396bce0384cded025087cff3c176ea5e9afb9bd8fcaa46d6fa8c51dd172ba513"; // 钉钉WEBHOOK
|
||||
|
||||
|
||||
IS_QQMAIL = 1; // 开启QQ邮箱告警(默认使用gomail: https://git.aixiao.me/aixiao/gomail.git)(1开启,非1关闭)
|
||||
RECV_MAIL = "1605227279@qq.com"; // 接收者邮箱
|
||||
}
|
||||
|
18
rhost.h
18
rhost.h
@ -19,6 +19,7 @@
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
|
||||
typedef struct now_next_time
|
||||
{
|
||||
int now_year;
|
||||
@ -39,17 +40,22 @@ typedef struct now_next_time
|
||||
} now_next_time;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define COLOR_NONE "\033[0m" //表示清除前面设置的格式
|
||||
#define RED "\033[1;31;40m" //40表示背景色为黑色, 1 表示高亮
|
||||
#define BLUE "\033[1;34;40m"
|
||||
#define GREEN "\033[1;32;40m"
|
||||
#define YELLOW "\033[1;33;40m"
|
||||
|
||||
|
||||
#define CENTOS_SYSTEM 1
|
||||
#define DEBISN_SYSTEM 2
|
||||
#define UNKNOWN_SYSTEM 3
|
||||
|
||||
#define BUFFER 1024
|
||||
#define LONG_BUFFER 1024*1000
|
||||
#define ARGS_NUM 20
|
||||
#define WHITELIST_IP_NUM 1024
|
||||
#define BUILD(fmt...) do { fprintf(stderr,"%s %s ",__DATE__,__TIME__); fprintf(stderr, ##fmt); } while(0)
|
||||
@ -61,7 +67,19 @@ typedef struct now_next_time
|
||||
#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 QQMAIL "gomail -r %s -s \"System ban IP\" -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 LOG_FILE "nginx.log"
|
||||
|
||||
|
||||
extern void read_conf(char *filename, conf * configure);
|
||||
extern void free_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
|
||||
|
147
rule.c
147
rule.c
@ -1,147 +0,0 @@
|
||||
#include "rule.h"
|
||||
|
||||
|
||||
static int Handle_IP(conf *conf, char *ip)
|
||||
{
|
||||
char whitelist_ip[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } };
|
||||
char region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } };
|
||||
char REGION_LIST_COPY[conf->REGION_LIST_LEN + 1];
|
||||
char IPV4_WHITE_LIST_COPY[conf->IPV4_WHITE_LIST_LEN + 1];
|
||||
char *t = _time();
|
||||
|
||||
memset(REGION_LIST_COPY, 0, sizeof(REGION_LIST_COPY));
|
||||
memset(IPV4_WHITE_LIST_COPY, 0, sizeof(IPV4_WHITE_LIST_COPY));
|
||||
|
||||
memcpy(REGION_LIST_COPY, conf->REGION_LIST, strlen(conf->REGION_LIST));
|
||||
memcpy(IPV4_WHITE_LIST_COPY, conf->IPV4_WHITE_LIST, strlen(conf->IPV4_WHITE_LIST));
|
||||
|
||||
split_string(IPV4_WHITE_LIST_COPY, " ", whitelist_ip);
|
||||
split_string(REGION_LIST_COPY, " ", region_list);
|
||||
|
||||
// IP白名单
|
||||
if (conf->IPV4_RESTRICTION == 1) {
|
||||
if (whitelist(ip, whitelist_ip) == 1) {
|
||||
printf("%s 白名单IPV4:%s\n", t, ip);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (show_all_rule(ip) != 0) // 不在防火墙规则表里
|
||||
{
|
||||
char *area = NULL;
|
||||
char *xdb_path = "ip2region.xdb";
|
||||
|
||||
if (conf->REGION == 1) {
|
||||
if (conf->IP2REGION == 1) {
|
||||
//printf("%s Use ip2region !!!\n", t);
|
||||
|
||||
if (access(xdb_path, F_OK) == -1) {
|
||||
xdb_path = "ip2region/ip2region.xdb";
|
||||
if (access(xdb_path, F_OK) == -1) {
|
||||
printf("%s ip2region.xdb DOESN'T EXIST!\n", t);
|
||||
}
|
||||
}
|
||||
area = ip2region(xdb_path, ip);
|
||||
if (area == NULL) {
|
||||
printf("%s ip2region解析地域错误\n", t);
|
||||
goto BLOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
if (isregion(area, region_list) == 1) {
|
||||
printf(RED "%s SSH Ip Address: %s, 地域白名单: %s\n" COLOR_NONE, t, ip, area);
|
||||
return 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
printf(RED "%s 攻击者IP地址:%s, %s\n" COLOR_NONE, t, ip, area);
|
||||
|
||||
BLOCKED:
|
||||
if (conf->IS_BLOCKED == 1) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (area != NULL) {
|
||||
free(area);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void extract_rhost_ip(conf *conf, const char *line) {
|
||||
char *rhost_start = strstr(line, RHOST_KEY);
|
||||
if (rhost_start) {
|
||||
rhost_start += strlen(RHOST_KEY); // 移动到rhost=后的字符
|
||||
char *rhost_end = strpbrk(rhost_start, " \n");
|
||||
if (rhost_end) {
|
||||
char ip[64];
|
||||
strncpy(ip, rhost_start, rhost_end - rhost_start);
|
||||
ip[rhost_end - rhost_start] = '\0';
|
||||
|
||||
Handle_IP(conf, ip);
|
||||
} else {
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rule_(conf *conf, char *LOG_FILE) {
|
||||
FILE *file;
|
||||
char buffer[BUFFER_SIZE];
|
||||
off_t last_size = 0;
|
||||
struct stat file_stat;
|
||||
|
||||
// 打开日志文件
|
||||
file = fopen(LOG_FILE, "r");
|
||||
if (file == NULL) {
|
||||
perror("无法打开日志文件");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// 获取文件初始大小
|
||||
fseek(file, 0, SEEK_END);
|
||||
last_size = ftell(file);
|
||||
|
||||
while (1) {
|
||||
// 检查文件是否被轮转
|
||||
if (stat(LOG_FILE, &file_stat) == -1) {
|
||||
perror("无法获取文件状态");
|
||||
fclose(file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// 如果文件大小小于上次读取的位置,说明文件被轮转了
|
||||
if (file_stat.st_size < last_size) {
|
||||
fclose(file);
|
||||
file = fopen(LOG_FILE, "r");
|
||||
if (file == NULL) {
|
||||
perror("无法重新打开日志文件");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
last_size = 0;
|
||||
}
|
||||
|
||||
// 移动到上次读取的位置
|
||||
fseek(file, last_size, SEEK_SET);
|
||||
|
||||
// 逐行读取新增的日志内容
|
||||
while (fgets(buffer, sizeof(buffer), file) != NULL) {
|
||||
extract_rhost_ip(conf, buffer);
|
||||
}
|
||||
|
||||
// 记录当前文件大小
|
||||
last_size = ftell(file);
|
||||
|
||||
// 暂停一段时间然后继续检查文件变化
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
// 关闭文件
|
||||
fclose(file);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
26
rule.h
26
rule.h
@ -1,26 +0,0 @@
|
||||
#ifndef RULE_H
|
||||
#define RULE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "rhost.h"
|
||||
#include "conf.h"
|
||||
#include "common.h"
|
||||
#include "libiptc.h"
|
||||
#include "ip2region/ip2region.h"
|
||||
|
||||
|
||||
|
||||
#define RHOST_KEY "rhost="
|
||||
#define BUFFER_SIZE 1024
|
||||
#define WHITELIST_IP_NUM 1024
|
||||
|
||||
extern int rule_(conf *conf, char *LOG_FILE);
|
||||
|
||||
#endif
|
136
warning.c
136
warning.c
@ -1,136 +0,0 @@
|
||||
#include "warning.h"
|
||||
|
||||
// 钉钉告警
|
||||
int dingding_warning(char *illegal_ip, char *public_ip, char *ip, conf *conf)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
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.log", "wt+")) == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
curl = curl_easy_init();
|
||||
if (curl == NULL) {
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
#define JSIN "{ \
|
||||
\"msgtype\": \"text\", \
|
||||
\"text\": { \
|
||||
\"content\": \"Alert @%s 服务器地址:%s,封禁非法入侵主机:(%s%s)\" \
|
||||
}, \
|
||||
\"at\": { \
|
||||
\"atMobiles\": [\"%s\"], \
|
||||
\"isAtAll\": false \
|
||||
} \
|
||||
}"
|
||||
|
||||
snprintf(jsonObj, BUFFER, JSIN, conf->PHONE, temp, ip, 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, char *ip, conf *conf)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char text[BUFFER];
|
||||
char temp[64];
|
||||
|
||||
// 初始化缓冲区
|
||||
memset(text, 0, BUFFER);
|
||||
memset(temp, 0, 64);
|
||||
|
||||
// 复制和处理public_ip
|
||||
strncpy(temp, public_ip, sizeof(temp) - 1);
|
||||
temp[_strlen(public_ip) - 1] = '\0';
|
||||
|
||||
// 构建邮件发送命令
|
||||
snprintf(text, BUFFER, "echo \"主机:%s, 禁止(%s%s)访问\" | mail -s \"System ban IP\" %s", temp, ip, illegal_ip, conf->RECV_MAIL);
|
||||
|
||||
// 使用popen发送邮件
|
||||
if (NULL == (fp = popen(text, "r"))) {
|
||||
perror("popen text");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 关闭文件指针
|
||||
if (NULL != fp && pclose(fp) == -1) {
|
||||
perror("pclose");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 第三方邮箱告警
|
||||
int QQ_mail_warning(char *illegal_ip, char *public_ip, char *ip, conf *conf)
|
||||
{
|
||||
char string[BUFFER + (sizeof(QQMAIL)) + 1];
|
||||
char text[BUFFER];
|
||||
char temp[32];
|
||||
|
||||
memset(string, 0, BUFFER + (sizeof(QQMAIL)) + 1);
|
||||
memset(text, 0, BUFFER);
|
||||
memset(temp, 0, 32);
|
||||
strcpy(temp, public_ip);
|
||||
temp[_strlen(public_ip) - 1] = '\0';
|
||||
|
||||
snprintf(text, BUFFER, "主机:%s, 禁止(%s%s)访问!", temp, ip, illegal_ip);
|
||||
snprintf(string, BUFFER + (sizeof(QQMAIL)) + 1, QQMAIL, conf->RECV_MAIL, text);
|
||||
|
||||
return system(string);
|
||||
}
|
||||
|
||||
// 第三方邮箱告警, 感染病毒邮件提醒
|
||||
int QQ_mail_warning_Virus_files(char *local_ip, int Virus_number, conf *conf)
|
||||
{
|
||||
char *command;
|
||||
char *text;
|
||||
char temp[32];
|
||||
|
||||
command = (char *)alloca(BUFFER + (sizeof(QQMAIL)) + 1);
|
||||
text = (char *)alloca(BUFFER);
|
||||
memset(command, 0, BUFFER + (sizeof(QQMAIL)) + 1);
|
||||
memset(text, 0, BUFFER);
|
||||
memset(temp, 0, 32);
|
||||
|
||||
strcpy(temp, local_ip);
|
||||
temp[_strlen(local_ip) - 1] = '\0';
|
||||
snprintf(text, BUFFER, "Host:%s, Infected files: %d, Please handle!", temp, Virus_number);
|
||||
snprintf(command, BUFFER + BUFFER + (sizeof(QQMAIL)) + 1, QQMAIL_Virus, conf->RECV_MAIL, text);
|
||||
|
||||
return system(command);
|
||||
}
|
32
warning.h
32
warning.h
@ -1,32 +0,0 @@
|
||||
#ifndef WARNING_H
|
||||
#define WARNING_H
|
||||
|
||||
#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>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "conf.h"
|
||||
|
||||
#define BUFFER 1024
|
||||
#define QQMAIL "gomail -r %s -s \"System ban IP\" -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\""
|
||||
|
||||
extern int dingding_warning(char *illegal_ip, char *public_ip, char *ip, conf *conf);
|
||||
extern int mail_warning(char *illegal_ip, char *public_ip, char *ip, conf *conf);
|
||||
extern int QQ_mail_warning(char *illegal_ip, char *public_ip, char *ip, conf *conf);
|
||||
extern int QQ_mail_warning_Virus_files(char *local_ip, int Virus_number, conf *conf);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user