diff --git a/.vscode/settings.json b/.vscode/settings.json index 553ce20..1b73545 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,14 @@ "libiptc.h": "c", "stdio.h": "c", "nginx.h": "c", - "cjson.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" } } \ No newline at end of file diff --git a/Makefile b/Makefile index 008976e..c5bac08 100644 --- a/Makefile +++ b/Makefile @@ -20,9 +20,6 @@ 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 @@ -38,10 +35,9 @@ LIBCOMMON_LIB += ./clamav/common/cert_util.c.o ./clamav/common/actions.c.o ./cla all: libclamav_rust libclamav rhost nginx.o -rhost: conf.o rhost.o libiptc.o ccronexpr.o nginx.o disk.o +rhost: conf.o common.o rhost.o libiptc.o ccronexpr.o rule.o nginx.o disk.o ip.o warning.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 @@ -50,7 +46,7 @@ rhost: conf.o rhost.o libiptc.o ccronexpr.o nginx.o disk.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) $(cJSON_LIB) $(ip2region_LIB) $(CLAMAV_LIB) $(IPTC_LIB) $(FRESHCLAM_LIB) + $(CC) $(CFLAGS) $^ -o $(OBG) $(ip2region_LIB) $(CLAMAV_LIB) $(IPTC_LIB) $(FRESHCLAM_LIB) chmod +x $(OBG) diff --git a/cJSON/cJSON.c b/cJSON/cJSON.c deleted file mode 100644 index 3063f74..0000000 --- a/cJSON/cJSON.c +++ /dev/null @@ -1,3110 +0,0 @@ -/* - 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. -*/ - -/* cJSON */ -/* JSON parser in C. */ - -/* disable warnings about old C89 functions in MSVC */ -#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) -#define _CRT_SECURE_NO_DEPRECATE -#endif - -#ifdef __GNUC__ -#pragma GCC visibility push(default) -#endif -#if defined(_MSC_VER) -#pragma warning (push) -/* disable warning about single line comments in system headers */ -#pragma warning (disable : 4001) -#endif - -#include -#include -#include -#include -#include -#include -#include - -#ifdef ENABLE_LOCALES -#include -#endif - -#if defined(_MSC_VER) -#pragma warning (pop) -#endif -#ifdef __GNUC__ -#pragma GCC visibility pop -#endif - -#include "cJSON.h" - -/* define our own boolean type */ -#ifdef true -#undef true -#endif -#define true ((cJSON_bool)1) - -#ifdef false -#undef false -#endif -#define false ((cJSON_bool)0) - -/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ -#ifndef isinf -#define isinf(d) (isnan((d - d)) && !isnan(d)) -#endif -#ifndef isnan -#define isnan(d) (d != d) -#endif - -#ifndef NAN -#ifdef _WIN32 -#define NAN sqrt(-1.0) -#else -#define NAN 0.0/0.0 -#endif -#endif - -typedef struct { - const unsigned char *json; - size_t position; -} error; -static error global_error = { NULL, 0 }; - -CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) -{ - return (const char*) (global_error.json + global_error.position); -} - -CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) -{ - if (!cJSON_IsString(item)) - { - return NULL; - } - - return item->valuestring; -} - -CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) -{ - if (!cJSON_IsNumber(item)) - { - return (double) NAN; - } - - return item->valuedouble; -} - -/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 15) - #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. -#endif - -CJSON_PUBLIC(const char*) cJSON_Version(void) -{ - static char version[15]; - sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); - - return version; -} - -/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ -static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) -{ - if ((string1 == NULL) || (string2 == NULL)) - { - return 1; - } - - if (string1 == string2) - { - return 0; - } - - for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) - { - if (*string1 == '\0') - { - return 0; - } - } - - return tolower(*string1) - tolower(*string2); -} - -typedef struct internal_hooks -{ - void *(CJSON_CDECL *allocate)(size_t size); - void (CJSON_CDECL *deallocate)(void *pointer); - void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); -} internal_hooks; - -#if defined(_MSC_VER) -/* work around MSVC error C2322: '...' address of dllimport '...' is not static */ -static void * CJSON_CDECL internal_malloc(size_t size) -{ - return malloc(size); -} -static void CJSON_CDECL internal_free(void *pointer) -{ - free(pointer); -} -static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) -{ - return realloc(pointer, size); -} -#else -#define internal_malloc malloc -#define internal_free free -#define internal_realloc realloc -#endif - -/* strlen of character literals resolved at compile time */ -#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) - -static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; - -static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) -{ - size_t length = 0; - unsigned char *copy = NULL; - - if (string == NULL) - { - return NULL; - } - - length = strlen((const char*)string) + sizeof(""); - copy = (unsigned char*)hooks->allocate(length); - if (copy == NULL) - { - return NULL; - } - memcpy(copy, string, length); - - return copy; -} - -CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) -{ - if (hooks == NULL) - { - /* Reset hooks */ - global_hooks.allocate = malloc; - global_hooks.deallocate = free; - global_hooks.reallocate = realloc; - return; - } - - global_hooks.allocate = malloc; - if (hooks->malloc_fn != NULL) - { - global_hooks.allocate = hooks->malloc_fn; - } - - global_hooks.deallocate = free; - if (hooks->free_fn != NULL) - { - global_hooks.deallocate = hooks->free_fn; - } - - /* use realloc only if both free and malloc are used */ - global_hooks.reallocate = NULL; - if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) - { - global_hooks.reallocate = realloc; - } -} - -/* Internal constructor. */ -static cJSON *cJSON_New_Item(const internal_hooks * const hooks) -{ - cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); - if (node) - { - memset(node, '\0', sizeof(cJSON)); - } - - return node; -} - -/* Delete a cJSON structure. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) -{ - cJSON *next = NULL; - while (item != NULL) - { - next = item->next; - if (!(item->type & cJSON_IsReference) && (item->child != NULL)) - { - cJSON_Delete(item->child); - } - if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) - { - global_hooks.deallocate(item->valuestring); - } - if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) - { - global_hooks.deallocate(item->string); - } - global_hooks.deallocate(item); - item = next; - } -} - -/* get the decimal point character of the current locale */ -static unsigned char get_decimal_point(void) -{ -#ifdef ENABLE_LOCALES - struct lconv *lconv = localeconv(); - return (unsigned char) lconv->decimal_point[0]; -#else - return '.'; -#endif -} - -typedef struct -{ - const unsigned char *content; - size_t length; - size_t offset; - size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ - internal_hooks hooks; -} parse_buffer; - -/* check if the given size is left to read in a given parse buffer (starting with 1) */ -#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) -/* check if the buffer can be accessed at the given index (starting with 0) */ -#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) -#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) -/* get a pointer to the buffer at the position */ -#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) - -/* Parse the input text to generate a number, and populate the result into item. */ -static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) -{ - double number = 0; - unsigned char *after_end = NULL; - unsigned char number_c_string[64]; - unsigned char decimal_point = get_decimal_point(); - size_t i = 0; - - if ((input_buffer == NULL) || (input_buffer->content == NULL)) - { - return false; - } - - /* copy the number into a temporary buffer and replace '.' with the decimal point - * of the current locale (for strtod) - * This also takes care of '\0' not necessarily being available for marking the end of the input */ - for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) - { - switch (buffer_at_offset(input_buffer)[i]) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '+': - case '-': - case 'e': - case 'E': - number_c_string[i] = buffer_at_offset(input_buffer)[i]; - break; - - case '.': - number_c_string[i] = decimal_point; - break; - - default: - goto loop_end; - } - } -loop_end: - number_c_string[i] = '\0'; - - number = strtod((const char*)number_c_string, (char**)&after_end); - if (number_c_string == after_end) - { - return false; /* parse_error */ - } - - item->valuedouble = number; - - /* use saturation in case of overflow */ - if (number >= INT_MAX) - { - item->valueint = INT_MAX; - } - else if (number <= (double)INT_MIN) - { - item->valueint = INT_MIN; - } - else - { - item->valueint = (int)number; - } - - item->type = cJSON_Number; - - input_buffer->offset += (size_t)(after_end - number_c_string); - return true; -} - -/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ -CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) -{ - if (number >= INT_MAX) - { - object->valueint = INT_MAX; - } - else if (number <= (double)INT_MIN) - { - object->valueint = INT_MIN; - } - else - { - object->valueint = (int)number; - } - - return object->valuedouble = number; -} - -CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) -{ - char *copy = NULL; - /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ - if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) - { - return NULL; - } - if (strlen(valuestring) <= strlen(object->valuestring)) - { - strcpy(object->valuestring, valuestring); - return object->valuestring; - } - copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); - if (copy == NULL) - { - return NULL; - } - if (object->valuestring != NULL) - { - cJSON_free(object->valuestring); - } - object->valuestring = copy; - - return copy; -} - -typedef struct -{ - unsigned char *buffer; - size_t length; - size_t offset; - size_t depth; /* current nesting depth (for formatted printing) */ - cJSON_bool noalloc; - cJSON_bool format; /* is this print a formatted print */ - internal_hooks hooks; -} printbuffer; - -/* realloc printbuffer if necessary to have at least "needed" bytes more */ -static unsigned char* ensure(printbuffer * const p, size_t needed) -{ - unsigned char *newbuffer = NULL; - size_t newsize = 0; - - if ((p == NULL) || (p->buffer == NULL)) - { - return NULL; - } - - if ((p->length > 0) && (p->offset >= p->length)) - { - /* make sure that offset is valid */ - return NULL; - } - - if (needed > INT_MAX) - { - /* sizes bigger than INT_MAX are currently not supported */ - return NULL; - } - - needed += p->offset + 1; - if (needed <= p->length) - { - return p->buffer + p->offset; - } - - if (p->noalloc) { - return NULL; - } - - /* calculate new buffer size */ - if (needed > (INT_MAX / 2)) - { - /* overflow of int, use INT_MAX if possible */ - if (needed <= INT_MAX) - { - newsize = INT_MAX; - } - else - { - return NULL; - } - } - else - { - newsize = needed * 2; - } - - if (p->hooks.reallocate != NULL) - { - /* reallocate with realloc if available */ - newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); - if (newbuffer == NULL) - { - p->hooks.deallocate(p->buffer); - p->length = 0; - p->buffer = NULL; - - return NULL; - } - } - else - { - /* otherwise reallocate manually */ - newbuffer = (unsigned char*)p->hooks.allocate(newsize); - if (!newbuffer) - { - p->hooks.deallocate(p->buffer); - p->length = 0; - p->buffer = NULL; - - return NULL; - } - - memcpy(newbuffer, p->buffer, p->offset + 1); - p->hooks.deallocate(p->buffer); - } - p->length = newsize; - p->buffer = newbuffer; - - return newbuffer + p->offset; -} - -/* calculate the new length of the string in a printbuffer and update the offset */ -static void update_offset(printbuffer * const buffer) -{ - const unsigned char *buffer_pointer = NULL; - if ((buffer == NULL) || (buffer->buffer == NULL)) - { - return; - } - buffer_pointer = buffer->buffer + buffer->offset; - - buffer->offset += strlen((const char*)buffer_pointer); -} - -/* securely comparison of floating-point variables */ -static cJSON_bool compare_double(double a, double b) -{ - double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); - return (fabs(a - b) <= maxVal * DBL_EPSILON); -} - -/* Render the number nicely from the given item into a string. */ -static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output_pointer = NULL; - double d = item->valuedouble; - int length = 0; - size_t i = 0; - unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ - unsigned char decimal_point = get_decimal_point(); - double test = 0.0; - - if (output_buffer == NULL) - { - return false; - } - - /* This checks for NaN and Infinity */ - if (isnan(d) || isinf(d)) - { - length = sprintf((char*)number_buffer, "null"); - } - else - { - /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ - length = sprintf((char*)number_buffer, "%1.15g", d); - - /* Check whether the original double can be recovered */ - if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) - { - /* If not, print with 17 decimal places of precision */ - length = sprintf((char*)number_buffer, "%1.17g", d); - } - } - - /* sprintf failed or buffer overrun occurred */ - if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) - { - return false; - } - - /* reserve appropriate space in the output */ - output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); - if (output_pointer == NULL) - { - return false; - } - - /* copy the printed number to the output and replace locale - * dependent decimal point with '.' */ - for (i = 0; i < ((size_t)length); i++) - { - if (number_buffer[i] == decimal_point) - { - output_pointer[i] = '.'; - continue; - } - - output_pointer[i] = number_buffer[i]; - } - output_pointer[i] = '\0'; - - output_buffer->offset += (size_t)length; - - return true; -} - -/* parse 4 digit hexadecimal number */ -static unsigned parse_hex4(const unsigned char * const input) -{ - unsigned int h = 0; - size_t i = 0; - - for (i = 0; i < 4; i++) - { - /* parse digit */ - if ((input[i] >= '0') && (input[i] <= '9')) - { - h += (unsigned int) input[i] - '0'; - } - else if ((input[i] >= 'A') && (input[i] <= 'F')) - { - h += (unsigned int) 10 + input[i] - 'A'; - } - else if ((input[i] >= 'a') && (input[i] <= 'f')) - { - h += (unsigned int) 10 + input[i] - 'a'; - } - else /* invalid */ - { - return 0; - } - - if (i < 3) - { - /* shift left to make place for the next nibble */ - h = h << 4; - } - } - - return h; -} - -/* converts a UTF-16 literal to UTF-8 - * A literal can be one or two sequences of the form \uXXXX */ -static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) -{ - long unsigned int codepoint = 0; - unsigned int first_code = 0; - const unsigned char *first_sequence = input_pointer; - unsigned char utf8_length = 0; - unsigned char utf8_position = 0; - unsigned char sequence_length = 0; - unsigned char first_byte_mark = 0; - - if ((input_end - first_sequence) < 6) - { - /* input ends unexpectedly */ - goto fail; - } - - /* get the first utf16 sequence */ - first_code = parse_hex4(first_sequence + 2); - - /* check that the code is valid */ - if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) - { - goto fail; - } - - /* UTF16 surrogate pair */ - if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) - { - const unsigned char *second_sequence = first_sequence + 6; - unsigned int second_code = 0; - sequence_length = 12; /* \uXXXX\uXXXX */ - - if ((input_end - second_sequence) < 6) - { - /* input ends unexpectedly */ - goto fail; - } - - if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) - { - /* missing second half of the surrogate pair */ - goto fail; - } - - /* get the second utf16 sequence */ - second_code = parse_hex4(second_sequence + 2); - /* check that the code is valid */ - if ((second_code < 0xDC00) || (second_code > 0xDFFF)) - { - /* invalid second half of the surrogate pair */ - goto fail; - } - - - /* calculate the unicode codepoint from the surrogate pair */ - codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); - } - else - { - sequence_length = 6; /* \uXXXX */ - codepoint = first_code; - } - - /* encode as UTF-8 - * takes at maximum 4 bytes to encode: - * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - if (codepoint < 0x80) - { - /* normal ascii, encoding 0xxxxxxx */ - utf8_length = 1; - } - else if (codepoint < 0x800) - { - /* two bytes, encoding 110xxxxx 10xxxxxx */ - utf8_length = 2; - first_byte_mark = 0xC0; /* 11000000 */ - } - else if (codepoint < 0x10000) - { - /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ - utf8_length = 3; - first_byte_mark = 0xE0; /* 11100000 */ - } - else if (codepoint <= 0x10FFFF) - { - /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ - utf8_length = 4; - first_byte_mark = 0xF0; /* 11110000 */ - } - else - { - /* invalid unicode codepoint */ - goto fail; - } - - /* encode as utf8 */ - for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) - { - /* 10xxxxxx */ - (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); - codepoint >>= 6; - } - /* encode first byte */ - if (utf8_length > 1) - { - (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); - } - else - { - (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); - } - - *output_pointer += utf8_length; - - return sequence_length; - -fail: - return 0; -} - -/* Parse the input text into an unescaped cinput, and populate item. */ -static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) -{ - const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; - const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; - unsigned char *output_pointer = NULL; - unsigned char *output = NULL; - - /* not a string */ - if (buffer_at_offset(input_buffer)[0] != '\"') - { - goto fail; - } - - { - /* calculate approximate size of the output (overestimate) */ - size_t allocation_length = 0; - size_t skipped_bytes = 0; - while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) - { - /* is escape sequence */ - if (input_end[0] == '\\') - { - if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) - { - /* prevent buffer overflow when last input character is a backslash */ - goto fail; - } - skipped_bytes++; - input_end++; - } - input_end++; - } - if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) - { - goto fail; /* string ended unexpectedly */ - } - - /* This is at most how much we need for the output */ - allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; - output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); - if (output == NULL) - { - goto fail; /* allocation failure */ - } - } - - output_pointer = output; - /* loop through the string literal */ - while (input_pointer < input_end) - { - if (*input_pointer != '\\') - { - *output_pointer++ = *input_pointer++; - } - /* escape sequence */ - else - { - unsigned char sequence_length = 2; - if ((input_end - input_pointer) < 1) - { - goto fail; - } - - switch (input_pointer[1]) - { - case 'b': - *output_pointer++ = '\b'; - break; - case 'f': - *output_pointer++ = '\f'; - break; - case 'n': - *output_pointer++ = '\n'; - break; - case 'r': - *output_pointer++ = '\r'; - break; - case 't': - *output_pointer++ = '\t'; - break; - case '\"': - case '\\': - case '/': - *output_pointer++ = input_pointer[1]; - break; - - /* UTF-16 literal */ - case 'u': - sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); - if (sequence_length == 0) - { - /* failed to convert UTF16-literal to UTF-8 */ - goto fail; - } - break; - - default: - goto fail; - } - input_pointer += sequence_length; - } - } - - /* zero terminate the output */ - *output_pointer = '\0'; - - item->type = cJSON_String; - item->valuestring = (char*)output; - - input_buffer->offset = (size_t) (input_end - input_buffer->content); - input_buffer->offset++; - - return true; - -fail: - if (output != NULL) - { - input_buffer->hooks.deallocate(output); - } - - if (input_pointer != NULL) - { - input_buffer->offset = (size_t)(input_pointer - input_buffer->content); - } - - return false; -} - -/* Render the cstring provided to an escaped version that can be printed. */ -static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) -{ - const unsigned char *input_pointer = NULL; - unsigned char *output = NULL; - unsigned char *output_pointer = NULL; - size_t output_length = 0; - /* numbers of additional characters needed for escaping */ - size_t escape_characters = 0; - - if (output_buffer == NULL) - { - return false; - } - - /* empty string */ - if (input == NULL) - { - output = ensure(output_buffer, sizeof("\"\"")); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "\"\""); - - return true; - } - - /* set "flag" to 1 if something needs to be escaped */ - for (input_pointer = input; *input_pointer; input_pointer++) - { - switch (*input_pointer) - { - case '\"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - /* one character escape sequence */ - escape_characters++; - break; - default: - if (*input_pointer < 32) - { - /* UTF-16 escape sequence uXXXX */ - escape_characters += 5; - } - break; - } - } - output_length = (size_t)(input_pointer - input) + escape_characters; - - output = ensure(output_buffer, output_length + sizeof("\"\"")); - if (output == NULL) - { - return false; - } - - /* no characters have to be escaped */ - if (escape_characters == 0) - { - output[0] = '\"'; - memcpy(output + 1, input, output_length); - output[output_length + 1] = '\"'; - output[output_length + 2] = '\0'; - - return true; - } - - output[0] = '\"'; - output_pointer = output + 1; - /* copy the string */ - for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) - { - if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) - { - /* normal character, copy */ - *output_pointer = *input_pointer; - } - else - { - /* character needs to be escaped */ - *output_pointer++ = '\\'; - switch (*input_pointer) - { - case '\\': - *output_pointer = '\\'; - break; - case '\"': - *output_pointer = '\"'; - break; - case '\b': - *output_pointer = 'b'; - break; - case '\f': - *output_pointer = 'f'; - break; - case '\n': - *output_pointer = 'n'; - break; - case '\r': - *output_pointer = 'r'; - break; - case '\t': - *output_pointer = 't'; - break; - default: - /* escape and print as unicode codepoint */ - sprintf((char*)output_pointer, "u%04x", *input_pointer); - output_pointer += 4; - break; - } - } - } - output[output_length + 1] = '\"'; - output[output_length + 2] = '\0'; - - return true; -} - -/* Invoke print_string_ptr (which is useful) on an item. */ -static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) -{ - return print_string_ptr((unsigned char*)item->valuestring, p); -} - -/* Predeclare these prototypes. */ -static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); -static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); -static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); -static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); -static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); -static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); - -/* Utility to jump whitespace and cr/lf */ -static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) -{ - if ((buffer == NULL) || (buffer->content == NULL)) - { - return NULL; - } - - if (cannot_access_at_index(buffer, 0)) - { - return buffer; - } - - while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) - { - buffer->offset++; - } - - if (buffer->offset == buffer->length) - { - buffer->offset--; - } - - return buffer; -} - -/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ -static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) -{ - if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) - { - return NULL; - } - - if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) - { - buffer->offset += 3; - } - - return buffer; -} - -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) -{ - size_t buffer_length; - - if (NULL == value) - { - return NULL; - } - - /* Adding null character size due to require_null_terminated. */ - buffer_length = strlen(value) + sizeof(""); - - return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); -} - -/* Parse an object - create a new root, and populate. */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) -{ - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; - cJSON *item = NULL; - - /* reset error position */ - global_error.json = NULL; - global_error.position = 0; - - if (value == NULL || 0 == buffer_length) - { - goto fail; - } - - buffer.content = (const unsigned char*)value; - buffer.length = buffer_length; - buffer.offset = 0; - buffer.hooks = global_hooks; - - item = cJSON_New_Item(&global_hooks); - if (item == NULL) /* memory fail */ - { - goto fail; - } - - if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) - { - /* parse failure. ep is set. */ - goto fail; - } - - /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ - if (require_null_terminated) - { - buffer_skip_whitespace(&buffer); - if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') - { - goto fail; - } - } - if (return_parse_end) - { - *return_parse_end = (const char*)buffer_at_offset(&buffer); - } - - return item; - -fail: - if (item != NULL) - { - cJSON_Delete(item); - } - - if (value != NULL) - { - error local_error; - local_error.json = (const unsigned char*)value; - local_error.position = 0; - - if (buffer.offset < buffer.length) - { - local_error.position = buffer.offset; - } - else if (buffer.length > 0) - { - local_error.position = buffer.length - 1; - } - - if (return_parse_end != NULL) - { - *return_parse_end = (const char*)local_error.json + local_error.position; - } - - global_error = local_error; - } - - return NULL; -} - -/* Default options for cJSON_Parse */ -CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) -{ - return cJSON_ParseWithOpts(value, 0, 0); -} - -CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) -{ - return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); -} - -#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) - -static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) -{ - static const size_t default_buffer_size = 256; - printbuffer buffer[1]; - unsigned char *printed = NULL; - - memset(buffer, 0, sizeof(buffer)); - - /* create buffer */ - buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); - buffer->length = default_buffer_size; - buffer->format = format; - buffer->hooks = *hooks; - if (buffer->buffer == NULL) - { - goto fail; - } - - /* print the value */ - if (!print_value(item, buffer)) - { - goto fail; - } - update_offset(buffer); - - /* check if reallocate is available */ - if (hooks->reallocate != NULL) - { - printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); - if (printed == NULL) { - goto fail; - } - buffer->buffer = NULL; - } - else /* otherwise copy the JSON over to a new buffer */ - { - printed = (unsigned char*) hooks->allocate(buffer->offset + 1); - if (printed == NULL) - { - goto fail; - } - memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); - printed[buffer->offset] = '\0'; /* just to be sure */ - - /* free the buffer */ - hooks->deallocate(buffer->buffer); - } - - return printed; - -fail: - if (buffer->buffer != NULL) - { - hooks->deallocate(buffer->buffer); - } - - if (printed != NULL) - { - hooks->deallocate(printed); - } - - return NULL; -} - -/* Render a cJSON item/entity/structure to text. */ -CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) -{ - return (char*)print(item, true, &global_hooks); -} - -CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) -{ - return (char*)print(item, false, &global_hooks); -} - -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) -{ - printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - - if (prebuffer < 0) - { - return NULL; - } - - p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); - if (!p.buffer) - { - return NULL; - } - - p.length = (size_t)prebuffer; - p.offset = 0; - p.noalloc = false; - p.format = fmt; - p.hooks = global_hooks; - - if (!print_value(item, &p)) - { - global_hooks.deallocate(p.buffer); - return NULL; - } - - return (char*)p.buffer; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) -{ - printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - - if ((length < 0) || (buffer == NULL)) - { - return false; - } - - p.buffer = (unsigned char*)buffer; - p.length = (size_t)length; - p.offset = 0; - p.noalloc = true; - p.format = format; - p.hooks = global_hooks; - - return print_value(item, &p); -} - -/* Parser core - when encountering text, process appropriately. */ -static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) -{ - if ((input_buffer == NULL) || (input_buffer->content == NULL)) - { - return false; /* no input */ - } - - /* parse the different types of values */ - /* null */ - if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) - { - item->type = cJSON_NULL; - input_buffer->offset += 4; - return true; - } - /* false */ - if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) - { - item->type = cJSON_False; - input_buffer->offset += 5; - return true; - } - /* true */ - if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) - { - item->type = cJSON_True; - item->valueint = 1; - input_buffer->offset += 4; - return true; - } - /* string */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) - { - return parse_string(item, input_buffer); - } - /* number */ - if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) - { - return parse_number(item, input_buffer); - } - /* array */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) - { - return parse_array(item, input_buffer); - } - /* object */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) - { - return parse_object(item, input_buffer); - } - - return false; -} - -/* Render a value to text. */ -static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output = NULL; - - if ((item == NULL) || (output_buffer == NULL)) - { - return false; - } - - switch ((item->type) & 0xFF) - { - case cJSON_NULL: - output = ensure(output_buffer, 5); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "null"); - return true; - - case cJSON_False: - output = ensure(output_buffer, 6); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "false"); - return true; - - case cJSON_True: - output = ensure(output_buffer, 5); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "true"); - return true; - - case cJSON_Number: - return print_number(item, output_buffer); - - case cJSON_Raw: - { - size_t raw_length = 0; - if (item->valuestring == NULL) - { - return false; - } - - raw_length = strlen(item->valuestring) + sizeof(""); - output = ensure(output_buffer, raw_length); - if (output == NULL) - { - return false; - } - memcpy(output, item->valuestring, raw_length); - return true; - } - - case cJSON_String: - return print_string(item, output_buffer); - - case cJSON_Array: - return print_array(item, output_buffer); - - case cJSON_Object: - return print_object(item, output_buffer); - - default: - return false; - } -} - -/* Build an array from input text. */ -static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) -{ - cJSON *head = NULL; /* head of the linked list */ - cJSON *current_item = NULL; - - if (input_buffer->depth >= CJSON_NESTING_LIMIT) - { - return false; /* to deeply nested */ - } - input_buffer->depth++; - - if (buffer_at_offset(input_buffer)[0] != '[') - { - /* not an array */ - goto fail; - } - - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) - { - /* empty array */ - goto success; - } - - /* check if we skipped to the end of the buffer */ - if (cannot_access_at_index(input_buffer, 0)) - { - input_buffer->offset--; - goto fail; - } - - /* step back to character in front of the first element */ - input_buffer->offset--; - /* loop through the comma separated array elements */ - do - { - /* allocate next item */ - cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); - if (new_item == NULL) - { - goto fail; /* allocation failure */ - } - - /* attach next item to list */ - if (head == NULL) - { - /* start the linked list */ - current_item = head = new_item; - } - else - { - /* add to the end and advance */ - current_item->next = new_item; - new_item->prev = current_item; - current_item = new_item; - } - - /* parse next value */ - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) - { - goto fail; /* failed to parse value */ - } - buffer_skip_whitespace(input_buffer); - } - while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - - if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') - { - goto fail; /* expected end of array */ - } - -success: - input_buffer->depth--; - - if (head != NULL) { - head->prev = current_item; - } - - item->type = cJSON_Array; - item->child = head; - - input_buffer->offset++; - - return true; - -fail: - if (head != NULL) - { - cJSON_Delete(head); - } - - return false; -} - -/* Render an array to text */ -static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output_pointer = NULL; - size_t length = 0; - cJSON *current_element = item->child; - - if (output_buffer == NULL) - { - return false; - } - - /* Compose the output array. */ - /* opening square bracket */ - output_pointer = ensure(output_buffer, 1); - if (output_pointer == NULL) - { - return false; - } - - *output_pointer = '['; - output_buffer->offset++; - output_buffer->depth++; - - while (current_element != NULL) - { - if (!print_value(current_element, output_buffer)) - { - return false; - } - update_offset(output_buffer); - if (current_element->next) - { - length = (size_t) (output_buffer->format ? 2 : 1); - output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { - return false; - } - *output_pointer++ = ','; - if(output_buffer->format) - { - *output_pointer++ = ' '; - } - *output_pointer = '\0'; - output_buffer->offset += length; - } - current_element = current_element->next; - } - - output_pointer = ensure(output_buffer, 2); - if (output_pointer == NULL) - { - return false; - } - *output_pointer++ = ']'; - *output_pointer = '\0'; - output_buffer->depth--; - - return true; -} - -/* Build an object from the text. */ -static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) -{ - cJSON *head = NULL; /* linked list head */ - cJSON *current_item = NULL; - - if (input_buffer->depth >= CJSON_NESTING_LIMIT) - { - return false; /* to deeply nested */ - } - input_buffer->depth++; - - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) - { - goto fail; /* not an object */ - } - - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) - { - goto success; /* empty object */ - } - - /* check if we skipped to the end of the buffer */ - if (cannot_access_at_index(input_buffer, 0)) - { - input_buffer->offset--; - goto fail; - } - - /* step back to character in front of the first element */ - input_buffer->offset--; - /* loop through the comma separated array elements */ - do - { - /* allocate next item */ - cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); - if (new_item == NULL) - { - goto fail; /* allocation failure */ - } - - /* attach next item to list */ - if (head == NULL) - { - /* start the linked list */ - current_item = head = new_item; - } - else - { - /* add to the end and advance */ - current_item->next = new_item; - new_item->prev = current_item; - current_item = new_item; - } - - /* parse the name of the child */ - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_string(current_item, input_buffer)) - { - goto fail; /* failed to parse name */ - } - buffer_skip_whitespace(input_buffer); - - /* swap valuestring and string, because we parsed the name */ - current_item->string = current_item->valuestring; - current_item->valuestring = NULL; - - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) - { - goto fail; /* invalid object */ - } - - /* parse the value */ - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) - { - goto fail; /* failed to parse value */ - } - buffer_skip_whitespace(input_buffer); - } - while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) - { - goto fail; /* expected end of object */ - } - -success: - input_buffer->depth--; - - if (head != NULL) { - head->prev = current_item; - } - - item->type = cJSON_Object; - item->child = head; - - input_buffer->offset++; - return true; - -fail: - if (head != NULL) - { - cJSON_Delete(head); - } - - return false; -} - -/* Render an object to text. */ -static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output_pointer = NULL; - size_t length = 0; - cJSON *current_item = item->child; - - if (output_buffer == NULL) - { - return false; - } - - /* Compose the output: */ - length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ - output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { - return false; - } - - *output_pointer++ = '{'; - output_buffer->depth++; - if (output_buffer->format) - { - *output_pointer++ = '\n'; - } - output_buffer->offset += length; - - while (current_item) - { - if (output_buffer->format) - { - size_t i; - output_pointer = ensure(output_buffer, output_buffer->depth); - if (output_pointer == NULL) - { - return false; - } - for (i = 0; i < output_buffer->depth; i++) - { - *output_pointer++ = '\t'; - } - output_buffer->offset += output_buffer->depth; - } - - /* print key */ - if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) - { - return false; - } - update_offset(output_buffer); - - length = (size_t) (output_buffer->format ? 2 : 1); - output_pointer = ensure(output_buffer, length); - if (output_pointer == NULL) - { - return false; - } - *output_pointer++ = ':'; - if (output_buffer->format) - { - *output_pointer++ = '\t'; - } - output_buffer->offset += length; - - /* print value */ - if (!print_value(current_item, output_buffer)) - { - return false; - } - update_offset(output_buffer); - - /* print comma if not last */ - length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); - output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { - return false; - } - if (current_item->next) - { - *output_pointer++ = ','; - } - - if (output_buffer->format) - { - *output_pointer++ = '\n'; - } - *output_pointer = '\0'; - output_buffer->offset += length; - - current_item = current_item->next; - } - - output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); - if (output_pointer == NULL) - { - return false; - } - if (output_buffer->format) - { - size_t i; - for (i = 0; i < (output_buffer->depth - 1); i++) - { - *output_pointer++ = '\t'; - } - } - *output_pointer++ = '}'; - *output_pointer = '\0'; - output_buffer->depth--; - - return true; -} - -/* Get Array size/item / object item. */ -CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) -{ - cJSON *child = NULL; - size_t size = 0; - - if (array == NULL) - { - return 0; - } - - child = array->child; - - while(child != NULL) - { - size++; - child = child->next; - } - - /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ - - return (int)size; -} - -static cJSON* get_array_item(const cJSON *array, size_t index) -{ - cJSON *current_child = NULL; - - if (array == NULL) - { - return NULL; - } - - current_child = array->child; - while ((current_child != NULL) && (index > 0)) - { - index--; - current_child = current_child->next; - } - - return current_child; -} - -CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) -{ - if (index < 0) - { - return NULL; - } - - return get_array_item(array, (size_t)index); -} - -static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) -{ - cJSON *current_element = NULL; - - if ((object == NULL) || (name == NULL)) - { - return NULL; - } - - current_element = object->child; - if (case_sensitive) - { - while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) - { - current_element = current_element->next; - } - } - else - { - while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) - { - current_element = current_element->next; - } - } - - if ((current_element == NULL) || (current_element->string == NULL)) { - return NULL; - } - - return current_element; -} - -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) -{ - return get_object_item(object, string, false); -} - -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) -{ - return get_object_item(object, string, true); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) -{ - return cJSON_GetObjectItem(object, string) ? 1 : 0; -} - -/* Utility for array list handling. */ -static void suffix_object(cJSON *prev, cJSON *item) -{ - prev->next = item; - item->prev = prev; -} - -/* Utility for handling references. */ -static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) -{ - cJSON *reference = NULL; - if (item == NULL) - { - return NULL; - } - - reference = cJSON_New_Item(hooks); - if (reference == NULL) - { - return NULL; - } - - memcpy(reference, item, sizeof(cJSON)); - reference->string = NULL; - reference->type |= cJSON_IsReference; - reference->next = reference->prev = NULL; - return reference; -} - -static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) -{ - cJSON *child = NULL; - - if ((item == NULL) || (array == NULL) || (array == item)) - { - return false; - } - - child = array->child; - /* - * To find the last item in array quickly, we use prev in array - */ - if (child == NULL) - { - /* list is empty, start new one */ - array->child = item; - item->prev = item; - item->next = NULL; - } - else - { - /* append to the end */ - if (child->prev) - { - suffix_object(child->prev, item); - array->child->prev = item; - } - } - - return true; -} - -/* Add item to array/object. */ -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) -{ - return add_item_to_array(array, item); -} - -#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) - #pragma GCC diagnostic push -#endif -#ifdef __GNUC__ -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif -/* helper function to cast away const */ -static void* cast_away_const(const void* string) -{ - return (void*)string; -} -#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) - #pragma GCC diagnostic pop -#endif - - -static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) -{ - char *new_key = NULL; - int new_type = cJSON_Invalid; - - if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) - { - return false; - } - - if (constant_key) - { - new_key = (char*)cast_away_const(string); - new_type = item->type | cJSON_StringIsConst; - } - else - { - new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); - if (new_key == NULL) - { - return false; - } - - new_type = item->type & ~cJSON_StringIsConst; - } - - if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) - { - hooks->deallocate(item->string); - } - - item->string = new_key; - item->type = new_type; - - return add_item_to_array(object, item); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) -{ - return add_item_to_object(object, string, item, &global_hooks, false); -} - -/* Add an item to an object with constant string as key */ -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) -{ - return add_item_to_object(object, string, item, &global_hooks, true); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) -{ - if (array == NULL) - { - return false; - } - - return add_item_to_array(array, create_reference(item, &global_hooks)); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) -{ - if ((object == NULL) || (string == NULL)) - { - return false; - } - - return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); -} - -CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) -{ - cJSON *null = cJSON_CreateNull(); - if (add_item_to_object(object, name, null, &global_hooks, false)) - { - return null; - } - - cJSON_Delete(null); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) -{ - cJSON *true_item = cJSON_CreateTrue(); - if (add_item_to_object(object, name, true_item, &global_hooks, false)) - { - return true_item; - } - - cJSON_Delete(true_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) -{ - cJSON *false_item = cJSON_CreateFalse(); - if (add_item_to_object(object, name, false_item, &global_hooks, false)) - { - return false_item; - } - - cJSON_Delete(false_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) -{ - cJSON *bool_item = cJSON_CreateBool(boolean); - if (add_item_to_object(object, name, bool_item, &global_hooks, false)) - { - return bool_item; - } - - cJSON_Delete(bool_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) -{ - cJSON *number_item = cJSON_CreateNumber(number); - if (add_item_to_object(object, name, number_item, &global_hooks, false)) - { - return number_item; - } - - cJSON_Delete(number_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) -{ - cJSON *string_item = cJSON_CreateString(string); - if (add_item_to_object(object, name, string_item, &global_hooks, false)) - { - return string_item; - } - - cJSON_Delete(string_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) -{ - cJSON *raw_item = cJSON_CreateRaw(raw); - if (add_item_to_object(object, name, raw_item, &global_hooks, false)) - { - return raw_item; - } - - cJSON_Delete(raw_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) -{ - cJSON *object_item = cJSON_CreateObject(); - if (add_item_to_object(object, name, object_item, &global_hooks, false)) - { - return object_item; - } - - cJSON_Delete(object_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) -{ - cJSON *array = cJSON_CreateArray(); - if (add_item_to_object(object, name, array, &global_hooks, false)) - { - return array; - } - - cJSON_Delete(array); - return NULL; -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) -{ - if ((parent == NULL) || (item == NULL)) - { - return NULL; - } - - if (item != parent->child) - { - /* not the first element */ - item->prev->next = item->next; - } - if (item->next != NULL) - { - /* not the last element */ - item->next->prev = item->prev; - } - - if (item == parent->child) - { - /* first element */ - parent->child = item->next; - } - else if (item->next == NULL) - { - /* last element */ - parent->child->prev = item->prev; - } - - /* make sure the detached item doesn't point anywhere anymore */ - item->prev = NULL; - item->next = NULL; - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) -{ - if (which < 0) - { - return NULL; - } - - return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) -{ - cJSON_Delete(cJSON_DetachItemFromArray(array, which)); -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) -{ - cJSON *to_detach = cJSON_GetObjectItem(object, string); - - return cJSON_DetachItemViaPointer(object, to_detach); -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) -{ - cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); - - return cJSON_DetachItemViaPointer(object, to_detach); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) -{ - cJSON_Delete(cJSON_DetachItemFromObject(object, string)); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) -{ - cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); -} - -/* Replace array/object items with new ones. */ -CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) -{ - cJSON *after_inserted = NULL; - - if (which < 0) - { - return false; - } - - after_inserted = get_array_item(array, (size_t)which); - if (after_inserted == NULL) - { - return add_item_to_array(array, newitem); - } - - newitem->next = after_inserted; - newitem->prev = after_inserted->prev; - after_inserted->prev = newitem; - if (after_inserted == array->child) - { - array->child = newitem; - } - else - { - newitem->prev->next = newitem; - } - return true; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) -{ - if ((parent == NULL) || (replacement == NULL) || (item == NULL)) - { - return false; - } - - if (replacement == item) - { - return true; - } - - replacement->next = item->next; - replacement->prev = item->prev; - - if (replacement->next != NULL) - { - replacement->next->prev = replacement; - } - if (parent->child == item) - { - if (parent->child->prev == parent->child) - { - replacement->prev = replacement; - } - parent->child = replacement; - } - else - { /* - * To find the last item in array quickly, we use prev in array. - * We can't modify the last item's next pointer where this item was the parent's child - */ - if (replacement->prev != NULL) - { - replacement->prev->next = replacement; - } - if (replacement->next == NULL) - { - parent->child->prev = replacement; - } - } - - item->next = NULL; - item->prev = NULL; - cJSON_Delete(item); - - return true; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) -{ - if (which < 0) - { - return false; - } - - return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); -} - -static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) -{ - if ((replacement == NULL) || (string == NULL)) - { - return false; - } - - /* replace the name in the replacement */ - if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) - { - cJSON_free(replacement->string); - } - replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - replacement->type &= ~cJSON_StringIsConst; - - return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) -{ - return replace_item_in_object(object, string, newitem, false); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) -{ - return replace_item_in_object(object, string, newitem, true); -} - -/* Create basic types: */ -CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_NULL; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_True; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_False; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = boolean ? cJSON_True : cJSON_False; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_Number; - item->valuedouble = num; - - /* use saturation in case of overflow */ - if (num >= INT_MAX) - { - item->valueint = INT_MAX; - } - else if (num <= (double)INT_MIN) - { - item->valueint = INT_MIN; - } - else - { - item->valueint = (int)num; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_String; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - if(!item->valuestring) - { - cJSON_Delete(item); - return NULL; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if (item != NULL) - { - item->type = cJSON_String | cJSON_IsReference; - item->valuestring = (char*)cast_away_const(string); - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if (item != NULL) { - item->type = cJSON_Object | cJSON_IsReference; - item->child = (cJSON*)cast_away_const(child); - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { - cJSON *item = cJSON_New_Item(&global_hooks); - if (item != NULL) { - item->type = cJSON_Array | cJSON_IsReference; - item->child = (cJSON*)cast_away_const(child); - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_Raw; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); - if(!item->valuestring) - { - cJSON_Delete(item); - return NULL; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type=cJSON_Array; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if (item) - { - item->type = cJSON_Object; - } - - return item; -} - -/* Create Arrays: */ -CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (numbers == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber(numbers[i]); - if (!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - if (a && a->child) { - a->child->prev = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (numbers == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber((double)numbers[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - if (a && a->child) { - a->child->prev = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (numbers == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber(numbers[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - if (a && a->child) { - a->child->prev = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (strings == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for (i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateString(strings[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p,n); - } - p = n; - } - - if (a && a->child) { - a->child->prev = n; - } - - return a; -} - -/* Duplication */ -CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) -{ - cJSON *newitem = NULL; - cJSON *child = NULL; - cJSON *next = NULL; - cJSON *newchild = NULL; - - /* Bail on bad ptr */ - if (!item) - { - goto fail; - } - /* Create new item */ - newitem = cJSON_New_Item(&global_hooks); - if (!newitem) - { - goto fail; - } - /* Copy over all vars */ - newitem->type = item->type & (~cJSON_IsReference); - newitem->valueint = item->valueint; - newitem->valuedouble = item->valuedouble; - if (item->valuestring) - { - newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); - if (!newitem->valuestring) - { - goto fail; - } - } - if (item->string) - { - newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); - if (!newitem->string) - { - goto fail; - } - } - /* If non-recursive, then we're done! */ - if (!recurse) - { - return newitem; - } - /* Walk the ->next chain for the child. */ - child = item->child; - while (child != NULL) - { - newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ - if (!newchild) - { - goto fail; - } - if (next != NULL) - { - /* If newitem->child already set, then crosswire ->prev and ->next and move on */ - next->next = newchild; - newchild->prev = next; - next = newchild; - } - else - { - /* Set newitem->child and move to it */ - newitem->child = newchild; - next = newchild; - } - child = child->next; - } - if (newitem && newitem->child) - { - newitem->child->prev = newchild; - } - - return newitem; - -fail: - if (newitem != NULL) - { - cJSON_Delete(newitem); - } - - return NULL; -} - -static void skip_oneline_comment(char **input) -{ - *input += static_strlen("//"); - - for (; (*input)[0] != '\0'; ++(*input)) - { - if ((*input)[0] == '\n') { - *input += static_strlen("\n"); - return; - } - } -} - -static void skip_multiline_comment(char **input) -{ - *input += static_strlen("/*"); - - for (; (*input)[0] != '\0'; ++(*input)) - { - if (((*input)[0] == '*') && ((*input)[1] == '/')) - { - *input += static_strlen("*/"); - return; - } - } -} - -static void minify_string(char **input, char **output) { - (*output)[0] = (*input)[0]; - *input += static_strlen("\""); - *output += static_strlen("\""); - - - for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { - (*output)[0] = (*input)[0]; - - if ((*input)[0] == '\"') { - (*output)[0] = '\"'; - *input += static_strlen("\""); - *output += static_strlen("\""); - return; - } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { - (*output)[1] = (*input)[1]; - *input += static_strlen("\""); - *output += static_strlen("\""); - } - } -} - -CJSON_PUBLIC(void) cJSON_Minify(char *json) -{ - char *into = json; - - if (json == NULL) - { - return; - } - - while (json[0] != '\0') - { - switch (json[0]) - { - case ' ': - case '\t': - case '\r': - case '\n': - json++; - break; - - case '/': - if (json[1] == '/') - { - skip_oneline_comment(&json); - } - else if (json[1] == '*') - { - skip_multiline_comment(&json); - } else { - json++; - } - break; - - case '\"': - minify_string(&json, (char**)&into); - break; - - default: - into[0] = json[0]; - json++; - into++; - } - } - - /* and null-terminate. */ - *into = '\0'; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Invalid; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_False; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xff) == cJSON_True; -} - - -CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & (cJSON_True | cJSON_False)) != 0; -} -CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_NULL; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Number; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_String; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Array; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Object; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Raw; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) -{ - if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) - { - return false; - } - - /* check if type is valid */ - switch (a->type & 0xFF) - { - case cJSON_False: - case cJSON_True: - case cJSON_NULL: - case cJSON_Number: - case cJSON_String: - case cJSON_Raw: - case cJSON_Array: - case cJSON_Object: - break; - - default: - return false; - } - - /* identical objects are equal */ - if (a == b) - { - return true; - } - - switch (a->type & 0xFF) - { - /* in these cases and equal type is enough */ - case cJSON_False: - case cJSON_True: - case cJSON_NULL: - return true; - - case cJSON_Number: - if (compare_double(a->valuedouble, b->valuedouble)) - { - return true; - } - return false; - - case cJSON_String: - case cJSON_Raw: - if ((a->valuestring == NULL) || (b->valuestring == NULL)) - { - return false; - } - if (strcmp(a->valuestring, b->valuestring) == 0) - { - return true; - } - - return false; - - case cJSON_Array: - { - cJSON *a_element = a->child; - cJSON *b_element = b->child; - - for (; (a_element != NULL) && (b_element != NULL);) - { - if (!cJSON_Compare(a_element, b_element, case_sensitive)) - { - return false; - } - - a_element = a_element->next; - b_element = b_element->next; - } - - /* one of the arrays is longer than the other */ - if (a_element != b_element) { - return false; - } - - return true; - } - - case cJSON_Object: - { - cJSON *a_element = NULL; - cJSON *b_element = NULL; - cJSON_ArrayForEach(a_element, a) - { - /* TODO This has O(n^2) runtime, which is horrible! */ - b_element = get_object_item(b, a_element->string, case_sensitive); - if (b_element == NULL) - { - return false; - } - - if (!cJSON_Compare(a_element, b_element, case_sensitive)) - { - return false; - } - } - - /* doing this twice, once on a and b to prevent true comparison if a subset of b - * TODO: Do this the proper way, this is just a fix for now */ - cJSON_ArrayForEach(b_element, b) - { - a_element = get_object_item(a, b_element->string, case_sensitive); - if (a_element == NULL) - { - return false; - } - - if (!cJSON_Compare(b_element, a_element, case_sensitive)) - { - return false; - } - } - - return true; - } - - default: - return false; - } -} - -CJSON_PUBLIC(void *) cJSON_malloc(size_t size) -{ - return global_hooks.allocate(size); -} - -CJSON_PUBLIC(void) cJSON_free(void *object) -{ - global_hooks.deallocate(object); -} diff --git a/cJSON/cJSON.h b/cJSON/cJSON.h deleted file mode 100644 index 92907a2..0000000 --- a/cJSON/cJSON.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - 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 - -/* 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 diff --git a/common.c b/common.c new file mode 100644 index 0000000..2cb772b --- /dev/null +++ b/common.c @@ -0,0 +1,125 @@ +#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); +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..3a35843 --- /dev/null +++ b/common.h @@ -0,0 +1,36 @@ +#ifndef COMMON_H +#define COMMON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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 diff --git a/conf.c b/conf.c index 03a7178..fbeaea8 100644 --- a/conf.c +++ b/conf.c @@ -14,9 +14,7 @@ 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) { @@ -98,12 +96,6 @@ 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); @@ -132,19 +124,7 @@ 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) @@ -178,12 +158,7 @@ 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; @@ -308,12 +283,6 @@ 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) @@ -323,8 +292,6 @@ 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); @@ -345,7 +312,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) @@ -353,12 +320,7 @@ 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) @@ -381,17 +343,3 @@ 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); - } -} diff --git a/conf.h b/conf.h index 6a9595b..1a4ea24 100644 --- a/conf.h +++ b/conf.h @@ -7,8 +7,6 @@ #include #include -#define WHITELIST_IP_NUM 1024 - typedef struct CONF { char *DAEMON; @@ -26,7 +24,6 @@ typedef struct CONF int CLAMAV_ARG_LEN; int IS_BLOCKED; - int REFUSE_NUMBER; // 获取公网IP Url地址 char *PUBLIC_IP; @@ -34,8 +31,6 @@ typedef struct CONF // 地域白名单 int REGION; int IP2REGION; - char *REGION_URL; - int REGION_URL_LEN; char *REGION_LIST; int REGION_LIST_LEN; @@ -65,9 +60,9 @@ typedef struct CONF char *RECV_MAIL; } 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]); +extern void read_conf(char *filename, conf * configure); +extern void free_conf(conf * conf); +extern void ptintf_conf(conf * conf); + #endif diff --git a/disk.h b/disk.h index 5b44cbf..767607d 100644 --- a/disk.h +++ b/disk.h @@ -8,7 +8,8 @@ #include #include "rhost.h" - +#include "common.h" +#include "warning.h" #define INITIAL_SIZE 1024 #define BUFFER_INCREMENT 512 diff --git a/ip.c b/ip.c new file mode 100644 index 0000000..aea41d2 --- /dev/null +++ b/ip.c @@ -0,0 +1,98 @@ +#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; +} \ No newline at end of file diff --git a/ip.h b/ip.h new file mode 100644 index 0000000..1c14e9a --- /dev/null +++ b/ip.h @@ -0,0 +1,22 @@ +#ifndef IP_H +#define IP_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char *GET_PUBLIC_IP(char *URL); + +#endif diff --git a/nginx.c b/nginx.c index f8dc501..4a1aa07 100644 --- a/nginx.c +++ b/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); } -int IP_location(char *string, conf *config) +static int Handle_IP(char *string, conf *config) { char *area = NULL; char *xdb_path = "ip2region.xdb"; @@ -136,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'; - IP_location(read_buf, p); + Handle_IP(read_buf, p); } if (bytes_read == -1 && errno != EAGAIN) { perror("read"); diff --git a/nginx.h b/nginx.h index e9f9be9..40d65c7 100644 --- a/nginx.h +++ b/nginx.h @@ -10,6 +10,7 @@ #include #include "rhost.h" +#include "common.h" #include "libiptc.h" #include "ip2region/ip2region.h" diff --git a/rhost.c b/rhost.c index 3d30615..c2c6caa 100644 --- a/rhost.c +++ b/rhost.c @@ -1,12 +1,14 @@ #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 @@ -48,205 +50,9 @@ 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() { @@ -259,435 +65,6 @@ 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); -} - -// 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); -} - -// 封禁非法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 (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; @@ -700,7 +77,6 @@ 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) @@ -767,13 +143,11 @@ 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; } } @@ -884,7 +258,6 @@ static char help_information(void) int main(int argc, char *argv[], char **env) { - signal(SIGCHLD, sig_child); // 创建捕捉子进程退出信号 int pid; @@ -974,15 +347,15 @@ int main(int argc, char *argv[], char **env) head_argc += 1; } - /* - // 打印clamav参数 - for(int i=0; iDAEMON, "on")) { - goto goto_daemon; + goto DAEMON; } if (argv[1] != NULL && 0 == strcmp(argv[1], "-d")) { -goto_daemon: +DAEMON: // 守护进程 if ((pid = fork()) < 0) { @@ -1036,18 +409,40 @@ goto_daemon: if (-1 == (nice(-20))) perror("nice"); - // 处理Nginx - 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); + 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); + } } } + // 处理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 @@ -1113,28 +508,24 @@ goto_daemon: } _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); + sleep(conf->TIME); } - } else { - ; } + free(t); free_conf(conf); free(conf); diff --git a/rhost.conf b/rhost.conf index 7afeacf..8734e5d 100644 --- a/rhost.conf +++ b/rhost.conf @@ -1,47 +1,37 @@ global { - - DAEMON = "off"; // on开启后台运行,off不开启(弃用) - TIME = "10"; // 睡眠时间(大于等于1,单位秒) - + DAEMON = "off"; // on开启后台运行,off不开启(弃用) + TIME = "1"; // 睡眠时间(大于等于1,单位秒) + PUBLIC_IP = "http://inet-ip.info"; // 获取公网IP - IS_DISK = 1; // 磁盘使用率(1开启,非1关闭) - DISK_USE = 95; // 任意某块磁盘使用率告警(大于等于1) - + DISK_USE = 50; // 任意某块磁盘使用率告警(大于等于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= "/usr/local/nginx/logs/access.log"; // Nginx 日志文件 - NGINX_REGION_LIST = "中国 河南 郑州 上海"; // 地域列表(空格隔开) - - - IS_MAIL = 0; // 开启邮件告警(1开启,非1关闭) - + #NGINX_LOG_FILE= "/var/log/nginx/access.log"; // Nginx 日志文件 + NGINX_LOG_FILE= "/opt/nginx/logs/access.log"; // Nginx 日志文件 + NGINX_REGION_LIST = "中国 河南 郑州 上海 内网"; // 地域列表(空格隔开) 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"; // 接收者邮箱 } diff --git a/rhost.h b/rhost.h index c8e75bc..df4e65d 100644 --- a/rhost.h +++ b/rhost.h @@ -19,7 +19,6 @@ #include "conf.h" - typedef struct now_next_time { int now_year; @@ -40,22 +39,17 @@ 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) @@ -67,18 +61,7 @@ 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 diff --git a/rule.c b/rule.c new file mode 100644 index 0000000..ca8b3e5 --- /dev/null +++ b/rule.c @@ -0,0 +1,147 @@ +#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 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; +} diff --git a/rule.h b/rule.h new file mode 100644 index 0000000..e14a1c3 --- /dev/null +++ b/rule.h @@ -0,0 +1,26 @@ +#ifndef RULE_H +#define RULE_H + +#include +#include +#include +#include +#include +#include +#include + +#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 diff --git a/warning.c b/warning.c new file mode 100644 index 0000000..e9d7e49 --- /dev/null +++ b/warning.c @@ -0,0 +1,136 @@ +#include "warning.h" + +// 钉钉告警 +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); +} diff --git a/warning.h b/warning.h new file mode 100644 index 0000000..dabeee3 --- /dev/null +++ b/warning.h @@ -0,0 +1,32 @@ +#ifndef WARNING_H +#define WARNING_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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