From 84e1ac90f102d1d110bf9dc2d91362c070a509d7 Mon Sep 17 00:00:00 2001 From: Zxilly Date: Thu, 13 Apr 2023 22:21:57 +0800 Subject: [PATCH] refactor: remove ipset --- CMakeLists.txt | 9 +- Makefile | 13 +- README.md | 2 +- files/ua2f.init | 5 +- src/cache.c | 67 +++++ src/cache.h | 8 + src/child.c | 61 ++++ src/child.h | 10 + src/hashmap.h | 718 +++++++++++++++++++++++++++++++++++++++++++++++ src/ipset_hook.h | 21 -- src/rwmutex.h | 51 ++++ src/statistics.c | 33 +-- src/ua2f.c | 114 +------- src/util.c | 29 ++ src/util.h | 8 + 15 files changed, 1000 insertions(+), 149 deletions(-) create mode 100644 src/cache.c create mode 100644 src/cache.h create mode 100644 src/child.c create mode 100644 src/child.h create mode 100644 src/hashmap.h delete mode 100644 src/ipset_hook.h create mode 100644 src/rwmutex.h create mode 100644 src/util.c create mode 100644 src/util.h diff --git a/CMakeLists.txt b/CMakeLists.txt index db288f3..67e16a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,13 @@ include_directories("/usr/local/include") add_compile_options(-fsanitize=address) add_link_options(-fsanitize=address) -add_executable(ua2f src/ua2f.c src/statistics.c) +add_executable(ua2f + src/ua2f.c + src/statistics.c + src/child.c + src/util.c + src/cache.c) -target_link_libraries(ua2f mnl netfilter_queue ipset) +target_link_libraries(ua2f mnl netfilter_queue pthread) install(TARGETS ua2f RUNTIME DESTINATION bin) diff --git a/Makefile b/Makefile index 7f29857..b9645f9 100644 --- a/Makefile +++ b/Makefile @@ -15,19 +15,24 @@ define Package/ua2f SUBMENU:=Routing and Redirection TITLE:=Change User-Agent to Fwords on the fly. URL:=https://github.com/Zxilly/UA2F - DEPENDS:=+ipset +iptables-mod-conntrack-extra +iptables-mod-nfqueue \ - +libnetfilter-conntrack +libnetfilter-queue +iptables-mod-filter +iptables-mod-ipopt + DEPENDS:=+iptables-mod-conntrack-extra +iptables-mod-nfqueue \ + +libnetfilter-conntrack +libnetfilter-queue +iptables-mod-filter endef define Package/ua2f/description Change User-agent to Fwords to prevent being checked by Dr.Com. endef -EXTRA_LDFLAGS += -lmnl -lnetfilter_queue -lipset +EXTRA_LDFLAGS += -lmnl -lnetfilter_queue -lpthread define Build/Compile $(TARGET_CC) $(TARGET_CFLAGS) $(TARGET_LDFLAGS) $(EXTRA_LDFLAGS) \ - $(PKG_BUILD_DIR)/ua2f.c $(PKG_BUILD_DIR)/statistics.c -o $(PKG_BUILD_DIR)/ua2f + $(PKG_BUILD_DIR)/ua2f.c \ + $(PKG_BUILD_DIR)/statistics.c \ + $(PKG_BUILD_DIR)/child.c \ + $(PKG_BUILD_DIR)/util.c \ + $(PKG_BUILD_DIR)/cache.c \ + -o $(PKG_BUILD_DIR)/ua2f endef define Package/ua2f/install diff --git a/README.md b/README.md index 0b1ef36..6753c94 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ Mon Jan 4 13:25:04 2021 syslog.info UA2F[5219]: UA2F has handled 65536 http pac ``` Sat Mar 13 14:26:48 2021 user.notice : Try to start UA2F processor at [24049]. Sat Mar 13 14:26:48 2021 user.notice : UA2F processor start at [24049]. -Sat Mar 13 14:26:48 2021 syslog.notice UA2F[24049]: Pipset inited. +Sat Mar 13 14:26:48 2021 syslog.notice UA2F[24049]: ipset inited. Sat Mar 13 14:26:48 2021 syslog.notice UA2F[24049]: UA2F has inited successful. Sat Mar 13 14:26:51 2021 syslog.info UA2F[24049]: UA2F has handled 8 http, 0 http 1.0, 0 noua http, 58 tcp. Set 0 mark and 0 nohttp mark in 3 seconds Sat Mar 13 14:26:57 2021 syslog.info UA2F[24049]: UA2F has handled 16 http, 0 http 1.0, 1 noua http, 140 tcp. Set 0 mark and 1 nohttp mark in 9 seconds diff --git a/files/ua2f.init b/files/ua2f.init index 39846c7..a610ad7 100755 --- a/files/ua2f.init +++ b/files/ua2f.init @@ -31,7 +31,6 @@ setup_firewall() { config_get_bool handle_intranet "firewall" "handle_intranet" "0" config_get_bool handle_mmtls "firewall" "handle_mmtls" "0" - ipset create nohttp hash:ip,port hashsize 16384 timeout 300 $IPT_M -N ua2f $IPT_M -A ua2f -d 10.0.0.0/8 -j RETURN $IPT_M -A ua2f -d 172.16.0.0/12 -j RETURN @@ -45,7 +44,6 @@ setup_firewall() { [ "$handle_tls" -eq "1" ] || $IPT_M -A ua2f -p tcp --dport 443 -j RETURN # 不处理 HTTPS $IPT_M -A ua2f -p tcp --dport 80 -j CONNMARK --set-mark 44 $IPT_M -A ua2f -m connmark --mark 43 -j RETURN # 不处理标记为非 http 的流 (实验性) - $IPT_M -A ua2f -m set --match-set nohttp dst,dst -j RETURN [ "$handle_mmtls" -eq "1" ] || $IPT_M -A ua2f -p tcp --dport 80 -m string --string "/mmtls/" --algo bm -j RETURN # 不处理微信的mmtls $IPT_M -A ua2f -j NFQUEUE --queue-num 10010 $IPT_M -A FORWARD -p tcp -m conntrack --ctdir ORIGINAL -j ua2f @@ -94,8 +92,7 @@ stop_service() { $IPT_M -D FORWARD -p tcp -m conntrack --ctdir REPLY $IPT_M -F ua2f $IPT_M -X ua2f - ipset flush nohttp - ipset destroy nohttp + echo > "$FW_CONF" ) 2>"/dev/null" } diff --git a/src/cache.c b/src/cache.c new file mode 100644 index 0000000..68c81b2 --- /dev/null +++ b/src/cache.c @@ -0,0 +1,67 @@ +#include "cache.h" +#include "hashmap.h" +#include "rwmutex.h" + +#include +#include +#include +#include + +RWMutex lock; + +const double CACHE_TIMEOUT = 600; + +struct hashmap_s no_http_dst_cache; + +static int iterate_pairs(void *const context, struct hashmap_element_s *const e) { + __auto_type current_time = (time_t) context; + + __auto_type store_time = (time_t) e->data; + + if (difftime(current_time, store_time) > CACHE_TIMEOUT) { + return -1; + } + + return 0; +} + +_Noreturn static void check_cache() { + while (true) { + rw_mutex_write_lock(&lock); + + __auto_type current_time = time(NULL); + + hashmap_iterate_pairs(&no_http_dst_cache, iterate_pairs, (void *) current_time); + + rw_mutex_read_unlock(&lock); + + // wait for 1 minute + thrd_sleep(&(struct timespec) {60, 0}, NULL); + } +} + +void init_cache() { + rw_mutex_init(&lock); + hashmap_create(1024, &no_http_dst_cache); + + pthread_t cleanup_thread; + __auto_type ret = pthread_create(&cleanup_thread, NULL, (void *(*)(void *)) check_cache, NULL); + if (ret) { + syslog(LOG_ERR, "Failed to create cleanup thread: %d", ret); + exit(EXIT_FAILURE); + } +} + +bool check_addr_port(const char *addr_port, const int len) { + rw_mutex_read_lock(&lock); + __auto_type ret = hashmap_get(&no_http_dst_cache, addr_port, len) != NULL; + rw_mutex_read_unlock(&lock); + + rw_mutex_write_lock(&lock); + if (ret) { + hashmap_put(&no_http_dst_cache, addr_port, len, (void *) time(NULL)); + } + rw_mutex_write_unlock(&lock); + + return ret; +} \ No newline at end of file diff --git a/src/cache.h b/src/cache.h new file mode 100644 index 0000000..f85b036 --- /dev/null +++ b/src/cache.h @@ -0,0 +1,8 @@ +// +// Created by zxilly on 2023/4/13. +// + +#ifndef UA2F_CACHE_H +#define UA2F_CACHE_H + +#endif //UA2F_CACHE_H diff --git a/src/child.c b/src/child.c new file mode 100644 index 0000000..f2a0843 --- /dev/null +++ b/src/child.c @@ -0,0 +1,61 @@ +#include "child.h" + +#include +#include +#include +#include +#include + +static __pid_t child_pid = 0; +static u_int8_t failure_count = 0; + +const u_int8_t MAX_RETRY_COUNT = 8; + +static volatile sig_atomic_t graceful_exit_requested = false; + +void parent_sigterm_handler(int signum) { + graceful_exit_requested = true; +} + +void child_sigterm_handler(int signum) { + syslog(LOG_NOTICE, "Received SIGTERM, gracefully exiting."); + exit(EXIT_SUCCESS); +} + +void works_as_child() { + while (!graceful_exit_requested) { + if (failure_count++ > MAX_RETRY_COUNT) { + syslog(LOG_ERR, "UA2F processor failed to start after [%d] times.", MAX_RETRY_COUNT); + exit(EXIT_FAILURE); + } + + child_pid = fork(); + if (child_pid < 0) { + syslog(LOG_ERR, "Failed to fork child process"); + exit(EXIT_FAILURE); + } + + if (child_pid == 0) { + syslog(LOG_NOTICE, "UA2F processor start at [%d].", getpid()); + signal(SIGTERM, child_sigterm_handler); + return; + } + + signal(SIGTERM, parent_sigterm_handler); + + syslog(LOG_NOTICE, "Try to start UA2F processor at [%d].", child_pid); + + int exit_stat; + waitpid(child_pid, &exit_stat, 0); + + if (WIFEXITED(exit_stat)) { + syslog(LOG_NOTICE, "UA2F processor at [%d] exit with code [%d].", child_pid, WEXITSTATUS(exit_stat)); + if (WEXITSTATUS(exit_stat) == 0) { + exit(EXIT_SUCCESS); + } + } + } + + syslog(LOG_NOTICE, "Received SIGTERM, gracefully exited."); + exit(EXIT_SUCCESS); +} diff --git a/src/child.h b/src/child.h new file mode 100644 index 0000000..1095d94 --- /dev/null +++ b/src/child.h @@ -0,0 +1,10 @@ +// +// Created by zxilly on 2023/4/13. +// + +#ifndef UA2F_CHILD_H +#define UA2F_CHILD_H + +void works_as_child(); + +#endif //UA2F_CHILD_H diff --git a/src/hashmap.h b/src/hashmap.h new file mode 100644 index 0000000..e424e3e --- /dev/null +++ b/src/hashmap.h @@ -0,0 +1,718 @@ +/* + The latest version of this library is available on GitHub; + https://github.com/sheredom/hashmap.h +*/ + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + 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 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. + + For more information, please refer to +*/ +#ifndef SHEREDOM_HASHMAP_H_INCLUDED +#define SHEREDOM_HASHMAP_H_INCLUDED + +#if defined(_MSC_VER) +// Workaround a bug in the MSVC runtime where it uses __cplusplus when not +// defined. +#pragma warning(push, 0) +#pragma warning(disable : 4668) +#endif + +#include +#include + +#if (defined(_MSC_VER) && defined(__AVX__)) || \ + (!defined(_MSC_VER) && defined(__SSE4_2__)) +#define HASHMAP_X86_SSE42 +#endif + +#if defined(HASHMAP_X86_SSE42) +#include +#endif + +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) +#define HASHMAP_ARM_CRC32 +#endif + +#if defined(HASHMAP_ARM_CRC32) +#include +#endif + +#if defined(_MSC_VER) +#include +#endif + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(_MSC_VER) +#pragma warning(push) +/* Stop MSVC complaining about unreferenced functions */ +#pragma warning(disable : 4505) +/* Stop MSVC complaining about not inlining functions */ +#pragma warning(disable : 4710) +/* Stop MSVC complaining about inlining functions! */ +#pragma warning(disable : 4711) +#endif + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wstatic-in-inline" +#endif + +#if defined(_MSC_VER) +#define HASHMAP_WEAK __inline +#elif defined(__clang__) || defined(__GNUC__) +#define HASHMAP_WEAK __attribute__((weak)) +#else +#error Non clang, non gcc, non MSVC compiler found! +#endif + +#if defined(_MSC_VER) +#define HASHMAP_ALWAYS_INLINE __forceinline +#elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__cplusplus) +#define HASHMAP_ALWAYS_INLINE __attribute__((always_inline)) inline +#else +/* If we cannot use inline, its not safe to use always_inline, so we mark the + * function weak. */ +#define HASHMAP_ALWAYS_INLINE HASHMAP_WEAK +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1920) +typedef unsigned __int8 hashmap_uint8_t; +typedef unsigned __int32 hashmap_uint32_t; +typedef unsigned __int64 hashmap_uint64_t; +#else +#include +typedef uint8_t hashmap_uint8_t; +typedef uint32_t hashmap_uint32_t; +typedef uint64_t hashmap_uint64_t; +#endif + +typedef struct hashmap_element_s { + const void *key; + hashmap_uint32_t key_len; + int in_use; + void *data; +} hashmap_element_t; + +typedef hashmap_uint32_t (*hashmap_hasher_t)(hashmap_uint32_t seed, + const void *key, + hashmap_uint32_t key_len); +typedef int (*hashmap_comparer_t)(const void *a, hashmap_uint32_t a_len, + const void *b, hashmap_uint32_t b_len); + +typedef struct hashmap_s { + hashmap_uint32_t log2_capacity; + hashmap_uint32_t size; + hashmap_hasher_t hasher; + hashmap_comparer_t comparer; + struct hashmap_element_s *data; +} hashmap_t; + +#define HASHMAP_LINEAR_PROBE_LENGTH (8) + +typedef struct hashmap_create_options_s { + hashmap_hasher_t hasher; + hashmap_comparer_t comparer; + hashmap_uint32_t initial_capacity; + hashmap_uint32_t _; +} hashmap_create_options_t; + +#if defined(__cplusplus) +extern "C" { +#endif + +/// @brief Create a hashmap. +/// @param initial_capacity The initial capacity of the hashmap. +/// @param out_hashmap The storage for the created hashmap. +/// @return On success 0 is returned. +HASHMAP_WEAK int hashmap_create(const hashmap_uint32_t initial_capacity, + struct hashmap_s *const out_hashmap); + +/// @brief Create a hashmap. +/// @param options The options to create the hashmap with. +/// @param out_hashmap The storage for the created hashmap. +/// @return On success 0 is returned. +/// +/// The options members work as follows: +/// - initial_capacity The initial capacity of the hashmap. +/// - hasher Which hashing function to use with the hashmap (by default the +// crc32 with Robert Jenkins' mix is used). +HASHMAP_WEAK int hashmap_create_ex(struct hashmap_create_options_s options, + struct hashmap_s *const out_hashmap); + +/// @brief Put an element into the hashmap. +/// @param hashmap The hashmap to insert into. +/// @param key The string key to use. +/// @param len The length of the string key. +/// @param value The value to insert. +/// @return On success 0 is returned. +/// +/// The key string slice is not copied when creating the hashmap entry, and thus +/// must remain a valid pointer until the hashmap entry is removed or the +/// hashmap is destroyed. +HASHMAP_WEAK int hashmap_put(struct hashmap_s *const hashmap, + const void *const key, const hashmap_uint32_t len, + void *const value); + +/// @brief Get an element from the hashmap. +/// @param hashmap The hashmap to get from. +/// @param key The string key to use. +/// @param len The length of the string key. +/// @return The previously set element, or NULL if none exists. +HASHMAP_WEAK void *hashmap_get(const struct hashmap_s *const hashmap, + const void *const key, + const hashmap_uint32_t len); + +/// @brief Remove an element from the hashmap. +/// @param hashmap The hashmap to remove from. +/// @param key The string key to use. +/// @param len The length of the string key. +/// @return On success 0 is returned. +HASHMAP_WEAK int hashmap_remove(struct hashmap_s *const hashmap, + const void *const key, + const hashmap_uint32_t len); + +/// @brief Remove an element from the hashmap. +/// @param hashmap The hashmap to remove from. +/// @param key The string key to use. +/// @param len The length of the string key. +/// @return On success the original stored key pointer is returned, on failure +/// NULL is returned. +HASHMAP_WEAK const void * +hashmap_remove_and_return_key(struct hashmap_s *const hashmap, + const void *const key, + const hashmap_uint32_t len); + +/// @brief Iterate over all the elements in a hashmap. +/// @param hashmap The hashmap to iterate over. +/// @param iterator The function pointer to call on each element. +/// @param context The context to pass as the first argument to f. +/// @return If the entire hashmap was iterated then 0 is returned. Otherwise if +/// the callback function f returned non-zero then non-zero is returned. +HASHMAP_WEAK int hashmap_iterate(const struct hashmap_s *const hashmap, + int (*iterator)(void *const context, + void *const value), + void *const context); + +/// @brief Iterate over all the elements in a hashmap. +/// @param hashmap The hashmap to iterate over. +/// @param iterator The function pointer to call on each element. +/// @param context The context to pass as the first argument to f. +/// @return If the entire hashmap was iterated then 0 is returned. +/// Otherwise if the callback function f returned positive then the positive +/// value is returned. If the callback function returns -1, the current item +/// is removed and iteration continues. +HASHMAP_WEAK int hashmap_iterate_pairs( + struct hashmap_s *const hashmap, + int (*iterator)(void *const, struct hashmap_element_s *const), + void *const context); + +/// @brief Get the size of the hashmap. +/// @param hashmap The hashmap to get the size of. +/// @return The size of the hashmap. +HASHMAP_ALWAYS_INLINE hashmap_uint32_t +hashmap_num_entries(const struct hashmap_s *const hashmap); + +/// @brief Get the capacity of the hashmap. +/// @param hashmap The hashmap to get the size of. +/// @return The capacity of the hashmap. +HASHMAP_ALWAYS_INLINE hashmap_uint32_t +hashmap_capacity(const struct hashmap_s *const hashmap); + +/// @brief Destroy the hashmap. +/// @param hashmap The hashmap to destroy. +HASHMAP_WEAK void hashmap_destroy(struct hashmap_s *const hashmap); + +static hashmap_uint32_t hashmap_crc32_hasher(const hashmap_uint32_t seed, + const void *const s, + const hashmap_uint32_t len); +static int hashmap_memcmp_comparer(const void *const a, + const hashmap_uint32_t a_len, + const void *const b, + const hashmap_uint32_t b_len); +HASHMAP_ALWAYS_INLINE hashmap_uint32_t hashmap_hash_helper_int_helper( + const struct hashmap_s *const m, const void *const key, + const hashmap_uint32_t len); +HASHMAP_ALWAYS_INLINE int +hashmap_hash_helper(const struct hashmap_s *const m, const void *const key, + const hashmap_uint32_t len, + hashmap_uint32_t *const out_index); +HASHMAP_WEAK int hashmap_rehash_iterator(void *const new_hash, + struct hashmap_element_s *const e); +HASHMAP_ALWAYS_INLINE int hashmap_rehash_helper(struct hashmap_s *const m); +HASHMAP_ALWAYS_INLINE hashmap_uint32_t hashmap_clz(const hashmap_uint32_t x); + +#if defined(__cplusplus) +} +#endif + +#if defined(__cplusplus) +#define HASHMAP_CAST(type, x) static_cast(x) +#define HASHMAP_PTR_CAST(type, x) reinterpret_cast(x) +#define HASHMAP_NULL NULL +#else +#define HASHMAP_CAST(type, x) ((type)(x)) +#define HASHMAP_PTR_CAST(type, x) ((type)(x)) +#define HASHMAP_NULL 0 +#endif + +int hashmap_create(const hashmap_uint32_t initial_capacity, + struct hashmap_s *const out_hashmap) { + struct hashmap_create_options_s options; + memset(&options, 0, sizeof(options)); + options.initial_capacity = initial_capacity; + + return hashmap_create_ex(options, out_hashmap); +} + +int hashmap_create_ex(struct hashmap_create_options_s options, + struct hashmap_s *const out_hashmap) { + if (2 > options.initial_capacity) { + options.initial_capacity = 2; + } else if (0 != (options.initial_capacity & (options.initial_capacity - 1))) { + options.initial_capacity = 1u + << (32 - hashmap_clz(options.initial_capacity)); + } + + if (HASHMAP_NULL == options.hasher) { + options.hasher = &hashmap_crc32_hasher; + } + + if (HASHMAP_NULL == options.comparer) { + options.comparer = &hashmap_memcmp_comparer; + } + + out_hashmap->data = HASHMAP_CAST( + struct hashmap_element_s *, + calloc(options.initial_capacity + HASHMAP_LINEAR_PROBE_LENGTH, + sizeof(struct hashmap_element_s))); + + out_hashmap->log2_capacity = 31 - hashmap_clz(options.initial_capacity); + out_hashmap->size = 0; + out_hashmap->hasher = options.hasher; + out_hashmap->comparer = options.comparer; + + return 0; +} + +int hashmap_put(struct hashmap_s *const m, const void *const key, + const hashmap_uint32_t len, void *const value) { + hashmap_uint32_t index; + + if ((HASHMAP_NULL == key) || (0 == len)) { + return 1; + } + + /* Find a place to put our value. */ + while (!hashmap_hash_helper(m, key, len, &index)) { + if (hashmap_rehash_helper(m)) { + return 1; + } + } + + /* Set the data. */ + m->data[index].data = value; + m->data[index].key = key; + m->data[index].key_len = len; + + /* If the hashmap element was not already in use, set that it is being used + * and bump our size. */ + if (0 == m->data[index].in_use) { + m->data[index].in_use = 1; + m->size++; + } + + return 0; +} + +void *hashmap_get(const struct hashmap_s *const m, const void *const key, + const hashmap_uint32_t len) { + hashmap_uint32_t i, curr; + + if ((HASHMAP_NULL == key) || (0 == len)) { + return HASHMAP_NULL; + } + + curr = hashmap_hash_helper_int_helper(m, key, len); + + /* Linear probing, if necessary */ + for (i = 0; i < HASHMAP_LINEAR_PROBE_LENGTH; i++) { + const hashmap_uint32_t index = curr + i; + + if (m->data[index].in_use) { + if (m->comparer(m->data[index].key, m->data[index].key_len, key, len)) { + return m->data[index].data; + } + } + } + + /* Not found */ + return HASHMAP_NULL; +} + +int hashmap_remove(struct hashmap_s *const m, const void *const key, + const hashmap_uint32_t len) { + hashmap_uint32_t i, curr; + + if ((HASHMAP_NULL == key) || (0 == len)) { + return 1; + } + + curr = hashmap_hash_helper_int_helper(m, key, len); + + /* Linear probing, if necessary */ + for (i = 0; i < HASHMAP_LINEAR_PROBE_LENGTH; i++) { + const hashmap_uint32_t index = curr + i; + + if (m->data[index].in_use) { + if (m->comparer(m->data[index].key, m->data[index].key_len, key, len)) { + /* Blank out the fields including in_use */ + memset(&m->data[index], 0, sizeof(struct hashmap_element_s)); + + /* Reduce the size */ + m->size--; + + return 0; + } + } + } + + return 1; +} + +const void *hashmap_remove_and_return_key(struct hashmap_s *const m, + const void *const key, + const hashmap_uint32_t len) { + hashmap_uint32_t i, curr; + + if ((HASHMAP_NULL == key) || (0 == len)) { + return HASHMAP_NULL; + } + + curr = hashmap_hash_helper_int_helper(m, key, len); + + /* Linear probing, if necessary */ + for (i = 0; i < HASHMAP_LINEAR_PROBE_LENGTH; i++) { + const hashmap_uint32_t index = curr + i; + + if (m->data[index].in_use) { + if (m->comparer(m->data[index].key, m->data[index].key_len, key, len)) { + const void *const stored_key = m->data[index].key; + + /* Blank out the fields */ + memset(&m->data[index], 0, sizeof(struct hashmap_element_s)); + + /* Reduce the size */ + m->size--; + + return stored_key; + } + } + } + + return HASHMAP_NULL; +} + +int hashmap_iterate(const struct hashmap_s *const m, + int (*f)(void *const, void *const), void *const context) { + hashmap_uint32_t i; + + for (i = 0; i < (hashmap_capacity(m) + HASHMAP_LINEAR_PROBE_LENGTH); i++) { + if (m->data[i].in_use) { + if (!f(context, m->data[i].data)) { + return 1; + } + } + } + + return 0; +} + +int hashmap_iterate_pairs(struct hashmap_s *const m, + int (*f)(void *const, + struct hashmap_element_s *const), + void *const context) { + hashmap_uint32_t i; + struct hashmap_element_s *p; + int r; + + for (i = 0; i < (hashmap_capacity(m) + HASHMAP_LINEAR_PROBE_LENGTH); i++) { + p = &m->data[i]; + if (p->in_use) { + r = f(context, p); + switch (r) { + case -1: /* remove item */ + memset(p, 0, sizeof(struct hashmap_element_s)); + m->size--; + break; + case 0: /* continue iterating */ + break; + default: /* early exit */ + return 1; + } + } + } + return 0; +} + +void hashmap_destroy(struct hashmap_s *const m) { + free(m->data); + memset(m, 0, sizeof(struct hashmap_s)); +} + +HASHMAP_ALWAYS_INLINE hashmap_uint32_t +hashmap_num_entries(const struct hashmap_s *const m) { + return m->size; +} + +HASHMAP_ALWAYS_INLINE hashmap_uint32_t +hashmap_capacity(const struct hashmap_s *const m) { + return 1u << m->log2_capacity; +} + +hashmap_uint32_t hashmap_crc32_hasher(const hashmap_uint32_t seed, + const void *const k, + const hashmap_uint32_t len) { + hashmap_uint32_t i = 0; + hashmap_uint32_t crc32val = seed; + const hashmap_uint8_t *const s = HASHMAP_PTR_CAST(const hashmap_uint8_t *, k); + +#if defined(HASHMAP_X86_SSE42) + for (; (i + sizeof(hashmap_uint32_t)) < len; i += sizeof(hashmap_uint32_t)) { + hashmap_uint32_t next; + memcpy(&next, &s[i], sizeof(next)); + crc32val = _mm_crc32_u32(crc32val, next); + } + + for (; i < len; i++) { + crc32val = _mm_crc32_u8(crc32val, s[i]); + } +#elif defined(HASHMAP_ARM_CRC32) + for (; (i + sizeof(hashmap_uint64_t)) < len; i += sizeof(hashmap_uint64_t)) { + hashmap_uint64_t next; + memcpy(&next, &s[i], sizeof(next)); + crc32val = __crc32d(crc32val, next); + } + + for (; i < len; i++) { + crc32val = __crc32b(crc32val, s[i]); + } +#else + // Using polynomial 0x11EDC6F41 to match SSE 4.2's crc function. + static const hashmap_uint32_t crc32_tab[] = { + 0x00000000U, 0xF26B8303U, 0xE13B70F7U, 0x1350F3F4U, 0xC79A971FU, + 0x35F1141CU, 0x26A1E7E8U, 0xD4CA64EBU, 0x8AD958CFU, 0x78B2DBCCU, + 0x6BE22838U, 0x9989AB3BU, 0x4D43CFD0U, 0xBF284CD3U, 0xAC78BF27U, + 0x5E133C24U, 0x105EC76FU, 0xE235446CU, 0xF165B798U, 0x030E349BU, + 0xD7C45070U, 0x25AFD373U, 0x36FF2087U, 0xC494A384U, 0x9A879FA0U, + 0x68EC1CA3U, 0x7BBCEF57U, 0x89D76C54U, 0x5D1D08BFU, 0xAF768BBCU, + 0xBC267848U, 0x4E4DFB4BU, 0x20BD8EDEU, 0xD2D60DDDU, 0xC186FE29U, + 0x33ED7D2AU, 0xE72719C1U, 0x154C9AC2U, 0x061C6936U, 0xF477EA35U, + 0xAA64D611U, 0x580F5512U, 0x4B5FA6E6U, 0xB93425E5U, 0x6DFE410EU, + 0x9F95C20DU, 0x8CC531F9U, 0x7EAEB2FAU, 0x30E349B1U, 0xC288CAB2U, + 0xD1D83946U, 0x23B3BA45U, 0xF779DEAEU, 0x05125DADU, 0x1642AE59U, + 0xE4292D5AU, 0xBA3A117EU, 0x4851927DU, 0x5B016189U, 0xA96AE28AU, + 0x7DA08661U, 0x8FCB0562U, 0x9C9BF696U, 0x6EF07595U, 0x417B1DBCU, + 0xB3109EBFU, 0xA0406D4BU, 0x522BEE48U, 0x86E18AA3U, 0x748A09A0U, + 0x67DAFA54U, 0x95B17957U, 0xCBA24573U, 0x39C9C670U, 0x2A993584U, + 0xD8F2B687U, 0x0C38D26CU, 0xFE53516FU, 0xED03A29BU, 0x1F682198U, + 0x5125DAD3U, 0xA34E59D0U, 0xB01EAA24U, 0x42752927U, 0x96BF4DCCU, + 0x64D4CECFU, 0x77843D3BU, 0x85EFBE38U, 0xDBFC821CU, 0x2997011FU, + 0x3AC7F2EBU, 0xC8AC71E8U, 0x1C661503U, 0xEE0D9600U, 0xFD5D65F4U, + 0x0F36E6F7U, 0x61C69362U, 0x93AD1061U, 0x80FDE395U, 0x72966096U, + 0xA65C047DU, 0x5437877EU, 0x4767748AU, 0xB50CF789U, 0xEB1FCBADU, + 0x197448AEU, 0x0A24BB5AU, 0xF84F3859U, 0x2C855CB2U, 0xDEEEDFB1U, + 0xCDBE2C45U, 0x3FD5AF46U, 0x7198540DU, 0x83F3D70EU, 0x90A324FAU, + 0x62C8A7F9U, 0xB602C312U, 0x44694011U, 0x5739B3E5U, 0xA55230E6U, + 0xFB410CC2U, 0x092A8FC1U, 0x1A7A7C35U, 0xE811FF36U, 0x3CDB9BDDU, + 0xCEB018DEU, 0xDDE0EB2AU, 0x2F8B6829U, 0x82F63B78U, 0x709DB87BU, + 0x63CD4B8FU, 0x91A6C88CU, 0x456CAC67U, 0xB7072F64U, 0xA457DC90U, + 0x563C5F93U, 0x082F63B7U, 0xFA44E0B4U, 0xE9141340U, 0x1B7F9043U, + 0xCFB5F4A8U, 0x3DDE77ABU, 0x2E8E845FU, 0xDCE5075CU, 0x92A8FC17U, + 0x60C37F14U, 0x73938CE0U, 0x81F80FE3U, 0x55326B08U, 0xA759E80BU, + 0xB4091BFFU, 0x466298FCU, 0x1871A4D8U, 0xEA1A27DBU, 0xF94AD42FU, + 0x0B21572CU, 0xDFEB33C7U, 0x2D80B0C4U, 0x3ED04330U, 0xCCBBC033U, + 0xA24BB5A6U, 0x502036A5U, 0x4370C551U, 0xB11B4652U, 0x65D122B9U, + 0x97BAA1BAU, 0x84EA524EU, 0x7681D14DU, 0x2892ED69U, 0xDAF96E6AU, + 0xC9A99D9EU, 0x3BC21E9DU, 0xEF087A76U, 0x1D63F975U, 0x0E330A81U, + 0xFC588982U, 0xB21572C9U, 0x407EF1CAU, 0x532E023EU, 0xA145813DU, + 0x758FE5D6U, 0x87E466D5U, 0x94B49521U, 0x66DF1622U, 0x38CC2A06U, + 0xCAA7A905U, 0xD9F75AF1U, 0x2B9CD9F2U, 0xFF56BD19U, 0x0D3D3E1AU, + 0x1E6DCDEEU, 0xEC064EEDU, 0xC38D26C4U, 0x31E6A5C7U, 0x22B65633U, + 0xD0DDD530U, 0x0417B1DBU, 0xF67C32D8U, 0xE52CC12CU, 0x1747422FU, + 0x49547E0BU, 0xBB3FFD08U, 0xA86F0EFCU, 0x5A048DFFU, 0x8ECEE914U, + 0x7CA56A17U, 0x6FF599E3U, 0x9D9E1AE0U, 0xD3D3E1ABU, 0x21B862A8U, + 0x32E8915CU, 0xC083125FU, 0x144976B4U, 0xE622F5B7U, 0xF5720643U, + 0x07198540U, 0x590AB964U, 0xAB613A67U, 0xB831C993U, 0x4A5A4A90U, + 0x9E902E7BU, 0x6CFBAD78U, 0x7FAB5E8CU, 0x8DC0DD8FU, 0xE330A81AU, + 0x115B2B19U, 0x020BD8EDU, 0xF0605BEEU, 0x24AA3F05U, 0xD6C1BC06U, + 0xC5914FF2U, 0x37FACCF1U, 0x69E9F0D5U, 0x9B8273D6U, 0x88D28022U, + 0x7AB90321U, 0xAE7367CAU, 0x5C18E4C9U, 0x4F48173DU, 0xBD23943EU, + 0xF36E6F75U, 0x0105EC76U, 0x12551F82U, 0xE03E9C81U, 0x34F4F86AU, + 0xC69F7B69U, 0xD5CF889DU, 0x27A40B9EU, 0x79B737BAU, 0x8BDCB4B9U, + 0x988C474DU, 0x6AE7C44EU, 0xBE2DA0A5U, 0x4C4623A6U, 0x5F16D052U, + 0xAD7D5351U}; + + for (; i < len; i++) { + crc32val = crc32_tab[(HASHMAP_CAST(hashmap_uint8_t, crc32val) ^ s[i])] ^ + (crc32val >> 8); + } +#endif + + // Use the mix function from murmur3. + crc32val ^= len; + + crc32val ^= crc32val >> 16; + crc32val *= 0x85ebca6b; + crc32val ^= crc32val >> 13; + crc32val *= 0xc2b2ae35; + crc32val ^= crc32val >> 16; + + return crc32val; +} + +int hashmap_memcmp_comparer(const void *const a, const hashmap_uint32_t a_len, + const void *const b, const hashmap_uint32_t b_len) { + return (a_len == b_len) && (0 == memcmp(a, b, a_len)); +} + +HASHMAP_ALWAYS_INLINE hashmap_uint32_t +hashmap_hash_helper_int_helper(const struct hashmap_s *const m, + const void *const k, const hashmap_uint32_t l) { + return (m->hasher(~0u, k, l) * 2654435769u) >> (32u - m->log2_capacity); +} + +HASHMAP_ALWAYS_INLINE int +hashmap_hash_helper(const struct hashmap_s *const m, const void *const key, + const hashmap_uint32_t len, + hashmap_uint32_t *const out_index) { + hashmap_uint32_t curr; + hashmap_uint32_t i; + hashmap_uint32_t first_free; + + /* If full, return immediately */ + if (hashmap_num_entries(m) == hashmap_capacity(m)) { + return 0; + } + + /* Find the best index */ + curr = hashmap_hash_helper_int_helper(m, key, len); + first_free = ~0u; + + for (i = 0; i < HASHMAP_LINEAR_PROBE_LENGTH; i++) { + const hashmap_uint32_t index = curr + i; + + if (!m->data[index].in_use) { + first_free = (first_free < index) ? first_free : index; + } else if (m->comparer(m->data[index].key, m->data[index].key_len, key, + len)) { + *out_index = index; + return 1; + } + } + + // Couldn't find a free element in the linear probe. + if (~0u == first_free) { + return 0; + } + + *out_index = first_free; + return 1; +} + +int hashmap_rehash_iterator(void *const new_hash, + struct hashmap_element_s *const e) { + int temp = hashmap_put(HASHMAP_PTR_CAST(struct hashmap_s *, new_hash), e->key, + e->key_len, e->data); + + if (0 < temp) { + return 1; + } + + /* clear old value to avoid stale pointers */ + return -1; +} + +/* + * Doubles the size of the hashmap, and rehashes all the elements + */ +HASHMAP_ALWAYS_INLINE int hashmap_rehash_helper(struct hashmap_s *const m) { + struct hashmap_create_options_s options; + struct hashmap_s new_m; + int flag; + + memset(&options, 0, sizeof(options)); + options.initial_capacity = hashmap_capacity(m) * 2; + options.hasher = m->hasher; + + if (0 == options.initial_capacity) { + return 1; + } + + flag = hashmap_create_ex(options, &new_m); + + if (0 != flag) { + return flag; + } + + /* copy the old elements to the new table */ + flag = hashmap_iterate_pairs(m, hashmap_rehash_iterator, + HASHMAP_PTR_CAST(void *, &new_m)); + + if (0 != flag) { + return flag; + } + + hashmap_destroy(m); + + /* put new hash into old hash structure by copying */ + memcpy(m, &new_m, sizeof(struct hashmap_s)); + + return 0; +} + +HASHMAP_ALWAYS_INLINE hashmap_uint32_t hashmap_clz(const hashmap_uint32_t x) { +#if defined(_MSC_VER) + unsigned long result; + _BitScanReverse(&result, x); + return 31 - HASHMAP_CAST(hashmap_uint32_t, result); +#else + return HASHMAP_CAST(hashmap_uint32_t, __builtin_clz(x)); +#endif +} + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +#endif \ No newline at end of file diff --git a/src/ipset_hook.h b/src/ipset_hook.h deleted file mode 100644 index 61018e2..0000000 --- a/src/ipset_hook.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// Created by 12009 on 2021/1/12. -// -#include - -#ifndef UA2F_IPSET_HOOK_H -#define UA2F_IPSET_HOOK_H - -int func(struct ipset *ipset, void *p, int status, const char *msg, ...) { - return 0; -} - -int func2(struct ipset *ipset, void *p) { - return 0; -} - -int func3(struct ipset_session *session, void *p, const char *fmt, ...) { - return 0; -} - -#endif //UA2F_IPSET_HOOK_H diff --git a/src/rwmutex.h b/src/rwmutex.h new file mode 100644 index 0000000..2839d80 --- /dev/null +++ b/src/rwmutex.h @@ -0,0 +1,51 @@ +#ifndef UA2F_RWMUTEX_H +#define UA2F_RWMUTEX_H + +#include +#include +#include + +typedef struct { + mtx_t write_mtx; + mtx_t read_mtx; + atomic_int read_counter; +} RWMutex; + +void rw_mutex_init(RWMutex *rw_mutex) { + mtx_init(&rw_mutex->write_mtx, mtx_plain); + mtx_init(&rw_mutex->read_mtx, mtx_plain); + rw_mutex->read_counter = ATOMIC_VAR_INIT(0); +} + +void rw_mutex_destroy(RWMutex *rw_mutex) { + mtx_destroy(&rw_mutex->write_mtx); + mtx_destroy(&rw_mutex->read_mtx); +} + +void rw_mutex_read_lock(RWMutex *rw_mutex) { + mtx_lock(&rw_mutex->read_mtx); + __auto_type read_count = atomic_fetch_add(&rw_mutex->read_counter, 1); + if (read_count == 0) { + mtx_lock(&rw_mutex->write_mtx); + } + mtx_unlock(&rw_mutex->read_mtx); +} + +void rw_mutex_read_unlock(RWMutex *rw_mutex) { + mtx_lock(&rw_mutex->read_mtx); + __auto_type read_count = atomic_fetch_sub(&rw_mutex->read_counter, 1); + if (read_count == 1) { + mtx_unlock(&rw_mutex->write_mtx); + } + mtx_unlock(&rw_mutex->read_mtx); +} + +void rw_mutex_write_lock(RWMutex *rw_mutex) { + mtx_lock(&rw_mutex->write_mtx); +} + +void rw_mutex_write_unlock(RWMutex *rw_mutex) { + mtx_unlock(&rw_mutex->write_mtx); +} + +#endif //UA2F_RWMUTEX_H diff --git a/src/statistics.c b/src/statistics.c index 50f04ad..c7a3dc9 100644 --- a/src/statistics.c +++ b/src/statistics.c @@ -8,7 +8,7 @@ static long long UserAgentPacketCount = 0; static long long TcpPacketCount = 0; static long long PacketWithUserAgentMark = 0; static long long PacketWithoutUserAgentMark = 0; -static long long HttpPacketCount = 4; +static long long LastReportCount = 4; static time_t start_t; @@ -32,36 +32,33 @@ void count_packet_without_user_agent_mark() { PacketWithoutUserAgentMark++; } -void count_http_packet() { - HttpPacketCount++; -} - static char TimeStringBuffer[60]; -char *fill_time_string(int sec) { +char *fill_time_string(double sec) { + int s = (int) sec; memset(TimeStringBuffer, 0, sizeof(TimeStringBuffer)); - if (sec <= 60) { - sprintf(TimeStringBuffer, "%d seconds", sec); - } else if (sec <= 3600) { - sprintf(TimeStringBuffer, "%d minutes and %d seconds", sec / 60, sec % 60); - } else if (sec <= 86400) { - sprintf(TimeStringBuffer, "%d hours, %d minutes and %d seconds", sec / 3600, sec % 3600 / 60, sec % 60); + if (s <= 60) { + sprintf(TimeStringBuffer, "%d seconds", s); + } else if (s <= 3600) { + sprintf(TimeStringBuffer, "%d minutes and %d seconds", s / 60, s % 60); + } else if (s <= 86400) { + sprintf(TimeStringBuffer, "%d hours, %d minutes and %d seconds", s / 3600, s % 3600 / 60, s % 60); } else { - sprintf(TimeStringBuffer, "%d days, %d hours, %d minutes and %d seconds", sec / 86400, sec % 86400 / 3600, - sec % 3600 / 60, - sec % 60); + sprintf(TimeStringBuffer, "%d days, %d hours, %d minutes and %d seconds", s / 86400, s % 86400 / 3600, + s % 3600 / 60, + s % 60); } return TimeStringBuffer; } void try_print_statistics() { - if (UserAgentPacketCount / HttpPacketCount == 2 || UserAgentPacketCount - HttpPacketCount >= 8192) { - HttpPacketCount = UserAgentPacketCount; + if (UserAgentPacketCount / LastReportCount == 2 || UserAgentPacketCount - LastReportCount >= 16384) { + LastReportCount = UserAgentPacketCount; time_t current_t = time(NULL); syslog(LOG_INFO, "UA2F has handled %lld ua http, %lld tcp. Set %lld mark and %lld noUA mark in %s", UserAgentPacketCount, TcpPacketCount, PacketWithUserAgentMark, PacketWithoutUserAgentMark, - fill_time_string((int) difftime(current_t, start_t))); + fill_time_string(difftime(current_t, start_t))); } } diff --git a/src/ua2f.c b/src/ua2f.c index d8dbc8a..847ff0b 100644 --- a/src/ua2f.c +++ b/src/ua2f.c @@ -1,5 +1,6 @@ -#include "ipset_hook.h" #include "statistics.h" +#include "util.h" +#include "child.h" #include #include @@ -13,52 +14,20 @@ #include -#include - #include +#include +#include #include #include #include #include -#include #define NF_ACCEPT 1 -int child_status; - static struct mnl_socket *nl; -static const int queue_number = 10010; +const int queue_number = 10010; -char *UAstr = NULL; - -static struct ipset *Pipset; - -void *memncasemem(const void *l, size_t l_len, const void *s, size_t s_len) { - register char *cur, *last; - const char *cl = (const char *) l; - const char *cs = (const char *) s; - - /* we need something to compare */ - if (l_len == 0 || s_len == 0) - return NULL; - - /* "s" must be smaller or equal to "l" */ - if (l_len < s_len) - return NULL; - - /* special case where s_len == 1 */ - if (s_len == 1) - return memchr(l, (int) *cs, l_len); - - /* the last position where its possible to find "s" in "l" */ - last = (char *) cl + l_len - s_len; - - for (cur = (char *) cl; cur <= last; cur++) - if (cur[0] == cs[0] && strncasecmp(cur, cs, s_len) == 0) - return cur; - - return NULL; -} +char *replacement_user_agent_string = NULL; static int parse_attrs(const struct nlattr *attr, void *data) { const struct nlattr **tb = data; @@ -105,8 +74,6 @@ nfq_send_verdict(int queue_num, uint32_t id, struct pkt_buff *pktb, uint32_t mar mnl_attr_put_u32(nlh, CTA_MARK, htonl(43)); mnl_attr_nest_end(nlh, nest); // 加 CONNMARK - ipset_parse_line(Pipset, addcmd); //加 ipset 标记 - count_packet_without_user_agent_mark(); } } else { @@ -171,7 +138,7 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) { mark = ntohl(mnl_attr_get_u32(ctattr[CTA_MARK])); } else { mark = 1; // no mark 1 - } // NFQA_CT 一定存在,不存在说明有其他问题 + } if (ctattr[CTA_TUPLE_ORIG]) { mnl_attr_parse_nested(ctattr[CTA_TUPLE_ORIG], parse_attrs, originattr); @@ -249,7 +216,7 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) { } if (ualength > 0) { - if (nfq_tcp_mangle_ipv4(pktb, uaoffset, ualength, UAstr, ualength) == 1) { + if (nfq_tcp_mangle_ipv4(pktb, uaoffset, ualength, replacement_user_agent_string, ualength) == 1) { count_user_agent_packet(); } else { syslog(LOG_ERR, "Mangle packet failed."); @@ -267,68 +234,19 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) { return MNL_CB_OK; } -static void killChild() { - syslog(LOG_INFO, "Received SIGTERM, kill child %d", child_status); - kill(child_status, SIGKILL); // Not graceful, but work - exit(EXIT_SUCCESS); -} - int main(int argc, char *argv[]) { char *buf; - size_t sizeof_buf = 0xffff + (MNL_SOCKET_BUFFER_SIZE / 2); + struct nlmsghdr *nlh; ssize_t ret; unsigned int portid; - int errcount = 0; - - signal(SIGTERM, killChild); - - while (true) { - child_status = fork(); - if (child_status < 0) { - syslog(LOG_ERR, "Failed to give birth."); - syslog(LOG_ERR, "Exit at fork."); - exit(EXIT_FAILURE); - } else if (child_status == 0) { - syslog(LOG_NOTICE, "UA2F processor start at [%d].", getpid()); - break; - } else { - syslog(LOG_NOTICE, "Try to start UA2F processor at [%d].", child_status); - int deadstat; - int deadpid; - deadpid = wait(&deadstat); - if (deadpid == -1) { - syslog(LOG_ERR, "Child suicide."); - } else { - syslog(LOG_ERR, "Meet fatal error.[%d] dies by %d", deadpid, deadstat); - } - } - errcount++; - if (errcount > 10) { - syslog(LOG_ERR, "Meet too many fatal error, no longer try to recover."); - syslog(LOG_ERR, "Exit with too many error."); - exit(EXIT_FAILURE); - } - } - - openlog("UA2F", LOG_PID, LOG_SYSLOG); + works_as_child(); + init_statistics(); - ipset_load_types(); - Pipset = ipset_init(); - - if (!Pipset) { - syslog(LOG_ERR, "Pipset not inited."); - exit(EXIT_FAILURE); - } - - ipset_custom_printf(Pipset, func, func2, func3, NULL); // hook 掉退出的输出函数 - - syslog(LOG_NOTICE, "Pipset inited."); - nl = mnl_socket_open(NETLINK_NETFILTER); if (nl == NULL) { @@ -338,21 +256,19 @@ int main(int argc, char *argv[]) { } if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { - perror("mnl_socket_bind"); syslog(LOG_ERR, "Exit at mnl_socket_bind."); exit(EXIT_FAILURE); } portid = mnl_socket_get_portid(nl); - buf = malloc(sizeof_buf); + buf = malloc(MNL_SOCKET_BUFFER_SIZE); if (!buf) { - perror("allocate receive buffer"); - syslog(LOG_ERR, "Exit at breakpoint 6."); + syslog(LOG_ERR, "Failed to allocate buffer memory."); exit(EXIT_FAILURE); } - UAstr = malloc(sizeof_buf); - memset(UAstr, 'F', sizeof_buf); + replacement_user_agent_string = malloc(MNL_SOCKET_BUFFER_SIZE); + memset(replacement_user_agent_string, 'F', MNL_SOCKET_BUFFER_SIZE); nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_number); nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_BIND); diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..c57e1c9 --- /dev/null +++ b/src/util.c @@ -0,0 +1,29 @@ +#include +#include + +void *memncasemem(const void *l, size_t l_len, const void *s, size_t s_len) { + register char *cur, *last; + const char *cl = (const char *) l; + const char *cs = (const char *) s; + + /* we need something to compare */ + if (l_len == 0 || s_len == 0) + return NULL; + + /* "s" must be smaller or equal to "l" */ + if (l_len < s_len) + return NULL; + + /* special case where s_len == 1 */ + if (s_len == 1) + return memchr(l, (int) *cs, l_len); + + /* the last position where its possible to find "s" in "l" */ + last = (char *) cl + l_len - s_len; + + for (cur = (char *) cl; cur <= last; cur++) + if (cur[0] == cs[0] && strncasecmp(cur, cs, s_len) == 0) + return cur; + + return NULL; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..6faf9ae --- /dev/null +++ b/src/util.h @@ -0,0 +1,8 @@ +#ifndef UA2F_UTIL_H +#define UA2F_UTIL_H + +#include + +void *memncasemem(const void *l, size_t l_len, const void *s, size_t s_len); + +#endif //UA2F_UTIL_H